From 30be4f67d3f06a405fa1dbbe01701dcbee26e358 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 21 Jun 2024 21:44:56 -0700 Subject: [PATCH 001/325] Migrate StableSwarm -> SwarmUI --- .../Models/Packages/StableSwarm.cs | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 961fd6da6..09e159c92 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -5,6 +5,7 @@ using StabilityMatrix.Core.Exceptions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; +using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FDS; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; @@ -24,20 +25,18 @@ IPrerequisiteHelper prerequisiteHelper private Process? dotnetProcess; public override string Name => "StableSwarmUI"; - public override string DisplayName { get; set; } = "StableSwarmUI"; - public override string Author => "Stability-AI"; + public override string DisplayName { get; set; } = "SwarmUI"; + public override string Author => "mcmonkeyprojects"; public override string Blurb => "A Modular Stable Diffusion Web-User-Interface, with an emphasis on making powertools easily accessible, high performance, and extensibility."; public override string LicenseType => "MIT"; public override string LicenseUrl => - "https://github.com/Stability-AI/StableSwarmUI/blob/master/LICENSE.txt"; + "https://github.com/mcmonkeyprojects/SwarmUI/blob/master/LICENSE.txt"; public override string LaunchCommand => string.Empty; public override Uri PreviewImageUri => - new( - "https://raw.githubusercontent.com/Stability-AI/StableSwarmUI/master/.github/images/stableswarmui.jpg" - ); + new("https://github.com/mcmonkeyprojects/SwarmUI/raw/master/.github/images/swarmui.jpg"); public override string OutputFolderName => "Output"; public override IEnumerable AvailableSharedFolderMethods => [SharedFolderMethod.Symlink, SharedFolderMethod.Configuration, SharedFolderMethod.None]; @@ -133,7 +132,7 @@ public override async Task InstallPackage( Action? onConsoleOutput = null ) { - progress?.Report(new ProgressReport(-1f, "Installing StableSwarmUI...", isIndeterminate: true)); + progress?.Report(new ProgressReport(-1f, "Installing SwarmUI...", isIndeterminate: true)); var comfy = settingsManager.Settings.InstalledPackages.FirstOrDefault( x => x.PackageName == nameof(ComfyUI) @@ -141,7 +140,7 @@ public override async Task InstallPackage( if (comfy == null) { - throw new InvalidOperationException("ComfyUI must be installed to use StableSwarmUI"); + throw new InvalidOperationException("ComfyUI must be installed to use SwarmUI"); } try @@ -166,16 +165,16 @@ await prerequisiteHelper // ignore, probably means the source is already there } + var srcFolder = Path.Combine(installLocation, "src"); + var csprojName = "StableSwarmUI.csproj"; + if (File.Exists(Path.Combine(srcFolder, "SwarmUI.csproj"))) + { + csprojName = "SwarmUI.csproj"; + } + await prerequisiteHelper .RunDotnet( - [ - "build", - "src/StableSwarmUI.csproj", - "--configuration", - "Release", - "-o", - "src/bin/live_release" - ], + ["build", $"src/{csprojName}", "--configuration", "Release", "-o", "src/bin/live_release"], workingDirectory: installLocation, onProcessOutput: onConsoleOutput ) @@ -273,9 +272,16 @@ void HandleConsoleOutput(ProcessOutput s) } } + var releaseFolder = Path.Combine(installedPackagePath, "src", "bin", "live_release"); + var dllName = "StableSwarmUI.dll"; + if (File.Exists(Path.Combine(releaseFolder, "SwarmUI.dll"))) + { + dllName = "SwarmUI.dll"; + } + dotnetProcess = await prerequisiteHelper .RunDotnet( - args: $"src{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}live_release{Path.DirectorySeparatorChar}StableSwarmUI.dll {arguments.TrimEnd()}", + args: $"{Path.Combine(releaseFolder, dllName)} {arguments.TrimEnd()}", workingDirectory: installedPackagePath, envVars: aspEnvVars, onProcessOutput: HandleConsoleOutput, @@ -284,6 +290,46 @@ void HandleConsoleOutput(ProcessOutput s) .ConfigureAwait(false); } + public override async Task CheckForUpdates(InstalledPackage package) + { + var needsMigrate = false; + try + { + var output = await prerequisiteHelper + .GetGitOutput(["remote", "get-url", "origin"], package.FullPath) + .ConfigureAwait(false); + + if ( + output.StandardOutput != null + && output.StandardOutput.Contains("Stability", StringComparison.OrdinalIgnoreCase) + ) + { + needsMigrate = true; + } + } + catch (Exception) + { + needsMigrate = true; + } + + if (needsMigrate) + { + await prerequisiteHelper + .RunGit( + ["remote", "set-url", "origin", $"https://github.com/{Author}/SwarmUI"], + package.FullPath + ) + .ConfigureAwait(false); + } + + return await base.CheckForUpdates(package).ConfigureAwait(false); + } + + public override Task?> GetAllCommits(string branch, int page = 1, int perPage = 10) + { + return GithubApi.GetAllCommits(Author, "SwarmUI", branch, page, perPage); + } + public override Task SetupModelFolders( DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod From 2ea24f727e1ff41e4ffbc89e10c32d80c0db5b4b Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 21 Jun 2024 21:47:37 -0700 Subject: [PATCH 002/325] chagenlog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 741a4ac41..71ebbbda4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ 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.11.2 +### Changed +- StableSwarmUI installs will be migrated to SwarmUI by mcmonkeyprojects the next time the package is updated + - Note: As of 2024/06/21 StableSwarmUI will no longer be maintained under Stability AI. The original developer will be maintaining an independent version of this project + ## v2.11.1 ### Added - Added Rename option back to the Checkpoints page From 2f712b096054913f20c494fa30b691bd74c665f3 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 21 Jun 2024 22:27:22 -0700 Subject: [PATCH 003/325] fix url for new installs --- StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 09e159c92..c740a6161 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -27,7 +27,7 @@ IPrerequisiteHelper prerequisiteHelper public override string Name => "StableSwarmUI"; public override string DisplayName { get; set; } = "SwarmUI"; public override string Author => "mcmonkeyprojects"; - + public override string GithubUrl => $"https://github.com/{Author}/SwarmUI"; public override string Blurb => "A Modular Stable Diffusion Web-User-Interface, with an emphasis on making powertools easily accessible, high performance, and extensibility."; From 20880c46e8e95fbf6c3044af5a79604c7ce5959e Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 03:04:41 -0400 Subject: [PATCH 004/325] Image copy behavior setting for AlwaysCopyImagesAsFiles --- .../Controls/AdvancedImageBoxView.axaml.cs | 11 +++--- .../Helpers/WindowsClipboard.cs | 25 +++++++------- .../Dialogs/ImageViewerViewModel.cs | 34 +++++++++++++------ .../Inference/ImageFolderCardViewModel.cs | 9 +++-- .../ViewModels/OutputsPageViewModel.cs | 4 ++- .../Views/Dialogs/ImageViewerDialog.axaml | 3 +- .../Models/Settings/Settings.cs | 5 +++ 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs index 3ecc19f75..6aa0873f2 100644 --- a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs @@ -1,10 +1,12 @@ using System.Threading.Tasks; using Avalonia.Controls; using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.DependencyInjection; using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.Controls; @@ -22,13 +24,12 @@ private static async Task FlyoutCopy(ImageSource? imageSource) if (imageSource is null) return; - if (Compat.IsWindows && imageSource.Bitmap is { } bitmap) + var settings = App.Services.GetService()?.Settings; + + if (Compat.IsWindows && settings?.AlwaysCopyImagesAsFiles != true && imageSource.Bitmap is { } bitmap) { // Use bitmap on Windows if available - await Task.Run(() => - { - WindowsClipboard.SetBitmap(bitmap); - }); + await WindowsClipboard.SetBitmapAsync(bitmap); } else if (imageSource.LocalFile is { } imagePath) { diff --git a/StabilityMatrix.Avalonia/Helpers/WindowsClipboard.cs b/StabilityMatrix.Avalonia/Helpers/WindowsClipboard.cs index 749c1db46..d4b555378 100644 --- a/StabilityMatrix.Avalonia/Helpers/WindowsClipboard.cs +++ b/StabilityMatrix.Avalonia/Helpers/WindowsClipboard.cs @@ -3,6 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using System.Threading.Tasks; using Avalonia.Media.Imaging; namespace StabilityMatrix.Avalonia.Helpers; @@ -10,6 +11,11 @@ namespace StabilityMatrix.Avalonia.Helpers; [SupportedOSPlatform("windows")] public static class WindowsClipboard { + public static async Task SetBitmapAsync(Bitmap bitmap) + { + await Task.Run(() => SetBitmap(bitmap)); + } + public static void SetBitmap(Bitmap bitmap) { if (bitmap == null) @@ -29,11 +35,7 @@ public static void SetBitmap(Bitmap bitmap) var sourceBitmapSelection = SelectObject(sourceDC, hBitmap); var destDC = CreateCompatibleDC(screenDC); - var compatibleBitmap = CreateCompatibleBitmap( - screenDC, - systemBitmap.Width, - systemBitmap.Height - ); + var compatibleBitmap = CreateCompatibleBitmap(screenDC, systemBitmap.Width, systemBitmap.Height); var destinationBitmapSelection = SelectObject(destDC, compatibleBitmap); @@ -45,10 +47,7 @@ public static void SetBitmap(Bitmap bitmap) EmptyClipboard(); - var result = SetClipboardData( - (uint) Win32ClipboardFormat.CF_BITMAP, - compatibleBitmap - ); + var result = SetClipboardData((uint)Win32ClipboardFormat.CF_BITMAP, compatibleBitmap); if (result == IntPtr.Zero) { @@ -64,16 +63,16 @@ public static void SetBitmap(Bitmap bitmap) [DllImport("user32.dll", SetLastError = true)] static extern bool OpenClipboard(IntPtr hWndNewOwner); - + [DllImport("user32.dll", SetLastError = true)] private static extern bool CloseClipboard(); - + [DllImport("user32.dll")] static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem); - + [DllImport("user32.dll", SetLastError = true)] private static extern bool EmptyClipboard(); - + [DllImport("user32.dll", ExactSpelling = true)] public static extern IntPtr GetDC(IntPtr hWnd); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs index 8a15bb2b9..f6b6dc71d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs @@ -2,12 +2,13 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls.Primitives; -using Avalonia.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FluentAvalonia.Core; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels.Base; @@ -16,6 +17,7 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.Database; +using StabilityMatrix.Core.Services; using Size = StabilityMatrix.Core.Helper.Size; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; @@ -23,7 +25,10 @@ namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; [View(typeof(ImageViewerDialog))] [ManagedService] [Transient] -public partial class ImageViewerViewModel : ContentDialogViewModelBase +public partial class ImageViewerViewModel( + ILogger logger, + ISettingsManager settingsManager +) : ContentDialogViewModelBase { [ObservableProperty] private ImageSource? imageSource; @@ -81,18 +86,27 @@ private void OnNavigatePrevious() } [RelayCommand] - private async Task CopyImage(Bitmap? image) + private async Task CopyImage(ImageSource? image) { - if (image is null || !Compat.IsWindows) + if (image is null) return; - await Task.Run(() => + if ( + Compat.IsWindows + && !settingsManager.Settings.AlwaysCopyImagesAsFiles + && image.Bitmap is { } bitmap + ) { - if (Compat.IsWindows) - { - WindowsClipboard.SetBitmap(image); - } - }); + await WindowsClipboard.SetBitmapAsync(bitmap); + } + else if (image.LocalFile is { } imagePath) + { + await App.Clipboard.SetFileDataObjectAsync(imagePath); + } + else + { + logger.LogWarning("Failed to copy image: {Image}", image); + } } public override BetterContentDialog GetDialog() diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs index 3eb061440..261b0d6f8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs @@ -42,6 +42,7 @@ public partial class ImageFolderCardViewModel : ViewModelBase private readonly IImageIndexService imageIndexService; private readonly ISettingsManager settingsManager; private readonly INotificationService notificationService; + private readonly ServiceManager vmFactory; [ObservableProperty] private string? searchQuery; @@ -59,13 +60,15 @@ public ImageFolderCardViewModel( ILogger logger, IImageIndexService imageIndexService, ISettingsManager settingsManager, - INotificationService notificationService + INotificationService notificationService, + ServiceManager vmFactory ) { this.logger = logger; this.imageIndexService = imageIndexService; this.settingsManager = settingsManager; this.notificationService = notificationService; + this.vmFactory = vmFactory; var searcher = new ImageSearcher(); @@ -177,7 +180,9 @@ private async Task OnImageClick(LocalImageFile item) // Preload await image.GetBitmapAsync(); - var vm = new ImageViewerViewModel { ImageSource = image, LocalImageFile = item }; + var vm = vmFactory.Get(); + vm.ImageSource = image; + vm.LocalImageFile = item; using var onNext = Observable .FromEventPattern( diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs index ef1450693..3b93f5e36 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs @@ -244,7 +244,9 @@ public async Task ShowImageDialog(OutputImageViewModel item) // Preload await image.GetBitmapAsync(); - var vm = new ImageViewerViewModel { ImageSource = image, LocalImageFile = item.ImageFile }; + var vm = vmFactory.Get(); + vm.ImageSource = image; + vm.LocalImageFile = item.ImageFile; using var onNext = Observable .FromEventPattern( diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml index ac45af364..77f65d7b9 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml @@ -81,10 +81,9 @@ diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index fd7af8cd1..8ff66949c 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -125,6 +125,11 @@ public InstalledPackage? PreferredWorkflowPackage public bool IsDiscordRichPresenceEnabled { get; set; } + /// + /// If true, bitmaps in image viewers will be copied as temp files instead of native bitmap clipboard data + /// + public bool AlwaysCopyImagesAsFiles { get; set; } + [JsonIgnore] public Dictionary DefaultEnvironmentVariables { get; } = new() { ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib" }; From 81ce83560f79e9e5a01c601f55bbf62a11c84640 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 04:01:35 -0400 Subject: [PATCH 005/325] Add alt Copy as Bitmap option to image viewers --- .../Controls/AdvancedImageBoxView.axaml | 6 ++++ .../Controls/AdvancedImageBoxView.axaml.cs | 36 ++++++++++++------- .../Languages/Resources.Designer.cs | 9 +++++ .../Languages/Resources.resx | 3 ++ .../Dialogs/ImageViewerViewModel.cs | 35 +++++++++++++----- .../Views/Dialogs/ImageViewerDialog.axaml | 12 ++++++- 6 files changed, 79 insertions(+), 22 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml index 76d994668..692de0ecd 100644 --- a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml +++ b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml @@ -41,6 +41,12 @@ HotKey="Ctrl+C" IconSource="Copy" Text="{x:Static lang:Resources.Action_Copy}" /> + diff --git a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs index 6aa0873f2..1ce56e907 100644 --- a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs @@ -1,12 +1,12 @@ -using System.Threading.Tasks; +using System.IO; +using System.Threading.Tasks; using Avalonia.Controls; using CommunityToolkit.Mvvm.Input; -using Microsoft.Extensions.DependencyInjection; using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Core.Helper; -using StabilityMatrix.Core.Services; +using StabilityMatrix.Core.Models.FileInterfaces; namespace StabilityMatrix.Avalonia.Controls; @@ -19,23 +19,35 @@ public AdvancedImageBoxView() public static AsyncRelayCommand FlyoutCopyCommand { get; } = new(FlyoutCopy); + public static AsyncRelayCommand FlyoutCopyAsBitmapCommand { get; } = + new(FlyoutCopyAsBitmap); + private static async Task FlyoutCopy(ImageSource? imageSource) { if (imageSource is null) return; - var settings = App.Services.GetService()?.Settings; - - if (Compat.IsWindows && settings?.AlwaysCopyImagesAsFiles != true && imageSource.Bitmap is { } bitmap) + if (imageSource.LocalFile is { } imagePath) { - // Use bitmap on Windows if available - await WindowsClipboard.SetBitmapAsync(bitmap); + await App.Clipboard.SetFileDataObjectAsync(imagePath); + } + else if (await imageSource.GetBitmapAsync() is { } bitmap) + { + // Write to temp file + var tempFile = new FilePath(Path.GetTempFileName() + ".png"); + + bitmap.Save(tempFile); } - else if (imageSource.LocalFile is { } imagePath) + } + + private static async Task FlyoutCopyAsBitmap(ImageSource? imageSource) + { + if (imageSource is null || !Compat.IsWindows) + return; + + if (await imageSource.GetBitmapAsync() is { } bitmap) { - // Other OS or no bitmap, use image source - var clipboard = App.Clipboard; - await clipboard.SetFileDataObjectAsync(imagePath); + await WindowsClipboard.SetBitmapAsync(bitmap); } } } diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 9998a7e3e..8236f4986 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -167,6 +167,15 @@ public static string Action_Copy { } } + /// + /// Looks up a localized string similar to Copy as Bitmap. + /// + public static string Action_CopyAsBitmap { + get { + return ResourceManager.GetString("Action_CopyAsBitmap", resourceCulture); + } + } + /// /// Looks up a localized string similar to Copy Details. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 21a267a09..73d3e4df5 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1116,4 +1116,7 @@ App Data + + Copy as Bitmap + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs index f6b6dc71d..f29500732 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs @@ -17,7 +17,9 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.Database; +using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Services; +using Path = System.IO.Path; using Size = StabilityMatrix.Core.Helper.Size; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; @@ -91,21 +93,36 @@ private async Task CopyImage(ImageSource? image) if (image is null) return; - if ( - Compat.IsWindows - && !settingsManager.Settings.AlwaysCopyImagesAsFiles - && image.Bitmap is { } bitmap - ) + if (image.LocalFile is { } imagePath) { - await WindowsClipboard.SetBitmapAsync(bitmap); + await App.Clipboard.SetFileDataObjectAsync(imagePath); } - else if (image.LocalFile is { } imagePath) + else if (await image.GetBitmapAsync() is { } bitmap) { - await App.Clipboard.SetFileDataObjectAsync(imagePath); + // Write to temp file + var tempFile = new FilePath(Path.GetTempFileName() + ".png"); + + bitmap.Save(tempFile); + } + else + { + logger.LogWarning("Failed to copy image, no file path or bitmap: {Image}", image); + } + } + + [RelayCommand] + private async Task CopyImageAsBitmap(ImageSource? image) + { + if (image is null || !Compat.IsWindows) + return; + + if (await image.GetBitmapAsync() is { } bitmap) + { + await WindowsClipboard.SetBitmapAsync(bitmap); } else { - logger.LogWarning("Failed to copy image: {Image}", image); + logger.LogWarning("Failed to copy image, no bitmap: {Image}", image); } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml index 77f65d7b9..025bce07b 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml @@ -54,6 +54,9 @@ + @@ -84,7 +87,14 @@ CommandParameter="{Binding}" HotKey="Ctrl+C" IconSource="Copy" - Text="Copy" /> + Text="{x:Static lang:Resources.Action_Copy}" /> + From 2dce448d99c5ce971da8005dcee15d15cd48adc8 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 04:02:46 -0400 Subject: [PATCH 006/325] Remove unused setting --- StabilityMatrix.Core/Models/Settings/Settings.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index 8ff66949c..fd7af8cd1 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -125,11 +125,6 @@ public InstalledPackage? PreferredWorkflowPackage public bool IsDiscordRichPresenceEnabled { get; set; } - /// - /// If true, bitmaps in image viewers will be copied as temp files instead of native bitmap clipboard data - /// - public bool AlwaysCopyImagesAsFiles { get; set; } - [JsonIgnore] public Dictionary DefaultEnvironmentVariables { get; } = new() { ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib" }; From a802399949e9b618377cec870b6de80b387fb99a Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 04:03:53 -0400 Subject: [PATCH 007/325] Fix file not found error for SetFileDataObjectAsync with storage provider local file paths --- .../Extensions/ClipboardExtensions.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/StabilityMatrix.Avalonia/Extensions/ClipboardExtensions.cs b/StabilityMatrix.Avalonia/Extensions/ClipboardExtensions.cs index 9138f63a1..a8caf4fa8 100644 --- a/StabilityMatrix.Avalonia/Extensions/ClipboardExtensions.cs +++ b/StabilityMatrix.Avalonia/Extensions/ClipboardExtensions.cs @@ -4,6 +4,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Platform.Storage; +using StabilityMatrix.Core.Extensions; namespace StabilityMatrix.Avalonia.Extensions; @@ -15,10 +16,7 @@ public static class ClipboardExtensions /// Set file paths to the clipboard. /// /// Thrown if unable to get file from path - public static async Task SetFileDataObjectAsync( - this IClipboard clipboard, - params string[] filePaths - ) + public static async Task SetFileDataObjectAsync(this IClipboard clipboard, params string[] filePaths) { await clipboard.SetFileDataObjectAsync((IEnumerable)filePaths); } @@ -27,19 +25,19 @@ params string[] filePaths /// Set file paths to the clipboard. /// /// Thrown if unable to get file from path - public static async Task SetFileDataObjectAsync( - this IClipboard clipboard, - IEnumerable filePaths - ) + public static async Task SetFileDataObjectAsync(this IClipboard clipboard, IEnumerable filePaths) { var files = new List(); foreach (var filePath in filePaths) { - var file = await StorageProvider.TryGetFileFromPathAsync(filePath); + // Normalize path that might have come from avalonia storage provider already + var normalizedPath = filePath.StripStart("file:///").StripStart("file://"); + + var file = await StorageProvider.TryGetFileFromPathAsync(normalizedPath); if (file is null) { - throw new IOException($"File {filePath} was not found"); + throw new IOException($"File {normalizedPath} ({filePath}) was not found"); } files.Add(file); From eb0f7a37455578539511f42fb3a184a0170bc3b1 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 04:16:25 -0400 Subject: [PATCH 008/325] chagenlog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ebbbda4..b8cc16adc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.12.0-dev.1 +### Added +- Image viewer context menus now have 2 options: `Copy (Ctrl+C)` which now always copies the image as a file, and `Copy as Bitmap (Shift+Ctrl+C)` (Available on Windows) which copies to the clipboard as native bitmap. This changes the previous single `Copy` button behavior that would first attempt a native bitmap copy on Windows when available, and fall back to a file copy if not. + ## v2.11.2 ### Changed - StableSwarmUI installs will be migrated to SwarmUI by mcmonkeyprojects the next time the package is updated From 0dc745c09a29598c4737b855c32e602e52fdd82a Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 04:57:41 -0400 Subject: [PATCH 009/325] Actually copy path now --- StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs | 2 ++ .../ViewModels/Dialogs/ImageViewerViewModel.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs index 1ce56e907..3609ee812 100644 --- a/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/AdvancedImageBoxView.axaml.cs @@ -37,6 +37,8 @@ private static async Task FlyoutCopy(ImageSource? imageSource) var tempFile = new FilePath(Path.GetTempFileName() + ".png"); bitmap.Save(tempFile); + + await App.Clipboard.SetFileDataObjectAsync(tempFile); } } diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs index f29500732..fcce74a59 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ImageViewerViewModel.cs @@ -103,6 +103,8 @@ private async Task CopyImage(ImageSource? image) var tempFile = new FilePath(Path.GetTempFileName() + ".png"); bitmap.Save(tempFile); + + await App.Clipboard.SetFileDataObjectAsync(tempFile); } else { From df7d1d5d4d4e8ace83891ff4cbdee3c71a0abe8a Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 22 Jun 2024 12:23:17 -0700 Subject: [PATCH 010/325] pin setuptools version for forge --- CHANGELOG.md | 2 ++ StabilityMatrix.Core/Models/Packages/SDWebForge.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ebbbda4..86bee48f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ### Changed - StableSwarmUI installs will be migrated to SwarmUI by mcmonkeyprojects the next time the package is updated - Note: As of 2024/06/21 StableSwarmUI will no longer be maintained under Stability AI. The original developer will be maintaining an independent version of this project +### Fixed +- Fixed [#700](https://github.com/LykosAI/StabilityMatrix/issues/700) - `cannot import 'packaging'` error for Forge ## v2.11.1 ### Added diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index 9e3049559..795678bb3 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -169,7 +169,7 @@ public override async Task InstallPackage( await requirements.WriteAllTextAsync(requirementsContent).ConfigureAwait(false); } - var pipArgs = new PipInstallArgs(); + var pipArgs = new PipInstallArgs("setuptools==69.5.1"); if (torchVersion is TorchVersion.DirectMl) { pipArgs = pipArgs.WithTorchDirectML(); From e1490b454651e7d43faff661aa0e41646143280f Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 16:15:25 -0400 Subject: [PATCH 011/325] Fix StableSwarm update check, add BaseGitPackage.GitName --- .../Models/Packages/BaseGitPackage.cs | 35 +++++++++---------- .../Models/Packages/StableSwarm.cs | 7 ++-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index ff1117a9b..8cef3f27f 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -29,12 +29,14 @@ public abstract class BaseGitPackage : BasePackage protected readonly IPrerequisiteHelper PrerequisiteHelper; public PyVenvRunner? VenvRunner; + public virtual string GitName => Name; + /// /// URL of the hosted web page on launch /// protected string WebUrl = string.Empty; - public override string GithubUrl => $"https://github.com/{Author}/{Name}"; + public override string GithubUrl => $"https://github.com/{Author}/{GitName}"; public string DownloadLocation => Path.Combine(SettingsManager.LibraryDir, "Packages", $"{Name}.zip"); @@ -42,17 +44,17 @@ protected string GetDownloadUrl(DownloadPackageVersionOptions versionOptions) { if (!string.IsNullOrWhiteSpace(versionOptions.CommitHash)) { - return $"https://github.com/{Author}/{Name}/archive/{versionOptions.CommitHash}.zip"; + return $"https://github.com/{Author}/{GitName}/archive/{versionOptions.CommitHash}.zip"; } if (!string.IsNullOrWhiteSpace(versionOptions.VersionTag)) { - return $"https://api.github.com/repos/{Author}/{Name}/zipball/{versionOptions.VersionTag}"; + return $"https://api.github.com/repos/{Author}/{GitName}/zipball/{versionOptions.VersionTag}"; } if (!string.IsNullOrWhiteSpace(versionOptions.BranchName)) { - return $"https://api.github.com/repos/{Author}/{Name}/zipball/{versionOptions.BranchName}"; + return $"https://api.github.com/repos/{Author}/{GitName}/zipball/{versionOptions.BranchName}"; } throw new Exception("No download URL available"); @@ -75,7 +77,7 @@ public override async Task GetLatestVersion(bool { if (ShouldIgnoreReleases) { - var commits = await GithubApi.GetAllCommits(Author, Name, MainBranch).ConfigureAwait(false); + var commits = await GithubApi.GetAllCommits(Author, GitName, MainBranch).ConfigureAwait(false); return new DownloadPackageVersionOptions { IsLatest = true, @@ -85,7 +87,7 @@ public override async Task GetLatestVersion(bool }; } - var releases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false); + var releases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); var latestRelease = includePrerelease ? releases.First() : releases.First(x => !x.Prerelease); return new DownloadPackageVersionOptions @@ -98,7 +100,7 @@ public override async Task GetLatestVersion(bool public override Task?> GetAllCommits(string branch, int page = 1, int perPage = 10) { - return GithubApi.GetAllCommits(Author, Name, branch, page, perPage); + return GithubApi.GetAllCommits(Author, GitName, branch, page, perPage); } public override async Task GetAllVersionOptions() @@ -107,7 +109,7 @@ public override async Task GetAllVersionOptions() if (!ShouldIgnoreReleases) { - var allReleases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false); + var allReleases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); var releasesList = allReleases.ToList(); if (releasesList.Any()) { @@ -124,7 +126,7 @@ public override async Task GetAllVersionOptions() } // Branch mode - var allBranches = await GithubApi.GetAllBranches(Author, Name).ConfigureAwait(false); + var allBranches = await GithubApi.GetAllBranches(Author, GitName).ConfigureAwait(false); packageVersionOptions.AvailableBranches = allBranches.Select( b => new PackageVersion { TagName = $"{b.Name}", ReleaseNotesMarkdown = string.Empty } ); @@ -197,7 +199,7 @@ public async Task SetupVenvPure( public override async Task> GetReleaseTags() { - var allReleases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false); + var allReleases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); return allReleases; } @@ -576,8 +578,8 @@ SharedFolderMethod sharedFolderMethod await linkDir.DeleteAsync(false).ConfigureAwait(false); } - await StabilityMatrix - .Core.Helper.SharedFolders.UpdateLinksForPackage( + await Helper + .SharedFolders.UpdateLinksForPackage( sharedFolders, SettingsManager.ModelsDirectory, installDirectory @@ -597,7 +599,7 @@ SharedFolderMethod sharedFolderMethod { if (SharedFolders is not null && sharedFolderMethod == SharedFolderMethod.Symlink) { - StabilityMatrix.Core.Helper.SharedFolders.RemoveLinksForPackage(SharedFolders, installDirectory); + Helper.SharedFolders.RemoveLinksForPackage(SharedFolders, installDirectory); } return Task.CompletedTask; } @@ -606,7 +608,7 @@ public override Task SetupOutputFolderLinks(DirectoryPath installDirectory) { if (SharedOutputFolders is { } sharedOutputFolders) { - return StabilityMatrix.Core.Helper.SharedFolders.UpdateLinksForPackage( + return Helper.SharedFolders.UpdateLinksForPackage( sharedOutputFolders, SettingsManager.ImagesDirectory, installDirectory, @@ -621,10 +623,7 @@ public override Task RemoveOutputFolderLinks(DirectoryPath installDirectory) { if (SharedOutputFolders is { } sharedOutputFolders) { - StabilityMatrix.Core.Helper.SharedFolders.RemoveLinksForPackage( - sharedOutputFolders, - installDirectory - ); + Helper.SharedFolders.RemoveLinksForPackage(sharedOutputFolders, installDirectory); } return Task.CompletedTask; } diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index c740a6161..f2ab5d971 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -25,9 +25,9 @@ IPrerequisiteHelper prerequisiteHelper private Process? dotnetProcess; public override string Name => "StableSwarmUI"; + public override string GitName => "SwarmUI"; public override string DisplayName { get; set; } = "SwarmUI"; public override string Author => "mcmonkeyprojects"; - public override string GithubUrl => $"https://github.com/{Author}/SwarmUI"; public override string Blurb => "A Modular Stable Diffusion Web-User-Interface, with an emphasis on making powertools easily accessible, high performance, and extensibility."; @@ -315,10 +315,7 @@ public override async Task CheckForUpdates(InstalledPackage package) if (needsMigrate) { await prerequisiteHelper - .RunGit( - ["remote", "set-url", "origin", $"https://github.com/{Author}/SwarmUI"], - package.FullPath - ) + .RunGit(["remote", "set-url", "origin", GithubUrl], package.FullPath) .ConfigureAwait(false); } From cbb98784af94c588c4c8858a6987b51f171192ef Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 16:22:11 -0400 Subject: [PATCH 012/325] Change to RepositoryName --- .../Models/Packages/BaseGitPackage.cs | 25 +++++++++++-------- .../Models/Packages/StableSwarm.cs | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index 8cef3f27f..524ad95e9 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -29,14 +29,15 @@ public abstract class BaseGitPackage : BasePackage protected readonly IPrerequisiteHelper PrerequisiteHelper; public PyVenvRunner? VenvRunner; - public virtual string GitName => Name; + public virtual string RepositoryName => Name; + public virtual string RepositoryAuthor => Author; /// /// URL of the hosted web page on launch /// protected string WebUrl = string.Empty; - public override string GithubUrl => $"https://github.com/{Author}/{GitName}"; + public override string GithubUrl => $"https://github.com/{Author}/{RepositoryName}"; public string DownloadLocation => Path.Combine(SettingsManager.LibraryDir, "Packages", $"{Name}.zip"); @@ -44,17 +45,17 @@ protected string GetDownloadUrl(DownloadPackageVersionOptions versionOptions) { if (!string.IsNullOrWhiteSpace(versionOptions.CommitHash)) { - return $"https://github.com/{Author}/{GitName}/archive/{versionOptions.CommitHash}.zip"; + return $"https://github.com/{Author}/{RepositoryName}/archive/{versionOptions.CommitHash}.zip"; } if (!string.IsNullOrWhiteSpace(versionOptions.VersionTag)) { - return $"https://api.github.com/repos/{Author}/{GitName}/zipball/{versionOptions.VersionTag}"; + return $"https://api.github.com/repos/{Author}/{RepositoryName}/zipball/{versionOptions.VersionTag}"; } if (!string.IsNullOrWhiteSpace(versionOptions.BranchName)) { - return $"https://api.github.com/repos/{Author}/{GitName}/zipball/{versionOptions.BranchName}"; + return $"https://api.github.com/repos/{Author}/{RepositoryName}/zipball/{versionOptions.BranchName}"; } throw new Exception("No download URL available"); @@ -77,7 +78,9 @@ public override async Task GetLatestVersion(bool { if (ShouldIgnoreReleases) { - var commits = await GithubApi.GetAllCommits(Author, GitName, MainBranch).ConfigureAwait(false); + var commits = await GithubApi + .GetAllCommits(Author, RepositoryName, MainBranch) + .ConfigureAwait(false); return new DownloadPackageVersionOptions { IsLatest = true, @@ -87,7 +90,7 @@ public override async Task GetLatestVersion(bool }; } - var releases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); + var releases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); var latestRelease = includePrerelease ? releases.First() : releases.First(x => !x.Prerelease); return new DownloadPackageVersionOptions @@ -100,7 +103,7 @@ public override async Task GetLatestVersion(bool public override Task?> GetAllCommits(string branch, int page = 1, int perPage = 10) { - return GithubApi.GetAllCommits(Author, GitName, branch, page, perPage); + return GithubApi.GetAllCommits(Author, RepositoryName, branch, page, perPage); } public override async Task GetAllVersionOptions() @@ -109,7 +112,7 @@ public override async Task GetAllVersionOptions() if (!ShouldIgnoreReleases) { - var allReleases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); + var allReleases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); var releasesList = allReleases.ToList(); if (releasesList.Any()) { @@ -126,7 +129,7 @@ public override async Task GetAllVersionOptions() } // Branch mode - var allBranches = await GithubApi.GetAllBranches(Author, GitName).ConfigureAwait(false); + var allBranches = await GithubApi.GetAllBranches(Author, RepositoryName).ConfigureAwait(false); packageVersionOptions.AvailableBranches = allBranches.Select( b => new PackageVersion { TagName = $"{b.Name}", ReleaseNotesMarkdown = string.Empty } ); @@ -199,7 +202,7 @@ public async Task SetupVenvPure( public override async Task> GetReleaseTags() { - var allReleases = await GithubApi.GetAllReleases(Author, GitName).ConfigureAwait(false); + var allReleases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); return allReleases; } diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index f2ab5d971..d26231825 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -25,7 +25,7 @@ IPrerequisiteHelper prerequisiteHelper private Process? dotnetProcess; public override string Name => "StableSwarmUI"; - public override string GitName => "SwarmUI"; + public override string RepositoryName => "SwarmUI"; public override string DisplayName { get; set; } = "SwarmUI"; public override string Author => "mcmonkeyprojects"; public override string Blurb => From 362bb3dd39d9ade9d4195534001268338be9b36d Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 16:23:21 -0400 Subject: [PATCH 013/325] Fix RepositoryAuthor usages --- .../Models/Packages/BaseGitPackage.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index 524ad95e9..8c2347dbe 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -37,7 +37,7 @@ public abstract class BaseGitPackage : BasePackage /// protected string WebUrl = string.Empty; - public override string GithubUrl => $"https://github.com/{Author}/{RepositoryName}"; + public override string GithubUrl => $"https://github.com/{RepositoryAuthor}/{RepositoryName}"; public string DownloadLocation => Path.Combine(SettingsManager.LibraryDir, "Packages", $"{Name}.zip"); @@ -45,17 +45,17 @@ protected string GetDownloadUrl(DownloadPackageVersionOptions versionOptions) { if (!string.IsNullOrWhiteSpace(versionOptions.CommitHash)) { - return $"https://github.com/{Author}/{RepositoryName}/archive/{versionOptions.CommitHash}.zip"; + return $"https://github.com/{RepositoryAuthor}/{RepositoryName}/archive/{versionOptions.CommitHash}.zip"; } if (!string.IsNullOrWhiteSpace(versionOptions.VersionTag)) { - return $"https://api.github.com/repos/{Author}/{RepositoryName}/zipball/{versionOptions.VersionTag}"; + return $"https://api.github.com/repos/{RepositoryAuthor}/{RepositoryName}/zipball/{versionOptions.VersionTag}"; } if (!string.IsNullOrWhiteSpace(versionOptions.BranchName)) { - return $"https://api.github.com/repos/{Author}/{RepositoryName}/zipball/{versionOptions.BranchName}"; + return $"https://api.github.com/repos/{RepositoryAuthor}/{RepositoryName}/zipball/{versionOptions.BranchName}"; } throw new Exception("No download URL available"); @@ -79,7 +79,7 @@ public override async Task GetLatestVersion(bool if (ShouldIgnoreReleases) { var commits = await GithubApi - .GetAllCommits(Author, RepositoryName, MainBranch) + .GetAllCommits(RepositoryAuthor, RepositoryName, MainBranch) .ConfigureAwait(false); return new DownloadPackageVersionOptions { @@ -90,7 +90,7 @@ public override async Task GetLatestVersion(bool }; } - var releases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); + var releases = await GithubApi.GetAllReleases(RepositoryAuthor, RepositoryName).ConfigureAwait(false); var latestRelease = includePrerelease ? releases.First() : releases.First(x => !x.Prerelease); return new DownloadPackageVersionOptions @@ -103,7 +103,7 @@ public override async Task GetLatestVersion(bool public override Task?> GetAllCommits(string branch, int page = 1, int perPage = 10) { - return GithubApi.GetAllCommits(Author, RepositoryName, branch, page, perPage); + return GithubApi.GetAllCommits(RepositoryAuthor, RepositoryName, branch, page, perPage); } public override async Task GetAllVersionOptions() @@ -112,7 +112,9 @@ public override async Task GetAllVersionOptions() if (!ShouldIgnoreReleases) { - var allReleases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); + var allReleases = await GithubApi + .GetAllReleases(RepositoryAuthor, RepositoryName) + .ConfigureAwait(false); var releasesList = allReleases.ToList(); if (releasesList.Any()) { @@ -129,7 +131,9 @@ public override async Task GetAllVersionOptions() } // Branch mode - var allBranches = await GithubApi.GetAllBranches(Author, RepositoryName).ConfigureAwait(false); + var allBranches = await GithubApi + .GetAllBranches(RepositoryAuthor, RepositoryName) + .ConfigureAwait(false); packageVersionOptions.AvailableBranches = allBranches.Select( b => new PackageVersion { TagName = $"{b.Name}", ReleaseNotesMarkdown = string.Empty } ); @@ -202,7 +206,9 @@ public async Task SetupVenvPure( public override async Task> GetReleaseTags() { - var allReleases = await GithubApi.GetAllReleases(Author, RepositoryName).ConfigureAwait(false); + var allReleases = await GithubApi + .GetAllReleases(RepositoryAuthor, RepositoryName) + .ConfigureAwait(false); return allReleases; } From 1bac2f2ce7d424d3d52fd0d9b3f4783be7734f6b Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 16:33:51 -0400 Subject: [PATCH 014/325] Remove unused --- StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index d26231825..28ad81d5e 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -5,7 +5,6 @@ using StabilityMatrix.Core.Exceptions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; -using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FDS; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; @@ -322,11 +321,6 @@ await prerequisiteHelper return await base.CheckForUpdates(package).ConfigureAwait(false); } - public override Task?> GetAllCommits(string branch, int page = 1, int perPage = 10) - { - return GithubApi.GetAllCommits(Author, "SwarmUI", branch, page, perPage); - } - public override Task SetupModelFolders( DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod From 20d0e15fecec0e4cdbaa9b8adf30600a16e4a23c Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 17:03:34 -0400 Subject: [PATCH 015/325] Update backport package and add mainline number for cherry pick --- .github/workflows/backport.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 7bb427f53..5e82915ba 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -10,6 +10,11 @@ jobs: name: Backport PR runs-on: ubuntu-latest steps: + # Get the merge target branch to decide mainline number + # git cherry-pick mainline is 2 for merge to 'dev', else 1 + - name: Get target branch + run: echo "::set-env name=CP_MAINLINE::$(if [ '${{ github.event.pull_request.base.ref }}' == 'dev' ]; then echo 2; else echo 1; fi)" + - name: Write json id: create-json uses: jsdaniell/create-json@v1.2.3 @@ -18,11 +23,12 @@ jobs: json: | { "targetPRLabels": "backport", + "mainline": ${{ env.CP_MAINLINE }}, "prTitle": "[{{sourceBranch}} to {{targetBranch}}] backport: {{sourcePullRequest.title}} ({{sourcePullRequest.number}})" } - name: Backport Action - uses: sorenlouv/backport-github-action@v9.3.0 + uses: sorenlouv/backport-github-action@v9.5.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} auto_backport_label_prefix: backport-to- From 14026fcf4f6597a65530309c36cb0c7891e7c056 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 22 Jun 2024 17:10:49 -0400 Subject: [PATCH 016/325] Fix set-env not working --- .github/workflows/backport.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 5e82915ba..3fde845ab 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -13,8 +13,8 @@ jobs: # Get the merge target branch to decide mainline number # git cherry-pick mainline is 2 for merge to 'dev', else 1 - name: Get target branch - run: echo "::set-env name=CP_MAINLINE::$(if [ '${{ github.event.pull_request.base.ref }}' == 'dev' ]; then echo 2; else echo 1; fi)" - + run: echo "CP_MAINLINE=$(if [ '${{ github.event.pull_request.base.ref }}' == 'dev' ]; then echo 2; else echo 1; fi)" >> $GITHUB_ENV + - name: Write json id: create-json uses: jsdaniell/create-json@v1.2.3 @@ -26,7 +26,7 @@ jobs: "mainline": ${{ env.CP_MAINLINE }}, "prTitle": "[{{sourceBranch}} to {{targetBranch}}] backport: {{sourcePullRequest.title}} ({{sourcePullRequest.number}})" } - + - name: Backport Action uses: sorenlouv/backport-github-action@v9.5.1 with: From d16890172c6e648326bf5abde8124d06d6758b1f Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 01:06:34 -0400 Subject: [PATCH 017/325] Fix mainline maybe --- .github/workflows/backport.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 3fde845ab..d2838198e 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: # Get the merge target branch to decide mainline number - # git cherry-pick mainline is 2 for merge to 'dev', else 1 + # git cherry-pick mainline is 1 for merge to 'dev', else 2 - name: Get target branch - run: echo "CP_MAINLINE=$(if [ '${{ github.event.pull_request.base.ref }}' == 'dev' ]; then echo 2; else echo 1; fi)" >> $GITHUB_ENV + run: echo "CP_MAINLINE=$(if [ '${{ github.event.pull_request.base.ref }}' == 'dev' ]; then echo 1; else echo 2; fi)" >> $GITHUB_ENV - name: Write json id: create-json From efd72178806668b64d18ba41db20b0442a8c970a Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 16:06:27 -0400 Subject: [PATCH 018/325] Add PIP_DISABLE_PIP_VERSION_CHECK default env var --- StabilityMatrix.Core/Models/Settings/Settings.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index fd7af8cd1..4b3da4764 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -127,7 +127,13 @@ public InstalledPackage? PreferredWorkflowPackage [JsonIgnore] public Dictionary DefaultEnvironmentVariables { get; } = - new() { ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib" }; + new() + { + // Fixes potential setuptools error on Portable Windows Python + ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib", + // Suppresses 'A new release of pip is available' messages + ["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" + }; [JsonPropertyName("EnvironmentVariables")] public Dictionary? UserEnvironmentVariables { get; set; } From b2941904833d443284cd68b30a92014a35a80fc5 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 16:07:54 -0400 Subject: [PATCH 019/325] Add pip<24.1 spec for default pip --- StabilityMatrix.Core/Python/PyRunner.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/StabilityMatrix.Core/Python/PyRunner.cs b/StabilityMatrix.Core/Python/PyRunner.cs index 6e384449c..830e7d935 100644 --- a/StabilityMatrix.Core/Python/PyRunner.cs +++ b/StabilityMatrix.Core/Python/PyRunner.cs @@ -116,10 +116,17 @@ public async Task SetupPip() throw new FileNotFoundException("get-pip not found", GetPipPath); } - var result = await ProcessRunner - .GetProcessResultAsync(PythonExePath, "-m get-pip") + await ProcessRunner + .GetProcessResultAsync(PythonExePath, ["-m", "get-pip"]) + .EnsureSuccessExitCode() + .ConfigureAwait(false); + + // Pip version 24.1 deprecated numpy star requirement spec used by some packages + // So make the base pip less than that for compatibility, venvs can upgrade themselves if needed + await ProcessRunner + .GetProcessResultAsync(PythonExePath, ["-m", "pip", "install", "pip>=23.3.2,<24.1"]) + .EnsureSuccessExitCode() .ConfigureAwait(false); - result.EnsureSuccessExitCode(); } /// From fca3f4be45199615c658a722db018b5c5d1270a9 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 16:09:59 -0400 Subject: [PATCH 020/325] Add pip<24.1 spec for Fooocus install --- StabilityMatrix.Core/Models/Packages/Fooocus.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 905e94032..33d0fd0b3 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -273,6 +273,9 @@ public override async Task InstallPackage( progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + // Pip version 24.1 deprecated numpy requirement spec used by torchsde 0.2.5 + await venvRunner.PipInstall(["pip>=23.3.2,<24.1"], onConsoleOutput).ConfigureAwait(false); + var pipArgs = new PipInstallArgs(); if (torchVersion == TorchVersion.DirectMl) From 9ebfaceb691abc82785f66bae7bcffa041e5935e Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 16:21:20 -0400 Subject: [PATCH 021/325] changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0752c0526..e264039c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ### Added - Image viewer context menus now have 2 options: `Copy (Ctrl+C)` which now always copies the image as a file, and `Copy as Bitmap (Shift+Ctrl+C)` (Available on Windows) which copies to the clipboard as native bitmap. This changes the previous single `Copy` button behavior that would first attempt a native bitmap copy on Windows when available, and fall back to a file copy if not. +## v2.11.3 +### Changed +- Base Python install will now use `pip>=23.3.2,<24.1` for compatibility with `torchsde`.Individual Packages can upgrade as required. +- Added default `PIP_DISABLE_PIP_VERSION_CHECK=1` environment variable to suppress notices about pip version checks. + - As with other default environment variables, this can be overridden by setting your own value in `Settings > Environment Variables [Edit]`. +### Fixed +- Fooocus Package - Added `pip>=23.3.2,<24.1` specifier before install, fixes potential install errors due to deprecated requirement spec used by `torchsde`. + ## v2.11.2 ### Changed - StableSwarmUI installs will be migrated to SwarmUI by mcmonkeyprojects the next time the package is updated From 4914e95ead290f33aa8decf6c9140b489afdad67 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 16:35:38 -0400 Subject: [PATCH 022/325] Add supporters --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e264039c3..4da8b02f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - As with other default environment variables, this can be overridden by setting your own value in `Settings > Environment Variables [Edit]`. ### Fixed - Fooocus Package - Added `pip>=23.3.2,<24.1` specifier before install, fixes potential install errors due to deprecated requirement spec used by `torchsde`. +### Supporters +#### Visionaries +- Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! +#### Pioneers +- Thank you to our Pioneer-tier supporters on Patreon, **tankfox** and **tanangular**! Your support is greatly appreciated! ## v2.11.2 ### Changed From 9301b378f299ba24baf02dc259595f7501366542 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 18:32:31 -0400 Subject: [PATCH 023/325] Add .backportrc.json --- .backportrc.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .backportrc.json diff --git a/.backportrc.json b/.backportrc.json new file mode 100644 index 000000000..0bf6eeb48 --- /dev/null +++ b/.backportrc.json @@ -0,0 +1,8 @@ +{ + "sourceBranch": "dev", + "targetBranch": "main", + "mainline": 1, + "fork": false, + "targetPRLabels": ["backport"], + "prTitle": "[{{sourceBranch}} to {{targetBranch}}] backport: {{sourcePullRequest.title}} ({{sourcePullRequest.number}})" +} From 3415e1ad167c35c332893f42bb274852611da83d Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 23 Jun 2024 18:33:08 -0400 Subject: [PATCH 024/325] Fix targetPRLabels arg, set commitConflicts=true --- .github/workflows/backport.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index d2838198e..c4562308f 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -22,8 +22,9 @@ jobs: name: ".backportrc.json" json: | { - "targetPRLabels": "backport", + "targetPRLabels": ["backport"], "mainline": ${{ env.CP_MAINLINE }}, + "commitConflicts": "true", "prTitle": "[{{sourceBranch}} to {{targetBranch}}] backport: {{sourcePullRequest.title}} ({{sourcePullRequest.number}})" } From bd90ac02fbd55f0107d1335ee2da1086b09edd03 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 18:06:40 -0700 Subject: [PATCH 025/325] Added Change Version & Disable Update Check for packages --- CHANGELOG.md | 2 + .../Languages/Resources.Designer.cs | 18 +++ .../Languages/Resources.resx | 6 + .../Dialogs/PackageImportViewModel.cs | 65 +++++--- .../PackageManager/PackageCardViewModel.cs | 144 +++++++++++++++++- .../Views/Dialogs/PackageImportDialog.axaml | 15 +- .../MainPackageManagerView.axaml | 40 ++++- .../Models/InstalledPackage.cs | 1 + .../Models/Settings/Settings.cs | 9 ++ 9 files changed, 276 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0752c0526..1fff19148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.12.0-dev.1 ### Added - Image viewer context menus now have 2 options: `Copy (Ctrl+C)` which now always copies the image as a file, and `Copy as Bitmap (Shift+Ctrl+C)` (Available on Windows) which copies to the clipboard as native bitmap. This changes the previous single `Copy` button behavior that would first attempt a native bitmap copy on Windows when available, and fall back to a file copy if not. +- Added "Change Version" option to the package card overflow menu, allowing you to downgrade or upgrade a package to a specific version or commit +- Added "Disable Update Check" option to the package card overflow menu, allowing you to disable update checks for a specific package ## v2.11.2 ### Changed diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 8236f4986..c8d5754d6 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -1292,6 +1292,15 @@ public static string Label_Details { } } + /// + /// Looks up a localized string similar to Disable Update Check. + /// + public static string Label_DisableUpdateCheck { + get { + return ResourceManager.GetString("Label_DisableUpdateCheck", resourceCulture); + } + } + /// /// Looks up a localized string similar to Discord Rich Presence. /// @@ -3056,6 +3065,15 @@ public static string TextTemplate_PackageUpdatedToLatest { } } + /// + /// Looks up a localized string similar to {0} has been updated to the selected version. + /// + public static string TextTemplate_PackageUpdatedToSelected { + get { + return ResourceManager.GetString("TextTemplate_PackageUpdatedToSelected", resourceCulture); + } + } + /// /// Looks up a localized string similar to Updating {0}. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 73d3e4df5..a9b90c3e9 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1116,7 +1116,13 @@ App Data + + {0} has been updated to the selected version + Copy as Bitmap + + Disable Update Check + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs index 06ff94de5..a88a6c625 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs @@ -53,13 +53,18 @@ public partial class PackageImportViewModel : ContentDialogViewModelBase [ObservableProperty] private GitCommit? selectedCommit; + [ObservableProperty] + private bool canSelectBasePackage = true; + + [ObservableProperty] + private string? customCommitSha; + + [ObservableProperty] + private bool showCustomCommitSha; + // Version types (release or commit) [ObservableProperty] - [NotifyPropertyChangedFor( - nameof(ReleaseLabelText), - nameof(IsReleaseMode), - nameof(SelectedVersion) - )] + [NotifyPropertyChangedFor(nameof(ReleaseLabelText), nameof(IsReleaseMode), nameof(SelectedVersion))] private PackageVersionType selectedVersionType = PackageVersionType.Commit; [ObservableProperty] @@ -70,14 +75,10 @@ public partial class PackageImportViewModel : ContentDialogViewModelBase public bool IsReleaseMode { get => SelectedVersionType == PackageVersionType.GithubRelease; - set => - SelectedVersionType = value - ? PackageVersionType.GithubRelease - : PackageVersionType.Commit; + set => SelectedVersionType = value ? PackageVersionType.GithubRelease : PackageVersionType.Commit; } - public bool IsReleaseModeAvailable => - AvailableVersionTypes.HasFlag(PackageVersionType.GithubRelease); + public bool IsReleaseModeAvailable => AvailableVersionTypes.HasFlag(PackageVersionType.GithubRelease); public PackageImportViewModel(IPackageFactory packageFactory, ISettingsManager settingsManager) { @@ -138,6 +139,34 @@ partial void OnAvailableVersionTypesChanged(PackageVersionType value) partial void OnSelectedVersionTypeChanged(PackageVersionType value) => OnSelectedBasePackageChanged(SelectedBasePackage); + partial void OnSelectedVersionChanged(PackageVersion? value) + { + if (value == null || IsReleaseMode) + return; + + if (SelectedBasePackage is BaseGitPackage gitPackage) + { + Dispatcher + .UIThread.InvokeAsync(async () => + { + var commits = (await gitPackage.GetAllCommits(value.TagName))?.ToList(); + if (commits is null || commits.Count == 0) + return; + + commits = [..commits, new GitCommit { Sha = "Custom..." }]; + + AvailableCommits = new ObservableCollection(commits); + SelectedCommit = AvailableCommits[0]; + }) + .SafeFireAndForget(); + } + } + + partial void OnSelectedCommitChanged(GitCommit? value) + { + ShowCustomCommitSha = value is { Sha: "Custom..." }; + } + partial void OnSelectedBasePackageChanged(BasePackage? value) { if (value is null || SelectedBasePackage is null) @@ -155,13 +184,13 @@ partial void OnSelectedBasePackageChanged(BasePackage? value) if (Design.IsDesignMode) return; - Dispatcher.UIThread - .InvokeAsync(async () => + Dispatcher + .UIThread.InvokeAsync(async () => { Logger.Debug($"Release mode: {IsReleaseMode}"); var versionOptions = await value.GetAllVersionOptions(); - AvailableVersions = IsReleaseModeAvailable + AvailableVersions = IsReleaseMode ? new ObservableCollection(versionOptions.AvailableVersions) : new ObservableCollection(versionOptions.AvailableBranches); @@ -174,6 +203,8 @@ partial void OnSelectedBasePackageChanged(BasePackage? value) if (commits is null || commits.Count == 0) return; + commits = [..commits, new GitCommit { Sha = "Custom..." }]; + AvailableCommits = new ObservableCollection(commits); SelectedCommit = AvailableCommits[0]; UpdateSelectedVersionToLatestMain(); @@ -211,14 +242,12 @@ public async Task AddPackageWithCurrentInputs() if (IsReleaseMode) { version.InstalledReleaseVersion = - SelectedVersion?.TagName - ?? throw new NullReferenceException("Selected version is null"); + SelectedVersion?.TagName ?? throw new NullReferenceException("Selected version is null"); } else { version.InstalledBranch = - SelectedVersion?.TagName - ?? throw new NullReferenceException("Selected version is null"); + SelectedVersion?.TagName ?? throw new NullReferenceException("Selected version is null"); version.InstalledCommitSha = SelectedCommit?.Sha ?? throw new NullReferenceException("Selected commit is null"); } diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index e6908b77b..e4b4410d2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -98,6 +98,9 @@ RunningPackageService runningPackageService [ObservableProperty] private DownloadPackageVersionOptions? updateVersion; + [ObservableProperty] + private bool dontCheckForUpdates; + private void RunningPackagesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (runningPackageService.RunningPackages.Select(x => x.Value) is not { } runningPackages) @@ -147,6 +150,7 @@ partial void OnPackageChanged(InstalledPackage? value) UseSharedOutput = Package?.UseSharedOutputFolder ?? false; CanUseSharedOutput = basePackage?.SharedOutputFolders != null; CanUseExtensions = basePackage?.SupportsExtensions ?? false; + DontCheckForUpdates = Package?.DontCheckForUpdates ?? false; runningPackageService.RunningPackages.CollectionChanged += RunningPackagesOnCollectionChanged; EventManager.Instance.PackageRelaunchRequested += InstanceOnPackageRelaunchRequested; @@ -526,6 +530,119 @@ public async Task OpenFolder() await ProcessRunner.OpenFolderBrowser(Package.FullPath); } + [RelayCommand] + private async Task ChangeVersion() + { + if (Package is null || IsUnknownPackage) + return; + + var basePackage = packageFactory[Package.PackageName!]; + if (basePackage == null) + { + logger.LogWarning("Could not find package {SelectedPackagePackageName}", Package.PackageName); + notificationService.Show( + Resources.Label_InvalidPackageType, + Package.PackageName.ToRepr(), + NotificationType.Error + ); + return; + } + + var packageName = Package.DisplayName ?? Package.PackageName ?? ""; + + Text = $"Updating {packageName}"; + IsIndeterminate = true; + + try + { + var viewModel = vmFactory.Get(vm => + { + vm.PackagePath = new DirectoryPath( + Package?.FullPath ?? throw new InvalidOperationException() + ); + }); + + viewModel.SelectedBasePackage = basePackage; + viewModel.CanSelectBasePackage = false; + viewModel.IsReleaseMode = Package.Version?.IsReleaseMode ?? false; + + var dialog = new TaskDialog + { + Content = new PackageImportDialog { DataContext = viewModel }, + ShowProgressBar = false, + Buttons = new List + { + new(Resources.Action_Update, TaskDialogStandardResult.Yes) { IsDefault = true }, + new(Resources.Action_Cancel, TaskDialogStandardResult.Cancel) + }, + XamlRoot = App.VisualRoot + }; + + var result = await dialog.ShowAsync(); + if (result is not TaskDialogStandardResult.Yes) + return; + + var runner = new PackageModificationRunner + { + ModificationCompleteMessage = $"Updated {packageName}", + ModificationFailedMessage = $"Could not update {packageName}" + }; + + var versionOptions = new DownloadPackageVersionOptions(); + + if (!string.IsNullOrWhiteSpace(viewModel.CustomCommitSha)) + { + versionOptions.BranchName = viewModel.SelectedVersion?.TagName; + versionOptions.CommitHash = viewModel.CustomCommitSha; + } + else if (viewModel.SelectedVersionType == PackageVersionType.GithubRelease) + { + versionOptions.VersionTag = viewModel.SelectedVersion?.TagName; + } + else + { + versionOptions.BranchName = viewModel.SelectedVersion?.TagName; + versionOptions.CommitHash = viewModel.SelectedCommit?.Sha; + } + + var updatePackageStep = new UpdatePackageStep( + settingsManager, + Package, + versionOptions, + basePackage + ); + var steps = new List { updatePackageStep }; + + EventManager.Instance.OnPackageInstallProgressAdded(runner); + await runner.ExecuteSteps(steps); + + EventManager.Instance.OnInstalledPackagesChanged(); + + IsUpdateAvailable = false; + InstalledVersion = Package.Version?.DisplayVersion ?? "Unknown"; + notificationService.Show( + Resources.Progress_UpdateComplete, + string.Format(Resources.TextTemplate_PackageUpdatedToSelected, packageName), + NotificationType.Success + ); + } + catch (Exception e) + { + logger.LogError(e, "Error Updating Package ({PackageName})", basePackage.Name); + notificationService.ShowPersistent( + string.Format(Resources.TextTemplate_ErrorUpdatingPackage, packageName), + e.Message, + NotificationType.Error + ); + } + finally + { + IsIndeterminate = false; + Value = 0; + Text = ""; + } + } + [RelayCommand] public async Task OpenPythonPackagesDialog() { @@ -646,7 +763,7 @@ private async Task ShowLaunchOptions() private async Task HasUpdate() { - if (Package == null || IsUnknownPackage || Design.IsDesignMode) + if (Package == null || IsUnknownPackage || Design.IsDesignMode || Package.DontCheckForUpdates) return false; var basePackage = packageFactory[Package.PackageName!]; @@ -689,6 +806,8 @@ private async Task HasUpdate() public void ToggleSharedOutput() => UseSharedOutput = !UseSharedOutput; + public void ToggleDontCheckForUpdates() => DontCheckForUpdates = !DontCheckForUpdates; + partial void OnUseSharedOutputChanged(bool value) { if (Package == null) @@ -776,6 +895,29 @@ partial void OnIsSharedModelDisabledChanged(bool value) } } + partial void OnDontCheckForUpdatesChanged(bool value) + { + if (value) + { + UpdateVersion = null; + IsUpdateAvailable = false; + if (Package != null) + { + Package.UpdateAvailable = false; + } + } + else if (Package != null) + { + Package.LastUpdateCheck = DateTimeOffset.MinValue; + OnLoadedAsync().SafeFireAndForget(); + } + + settingsManager.Transaction(s => + { + s.SetUpdateCheckDisabledForPackage(Package, value); + }); + } + private void RunningPackageOnStartupComplete(object? sender, string e) { webUiUrl = e.Replace("0.0.0.0", "127.0.0.1"); diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/PackageImportDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/PackageImportDialog.axaml index 8cdbf0937..bf2afd31f 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/PackageImportDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/PackageImportDialog.axaml @@ -14,15 +14,17 @@ - - + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml index 7ea4e906e..6a00bfec9 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml @@ -104,12 +104,33 @@ + + + + + + + + + + + + + + + + @@ -127,7 +148,7 @@ - + + + + + + + @@ -215,7 +246,9 @@ - + + + @@ -240,6 +273,7 @@ + ? LaunchArgs { get; set; } public DateTimeOffset? LastUpdateCheck { get; set; } public bool UpdateAvailable { get; set; } + public bool DontCheckForUpdates { get; set; } [JsonConverter(typeof(JsonStringEnumConverter))] public TorchVersion? PreferredTorchVersion { get; set; } diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index fd7af8cd1..932300c83 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -219,6 +219,15 @@ public void UpdateActiveInstalledPackage() } } + public void SetUpdateCheckDisabledForPackage(InstalledPackage package, bool disabled) + { + var installedPackage = InstalledPackages.FirstOrDefault(p => p.Id == package.Id); + if (installedPackage != null) + { + installedPackage.DontCheckForUpdates = disabled; + } + } + /// /// Return either the system default culture, if supported, or en-US /// From b79b7b6fc29789d273d2d986a2c571699de813a2 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 18:23:47 -0700 Subject: [PATCH 026/325] transaction before reload --- .../PackageManager/PackageCardViewModel.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index e4b4410d2..194be4d28 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -901,21 +901,25 @@ partial void OnDontCheckForUpdatesChanged(bool value) { UpdateVersion = null; IsUpdateAvailable = false; - if (Package != null) + + if (Package == null) + return; + + Package.UpdateAvailable = false; + settingsManager.Transaction(s => { - Package.UpdateAvailable = false; - } + s.SetUpdateCheckDisabledForPackage(Package, value); + }); } else if (Package != null) { Package.LastUpdateCheck = DateTimeOffset.MinValue; + settingsManager.Transaction(s => + { + s.SetUpdateCheckDisabledForPackage(Package, value); + }); OnLoadedAsync().SafeFireAndForget(); } - - settingsManager.Transaction(s => - { - s.SetUpdateCheckDisabledForPackage(Package, value); - }); } private void RunningPackageOnStartupComplete(object? sender, string e) From 7ca13f2671c7ecb8a9fb8ab8ec6d1ec6bd5ea818 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 18:40:30 -0700 Subject: [PATCH 027/325] fix window thing being a window and not dialog --- .../ViewModels/PackageManager/PackageCardViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 194be4d28..415a48915 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -578,7 +578,7 @@ private async Task ChangeVersion() XamlRoot = App.VisualRoot }; - var result = await dialog.ShowAsync(); + var result = await dialog.ShowAsync(true); if (result is not TaskDialogStandardResult.Yes) return; From 75081cc3f72b28a463bc2fe9eb0695b693fb0235 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 20:19:56 -0700 Subject: [PATCH 028/325] fail message if fail --- .../PackageManager/PackageCardViewModel.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 194be4d28..8b4c3cb0d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -617,14 +617,25 @@ private async Task ChangeVersion() await runner.ExecuteSteps(steps); EventManager.Instance.OnInstalledPackagesChanged(); - IsUpdateAvailable = false; InstalledVersion = Package.Version?.DisplayVersion ?? "Unknown"; - notificationService.Show( - Resources.Progress_UpdateComplete, - string.Format(Resources.TextTemplate_PackageUpdatedToSelected, packageName), - NotificationType.Success - ); + + if (runner.Failed) + { + notificationService.Show( + Resources.Progress_UpdateFailed, + string.Format(runner.ModificationFailedMessage, packageName), + NotificationType.Error + ); + } + else + { + notificationService.Show( + Resources.Progress_UpdateComplete, + string.Format(Resources.TextTemplate_PackageUpdatedToSelected, packageName), + NotificationType.Success + ); + } } catch (Exception e) { From f4616930db2d8fac78659aa0e28f5effab2ca3a6 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 20:44:42 -0700 Subject: [PATCH 029/325] Fix swarm launch when spaces in path & fix model folders not being created on app startup --- .../ViewModels/CheckpointsPageViewModel.cs | 9 --------- .../ViewModels/MainWindowViewModel.cs | 7 +++++++ StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 8ddac7b54..2d0b3d825 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -295,15 +295,6 @@ or nameof(SortConnectedModelsFirst) true ); - try - { - SharedFolders.SetupSharedModelFolders(settingsManager.ModelsDirectory); - } - catch (Exception e) - { - logger.LogError(e, @"Failed to setup shared model folders"); - } - Refresh().SafeFireAndForget(); EventManager.Instance.ModelIndexChanged += (_, _) => diff --git a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs index 94f6369e7..2e1d92085 100644 --- a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using AsyncAwaitBestPractices; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Threading; @@ -115,6 +116,12 @@ protected override async Task OnInitialLoadedAsync() return; } + Task.Run(() => SharedFolders.SetupSharedModelFolders(settingsManager.ModelsDirectory)) + .SafeFireAndForget(ex => + { + Logger.Error(ex, "Error setting up shared model folders"); + }); + try { await modelDownloadLinkHandler.Value.StartListening(); diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 28ad81d5e..32ca92eb2 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -280,7 +280,7 @@ void HandleConsoleOutput(ProcessOutput s) dotnetProcess = await prerequisiteHelper .RunDotnet( - args: $"{Path.Combine(releaseFolder, dllName)} {arguments.TrimEnd()}", + args: [Path.Combine(releaseFolder, dllName), arguments.TrimEnd()], workingDirectory: installedPackagePath, envVars: aspEnvVars, onProcessOutput: HandleConsoleOutput, From ad3c1932c133f14d56b8d7907c62c7b9089602e7 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 23 Jun 2024 20:45:02 -0700 Subject: [PATCH 030/325] chagenlog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf04486a2..bf2afb10e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - As with other default environment variables, this can be overridden by setting your own value in `Settings > Environment Variables [Edit]`. ### Fixed - Fooocus Package - Added `pip>=23.3.2,<24.1` specifier before install, fixes potential install errors due to deprecated requirement spec used by `torchsde`. +- Fixed error when launching SwarmUI when installed to a path with spaces +- Fixed issue where model folders were being created too late in certain cases ### Supporters #### Visionaries - Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! From 1d046bbe94596945b49db07b9eaf4acd378847e7 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jun 2024 17:36:22 -0400 Subject: [PATCH 031/325] Add LiteDBContext.ClearAllCacheCollectionsAsync --- .../Database/ILiteDbContext.cs | 5 ++++ .../Database/LiteDbContext.cs | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/StabilityMatrix.Core/Database/ILiteDbContext.cs b/StabilityMatrix.Core/Database/ILiteDbContext.cs index 3e4288157..0fe7e7275 100644 --- a/StabilityMatrix.Core/Database/ILiteDbContext.cs +++ b/StabilityMatrix.Core/Database/ILiteDbContext.cs @@ -21,4 +21,9 @@ public interface ILiteDbContext : IDisposable Task UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCacheEntry entry); Task GetGithubCacheEntry(string cacheKey); Task UpsertGithubCacheEntry(GithubCacheEntry cacheEntry); + + /// + /// Clear all Collections that store re-fetchable cache type data. + /// + Task ClearAllCacheCollectionsAsync(); } diff --git a/StabilityMatrix.Core/Database/LiteDbContext.cs b/StabilityMatrix.Core/Database/LiteDbContext.cs index 9a87e4779..e0eaa3d4b 100644 --- a/StabilityMatrix.Core/Database/LiteDbContext.cs +++ b/StabilityMatrix.Core/Database/LiteDbContext.cs @@ -174,6 +174,30 @@ public async Task UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCach public Task UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) => GithubCache.UpsertAsync(cacheEntry); + /// + /// Clear all Collections that store re-fetchable cache type data. + /// + public async Task ClearAllCacheCollectionsAsync() + { + var collectionNames = new List + { + nameof(CivitModels), + nameof(CivitModelVersions), + nameof(CivitModelQueryCache), + nameof(GithubCache), + nameof(LocalModelFiles), + nameof(LocalImageFiles) + }; + + logger.LogInformation("Clearing all cache collections: [{@Names}]", collectionNames); + + foreach (var name in collectionNames) + { + var collection = Database.GetCollection(name); + await collection.DeleteAllAsync().ConfigureAwait(false); + } + } + public void Dispose() { if (lazyDatabase.IsValueCreated) From 660b31f35d0cee222ea938cc18aac3de803acc76 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jun 2024 17:36:48 -0400 Subject: [PATCH 032/325] Fix exceptions in litedb deserialize for ModelIndexService --- .../Services/ModelIndexService.cs | 67 ++++++++++++++++--- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index 5256ac1c3..0efea7fc3 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -2,10 +2,11 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Text; -using System.Text.Json; using AsyncAwaitBestPractices; using AutoCtor; using KGySoft.CoreLibraries; +using LiteDB; +using LiteDB.Async; using Microsoft.Extensions.Logging; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Database; @@ -15,6 +16,7 @@ using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FileInterfaces; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace StabilityMatrix.Core.Services; @@ -103,9 +105,34 @@ private async Task LoadFromDbAsync() logger.LogInformation("Loading models from database..."); - var allModels = ( - await liteDbContext.LocalModelFiles.IncludeAll().FindAllAsync().ConfigureAwait(false) - ).ToImmutableArray(); + ImmutableArray allModels = []; + try + { + allModels = + [ + ..( + await liteDbContext.LocalModelFiles.IncludeAll().FindAllAsync().ConfigureAwait(false) + ) + ]; + } + catch (Exception e) + { + // Handle enum deserialize exceptions from changes + if (e is LiteException or LiteAsyncException && e.InnerException is ArgumentException inner) + { + logger.LogWarning( + e, + "LiteDb Deserialize error while fetching LocalModelFiles '{Inner}', cache collections will be cleared", + inner.ToString() + ); + + await liteDbContext.ClearAllCacheCollectionsAsync().ConfigureAwait(false); + } + else + { + throw; + } + } ModelIndex = allModels.GroupBy(m => m.SharedFolderType).ToDictionary(g => g.Key, g => g.ToList()); @@ -479,12 +506,34 @@ private async Task RefreshIndexParallelCore() if (model.LatestModelInfo == null && model.HasConnectedModel) { - var civitModel = await liteDbContext - .CivitModels.Include(m => m.ModelVersions) - .FindByIdAsync(model.ConnectedModelInfo.ModelId) - .ConfigureAwait(false); + try + { + model.LatestModelInfo = await liteDbContext + .CivitModels.Include(m => m.ModelVersions) + .FindByIdAsync(model.ConnectedModelInfo.ModelId) + .ConfigureAwait(false); + } + catch (Exception e) + { + // Handle enum deserialize exceptions from changes + if ( + e is LiteException or LiteAsyncException + && e.InnerException is ArgumentException inner + ) + { + logger.LogWarning( + e, + "LiteDb Deserialize error while fetching CivitModels '{Inner}', cache collections will be cleared", + inner.ToString() + ); - model.LatestModelInfo = civitModel; + await liteDbContext.ClearAllCacheCollectionsAsync().ConfigureAwait(false); + } + else + { + throw; + } + } } var list = newIndex.GetOrAdd(model.SharedFolderType); list.Add(model); From 76b9145692d2652cc009eed2f2d91d87c0d2f1ab Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jun 2024 17:38:35 -0400 Subject: [PATCH 033/325] chagenlog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2afb10e..94764e9de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fooocus Package - Added `pip>=23.3.2,<24.1` specifier before install, fixes potential install errors due to deprecated requirement spec used by `torchsde`. - Fixed error when launching SwarmUI when installed to a path with spaces - Fixed issue where model folders were being created too late in certain cases +- Fixed [#683](https://github.com/LykosAI/StabilityMatrix/issues/683) - Model indexing causing LiteDB errors after upgrading from older versions due to updated enum values ### Supporters #### Visionaries - Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! From 7ae1d9efadff2622a9b5858d9d2755911b4a2b78 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jun 2024 18:16:06 -0400 Subject: [PATCH 034/325] Fix Inference prompt syntax for text allowing comments to be captured --- StabilityMatrix.Avalonia/Assets/ImagePrompt.tmLanguage.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Assets/ImagePrompt.tmLanguage.json b/StabilityMatrix.Avalonia/Assets/ImagePrompt.tmLanguage.json index fdf0964e3..6cca1b548 100644 --- a/StabilityMatrix.Avalonia/Assets/ImagePrompt.tmLanguage.json +++ b/StabilityMatrix.Avalonia/Assets/ImagePrompt.tmLanguage.json @@ -211,7 +211,7 @@ "name": "meta.embedded.model" }, "text": { - "match": "[^,:\\[\\]\\(\\)\\<\\> \\\\]+", + "match": "[^#,:\\[\\]\\(\\)\\<\\> \\\\]+", "name": "meta.embedded" }, "invalid_reserved" : { From 8a9acf7375434c497d60769548ad2412ee5d7189 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 25 Jun 2024 16:26:13 -0400 Subject: [PATCH 035/325] chagenlog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94764e9de..582c74b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Change Version" option to the package card overflow menu, allowing you to downgrade or upgrade a package to a specific version or commit - Added "Disable Update Check" option to the package card overflow menu, allowing you to disable update checks for a specific package +## v2.11.4 +### Fixed +- Fixed [#719](https://github.com/LykosAI/StabilityMatrix/issues/719) - Fix comments in Inference prompt not being ignored +### Supporters +#### Visionaries +- Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! +#### Pioneers +- Thank you to our Pioneer-tier supporters on Patreon, **tankfox** and **tanangular**! Your support is greatly appreciated! + ## v2.11.3 ### Changed - Base Python install will now use `pip>=23.3.2,<24.1` for compatibility with `torchsde`.Individual Packages can upgrade as required. From d6b4b425e7ca5dac605982c4a34d6452c80ec1a3 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 25 Jun 2024 18:16:08 -0400 Subject: [PATCH 036/325] Add issue templates --- .github/ISSUE_TEMPLATE/1-bug.yml | 62 ++++++++++++++++ .github/ISSUE_TEMPLATE/2-bug-crash.yml | 58 +++++++++++++++ .github/ISSUE_TEMPLATE/3-bug-package.yml | 78 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/4-feature-request.yml | 15 ++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ 5 files changed, 218 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/1-bug.yml create mode 100644 .github/ISSUE_TEMPLATE/2-bug-crash.yml create mode 100644 .github/ISSUE_TEMPLATE/3-bug-package.yml create mode 100644 .github/ISSUE_TEMPLATE/4-feature-request.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/1-bug.yml b/.github/ISSUE_TEMPLATE/1-bug.yml new file mode 100644 index 000000000..74725a877 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug.yml @@ -0,0 +1,62 @@ +name: Bug report +description: Submit a bug report +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + **New to Stability Matrix?** + For help or advice on using Stability Matrix, try one of the following options instead of opening a GitHub issue: + - Asking on our [Discord server](https://link.lykos.ai/discord?ref=github-issue-template) + - Creating a post on [Discussions](https://github.com/LykosAI/StabilityMatrix/discussions) + + This template is for reporting bugs experienced within the Stability Matrix app. + If your issue is regarding Package behavior when running it, or when installing or updating a specific Package, please use the [Package issue template](https://github.com/LykosAI/StabilityMatrix/issues/new/choose) instead. + + Make sure to also search the [existing issues](https://github.com/LykosAI/StabilityMatrix/issues) to see if your issue has already been reported. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Give a clear and concise description of what happened. Provide screenshots or videos of UI if necessary. Also tell us, what did you expect to happen? + placeholder: | + When dragging a model file into the ... page to import, I expected to see... + + Instead, I saw... + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: Steps to reproduce + description: Include a minimal step-by-step guide to reproduce the issue if possible. + placeholder: | + 1. Open Stability Matrix + 2. Go to the ... page + 3. Click on the ... button + 4. Expected to see ... open, but instead ... + - type: textarea + id: app-logs + attributes: + label: Relevant logs + description: Please copy and paste any relevant log output. (This will be automatically formatted, so no need for backticks.) + render: shell + - type: input + id: version + attributes: + label: Version + description: What version of Stability Matrix are you running? (Can be found at the bottom of the settings page) + placeholder: ex. v2.11.0 + validations: + required: true + - type: dropdown + id: os-platform + attributes: + label: What Operating System are you using? + options: + - Windows + - macOS + - Linux + - Other + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/2-bug-crash.yml b/.github/ISSUE_TEMPLATE/2-bug-crash.yml new file mode 100644 index 000000000..c592294d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-bug-crash.yml @@ -0,0 +1,58 @@ +name: Crash report +description: A crash of Stability Matrix, likely with the "An unexpected error occurred" dialog +labels: ["bug", "crash", "triage"] +body: + - type: markdown + attributes: + value: | + This template is for reporting crashes of Stability Matrix, likely with the "An unexpected error occurred" dialog. + If you are experiencing a different issue, please use the [Bug Report or Package Issue templates](https://github.com/LykosAI/StabilityMatrix/issues/new/choose). + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Give a clear and concise description of what happened. Include some minimal steps to reproducible the issue if possible. + placeholder: | + 1. Open Stability Matrix + 2. Go to the "..." page + 3. Click on the "..." button + 4. See the crash + validations: + required: true + - type: textarea + id: exception-details + attributes: + label: Exception Details + description: Please click the "Copy Details" button on the crash dialog and paste the details exactly as formatted here. + placeholder: | + ## Exception + OperationCanceledException: Example Message + ### Sentry ID + ``` + bc7da9b2fcc3e3568ceb81a72f3a128d + ``` + ### Stack Trace + ``` + at StabilityMatrix.Avalonia.ViewModels.Settings.MainSettingsViewModel.DebugThrowException() in MainSettingsViewModel.cs:line 716 + at CommunityToolkit.Mvvm.Input.RelayCommand.Execute(Object parameter) + ... + ``` + - type: input + id: version + attributes: + label: Version + description: What version of Stability Matrix are you running? (Can be found at the bottom of the settings page) + placeholder: ex. v2.11.0 + validations: + required: true + - type: dropdown + id: os-platform + attributes: + label: What Operating System are you using? + options: + - Windows + - macOS + - Linux + - Other + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/3-bug-package.yml b/.github/ISSUE_TEMPLATE/3-bug-package.yml new file mode 100644 index 000000000..036e70b85 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-bug-package.yml @@ -0,0 +1,78 @@ +name: Package issue +description: Report an issue with installing, updating, or running a Package +labels: ["bug", "area: package", "triage"] +body: + - type: markdown + attributes: + value: | + **Experiencing an issue while running a Package?** + + Make sure to also search the GitHub issues of the Package, to see if your issue has already been reported and being worked on by upstream authors. + - type: textarea + id: package-details + attributes: + label: Package + description: Provide the name of the Package you are experiencing issues with + placeholder: ex. `ComfyUI` + validations: + required: true + - type: dropdown + id: package-issue-phase + attributes: + label: When did the issue occur? + options: + - Installing the Package + - Updating the Package + - Running the Package + - Other + validations: + required: true + - type: input + id: hardware + attributes: + label: What GPU / hardware type are you using? + description: Installed dependencies and Package features often depend on the GPU or hardware type you are using. + placeholder: ex. Nvidia 2080 Super with CUDA, AMD Radeon VII, etc. + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Give a clear and concise description of what happened. Provide screenshots if necessary. Also tell us, what did you expect to happen? + validations: + required: true + - type: textarea + id: console-output + attributes: + label: Console output + description: Please copy and paste any console output or error messages. For failed install or updates, locate the progress on the bottom left, open the dialog, and click on "More Details" to copy the full console output. + placeholder: | + ``` + Unpacking... + Successfully built lycoris_lora + Installing collected packages: library, tomlkit, onnx, ml-dtypes, onnxruntime-gpu + Running setup.py develop for library + Attempting uninstall: onnx + Found existing installation: onnx 1.14.1 + ... + ``` + - type: input + id: version + attributes: + label: Version + description: What version of Stability Matrix are you running? (Can be found at the bottom of the settings page) + placeholder: ex. v2.11.0 + validations: + required: true + - type: dropdown + id: os-platform + attributes: + label: What Operating System are you using? + options: + - Windows + - macOS + - Linux + - Other + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/4-feature-request.yml b/.github/ISSUE_TEMPLATE/4-feature-request.yml new file mode 100644 index 000000000..34199f5d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4-feature-request.yml @@ -0,0 +1,15 @@ +name: Feature or enhancement +description: Submit a proposal for a new Stability Matrix feature or enhancement +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Consider first discussing your idea on our [Discord server](https://link.lykos.ai/discord?ref=github-issue-template) to get feedback from the developers and the community. + - type: textarea + id: proposal + attributes: + label: Proposal + description: Explain your idea for a new feature or enhancement. Include any relevant details or links to resources like Package documentation. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..8f0c0cfa6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Getting help + url: https://link.lykos.ai/discord?ref=github-issue-template + about: Ask questions about using Stability Matrix and get tips on using Packages on our Discord server From 4cacadf26a259761af9aa009227ba08fc688e95a Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 17:24:49 -0400 Subject: [PATCH 037/325] Fix pip pinning command syntax --- StabilityMatrix.Core/Models/Packages/Fooocus.cs | 2 +- StabilityMatrix.Core/Python/PyRunner.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 33d0fd0b3..d74f75280 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -274,7 +274,7 @@ public override async Task InstallPackage( progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); // Pip version 24.1 deprecated numpy requirement spec used by torchsde 0.2.5 - await venvRunner.PipInstall(["pip>=23.3.2,<24.1"], onConsoleOutput).ConfigureAwait(false); + await venvRunner.PipInstall(["pip==23.3.2"], onConsoleOutput).ConfigureAwait(false); var pipArgs = new PipInstallArgs(); diff --git a/StabilityMatrix.Core/Python/PyRunner.cs b/StabilityMatrix.Core/Python/PyRunner.cs index 830e7d935..8afa759c0 100644 --- a/StabilityMatrix.Core/Python/PyRunner.cs +++ b/StabilityMatrix.Core/Python/PyRunner.cs @@ -124,7 +124,7 @@ await ProcessRunner // Pip version 24.1 deprecated numpy star requirement spec used by some packages // So make the base pip less than that for compatibility, venvs can upgrade themselves if needed await ProcessRunner - .GetProcessResultAsync(PythonExePath, ["-m", "pip", "install", "pip>=23.3.2,<24.1"]) + .GetProcessResultAsync(PythonExePath, ["-m", "pip", "install", "pip==23.3.2"]) .EnsureSuccessExitCode() .ConfigureAwait(false); } From 9bbc1d16f723148ac6f34da80831cd0e44472d9f Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 17:26:20 -0400 Subject: [PATCH 038/325] chagenlog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 582c74b92..adbec4967 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.11.4 ### Fixed - Fixed [#719](https://github.com/LykosAI/StabilityMatrix/issues/719) - Fix comments in Inference prompt not being ignored +- Fixed pip requirement syntax for base Python install and override in Fooocus package, should fix issues with `torchsde` install in Fooocus ### Supporters #### Visionaries - Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! From ddb8958d724a05d9ef4a96a51d32c3787667c2c7 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 17:58:35 -0400 Subject: [PATCH 039/325] Refactor PyVenvRunner to use BaseInstall for cfg path, remove old ctor --- .../Dialogs/PythonPackagesItemViewModel.cs | 12 ++++--- .../Dialogs/PythonPackagesViewModel.cs | 24 +++++++++++--- StabilityMatrix.Core/Python/PyVenvRunner.cs | 31 +++++++++---------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs index 81fcbc904..c21da2573 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Avalonia.Controls; @@ -10,10 +9,11 @@ using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Python; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; -public partial class PythonPackagesItemViewModel : ViewModelBase +public partial class PythonPackagesItemViewModel(ISettingsManager settingsManager) : ViewModelBase { [ObservableProperty] private PipPackageInfo package; @@ -101,7 +101,11 @@ public async Task LoadExtraInfo(DirectoryPath venvPath) } else { - await using var venvRunner = new PyVenvRunner(venvPath); + await using var venvRunner = await PyBaseInstall.Default.CreateVenvRunnerAsync( + venvPath, + workingDirectory: venvPath.Parent, + environmentVariables: settingsManager.Settings.EnvironmentVariables + ); PipShowResult = await venvRunner.PipShow(Package.Name); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs index 68dd5ff56..45c284b2f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs @@ -4,6 +4,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using AsyncAwaitBestPractices; +using AutoCtor; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Threading; @@ -12,6 +13,7 @@ using DynamicData; using DynamicData.Binding; using FluentAvalonia.UI.Controls; +using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.ViewModels.Base; @@ -23,14 +25,19 @@ using StabilityMatrix.Core.Models.PackageModification; using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Python; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; [View(typeof(PythonPackagesDialog))] [ManagedService] [Transient] +[AutoConstruct] public partial class PythonPackagesViewModel : ContentDialogViewModelBase { + private readonly ILogger logger; + private readonly ISettingsManager settingsManager; + public DirectoryPath? VenvPath { get; set; } [ObservableProperty] @@ -47,7 +54,8 @@ public partial class PythonPackagesViewModel : ContentDialogViewModelBase [ObservableProperty] private string searchQuery = string.Empty; - public PythonPackagesViewModel() + [AutoPostConstruct] + private void PostConstruct() { var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(100)) @@ -65,7 +73,7 @@ public PythonPackagesViewModel() .Connect() .DeferUntilLoaded() .Filter(searchPredicate) - .Transform(p => new PythonPackagesItemViewModel { Package = p }) + .Transform(p => new PythonPackagesItemViewModel(settingsManager) { Package = p }) .SortBy(vm => vm.Package.Name) .Bind(Packages) .Subscribe(); @@ -86,7 +94,11 @@ private async Task Refresh() } else { - await using var venvRunner = new PyVenvRunner(VenvPath); + await using var venvRunner = await PyBaseInstall.Default.CreateVenvRunnerAsync( + VenvPath, + workingDirectory: VenvPath.Parent, + environmentVariables: settingsManager.Settings.EnvironmentVariables + ); var packages = await venvRunner.PipList(); packageSource.EditDiff(packages); @@ -104,7 +116,11 @@ private async Task RefreshBackground() if (VenvPath is null) return; - await using var venvRunner = new PyVenvRunner(VenvPath); + await using var venvRunner = await PyBaseInstall.Default.CreateVenvRunnerAsync( + VenvPath, + workingDirectory: VenvPath.Parent, + environmentVariables: settingsManager.Settings.EnvironmentVariables + ); var packages = await venvRunner.PipList(); diff --git a/StabilityMatrix.Core/Python/PyVenvRunner.cs b/StabilityMatrix.Core/Python/PyVenvRunner.cs index fe8678f3b..b984f7f91 100644 --- a/StabilityMatrix.Core/Python/PyVenvRunner.cs +++ b/StabilityMatrix.Core/Python/PyVenvRunner.cs @@ -20,6 +20,8 @@ public class PyVenvRunner : IDisposable, IAsyncDisposable { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + private string? lastSetPyvenvCfgPath; + /// /// Relative path to the site-packages folder from the venv root. /// This is platform specific. @@ -102,13 +104,6 @@ internal PyVenvRunner(PyBaseInstall baseInstall, DirectoryPath rootPath) EnvironmentVariables = EnvironmentVariables.SetItem("VIRTUAL_ENV", rootPath.FullPath); } - [Obsolete("Use `PyBaseInstall.CreateVenvRunner` instead.")] - public PyVenvRunner(DirectoryPath rootPath) - { - RootPath = rootPath; - EnvironmentVariables = EnvironmentVariables.SetItem("VIRTUAL_ENV", rootPath.FullPath); - } - public void UpdateEnvironmentVariables( Func, ImmutableDictionary> env ) @@ -171,12 +166,16 @@ public async Task Setup( /// Set current python path to pyvenv.cfg /// This should be called before using the venv, in case user moves the venv directory. /// - private void SetPyvenvCfg(string pythonDirectory) + private void SetPyvenvCfg(string pythonDirectory, bool force = false) { // Skip if we are not created yet if (!Exists()) return; + // Skip if already set to same value + if (lastSetPyvenvCfgPath == pythonDirectory && !force) + return; + // Path to pyvenv.cfg var cfgPath = Path.Combine(RootPath, "pyvenv.cfg"); if (!File.Exists(cfgPath)) @@ -205,6 +204,9 @@ private void SetPyvenvCfg(string pythonDirectory) // Convert to string for writing, strip the top section var cfgString = cfg.ToString()!.Replace(topSection, ""); File.WriteAllText(cfgPath, cfgString); + + // Update last set path + lastSetPyvenvCfgPath = pythonDirectory; } /// @@ -230,7 +232,6 @@ public async Task PipInstall(ProcessArgs args, Action? outputData outputDataReceived?.Invoke(s); }); - SetPyvenvCfg(PyRunner.PythonDir); RunDetached(args.Prepend("-m pip install").Concat("--exists-action s"), outputAction); await Process.WaitForExitAsync().ConfigureAwait(false); @@ -266,7 +267,6 @@ public async Task PipUninstall(string args, Action? outputDataRec outputDataReceived?.Invoke(s); }); - SetPyvenvCfg(PyRunner.PythonDir); RunDetached($"-m pip uninstall -y {args}", outputAction); await Process.WaitForExitAsync().ConfigureAwait(false); @@ -289,7 +289,7 @@ public async Task> PipList() throw new FileNotFoundException("pip not found", PipPath); } - SetPyvenvCfg(PyRunner.PythonDir); + SetPyvenvCfg(BaseInstall.RootPath); var result = await ProcessRunner .GetProcessResultAsync( @@ -342,7 +342,7 @@ public async Task> PipList() throw new FileNotFoundException("pip not found", PipPath); } - SetPyvenvCfg(PyRunner.PythonDir); + SetPyvenvCfg(BaseInstall.RootPath); var result = await ProcessRunner .GetProcessResultAsync( @@ -379,7 +379,7 @@ public async Task> PipList() throw new FileNotFoundException("pip not found", PipPath); } - SetPyvenvCfg(PyRunner.PythonDir); + SetPyvenvCfg(BaseInstall.RootPath); var args = new ProcessArgsBuilder( "-m", @@ -442,7 +442,6 @@ public async Task CustomInstall(ProcessArgs args, Action? outputD outputDataReceived(s); }); - SetPyvenvCfg(PyRunner.PythonDir); RunDetached(args, outputAction); await Process.WaitForExitAsync().ConfigureAwait(false); @@ -472,7 +471,7 @@ public async Task Run(ProcessArgs arguments) output.Append(s); }); - SetPyvenvCfg(PyRunner.PythonDir); + SetPyvenvCfg(BaseInstall.RootPath); using var process = ProcessRunner.StartProcess( PythonPath, arguments, @@ -499,7 +498,7 @@ public void RunDetached( { throw new FileNotFoundException("Venv python not found", PythonPath); } - SetPyvenvCfg(PyRunner.PythonDir); + SetPyvenvCfg(BaseInstall.RootPath); Logger.Info( "Launching venv process [{PythonPath}] " From 977d2c0ddbfe8e6676c98537013d672d29836737 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 18:52:52 -0400 Subject: [PATCH 040/325] Add Version usage for PyBaseInstall, set in ctor or detected --- StabilityMatrix.Core/Python/PyBaseInstall.cs | 79 ++++++++++++++++++-- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/StabilityMatrix.Core/Python/PyBaseInstall.cs b/StabilityMatrix.Core/Python/PyBaseInstall.cs index e0a8bd676..474dba024 100644 --- a/StabilityMatrix.Core/Python/PyBaseInstall.cs +++ b/StabilityMatrix.Core/Python/PyBaseInstall.cs @@ -1,18 +1,23 @@ using System.Text.Json; +using System.Text.RegularExpressions; using NLog; using StabilityMatrix.Core.Exceptions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Processes; +using MajorMinorVersion = (int Major, int Minor); namespace StabilityMatrix.Core.Python; -public class PyBaseInstall(DirectoryPath rootPath) +public class PyBaseInstall(DirectoryPath rootPath, MajorMinorVersion? version = null) { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static PyBaseInstall Default { get; } = new(PyRunner.PythonDir); + private readonly Lazy _lazyVersion = + version != null + ? new Lazy(version.Value) + : new Lazy(() => FindPythonVersion(rootPath)); /// /// Root path of the Python installation. @@ -25,15 +30,17 @@ public class PyBaseInstall(DirectoryPath rootPath) /// public bool IsWindowsPortable { get; init; } - private int MajorVersion { get; init; } - - private int MinorVersion { get; init; } + /// + /// Major and minor version of the Python installation. + /// Set in the constructor or lazily queried via . + /// + public MajorMinorVersion Version => _lazyVersion.Value; public FilePath PythonExePath => Compat.Switch( (PlatformKind.Windows, RootPath.JoinFile("python.exe")), - (PlatformKind.Linux, RootPath.JoinFile("bin", "python3")), - (PlatformKind.MacOS, RootPath.JoinFile("bin", "python3")) + (PlatformKind.Linux, RootPath.JoinFile("bin", $"python{Version.Major}")), + (PlatformKind.MacOS, RootPath.JoinFile("bin", $"python{Version.Major}")) ); public string DefaultTclTkPath => @@ -43,6 +50,64 @@ public class PyBaseInstall(DirectoryPath rootPath) (PlatformKind.MacOS, RootPath.JoinFile("lib", "tcl8.6")) ); + public static PyBaseInstall Default { get; } = new(PyRunner.PythonDir, (3, 10)); + + // Attempt to find the major and minor version of the Python installation. + private static MajorMinorVersion FindPythonVersion( + DirectoryPath rootPath, + PlatformKind platform = default + ) + { + if (platform == default) + { + platform = Compat.Platform; + } + + var searchPath = rootPath; + string glob; + Regex regex; + + if (platform.HasFlag(PlatformKind.Windows)) + { + glob = "python*.dll"; + regex = new Regex(@"python(\d)(\d+)\.dll"); + } + else if (platform.HasFlag(PlatformKind.MacOS)) + { + searchPath = rootPath.JoinDir("lib"); + glob = "libpython*.*.dylib"; + regex = new Regex(@"libpython(\d+)\.(\d+).dylib"); + } + else if (platform.HasFlag(PlatformKind.Linux)) + { + searchPath = rootPath.JoinDir("lib"); + glob = "libpython*.*.so"; + regex = new Regex(@"libpython(\d+)\.(\d+).so"); + } + else + { + throw new NotSupportedException("Unsupported platform"); + } + + var globResults = rootPath.EnumerateFiles(glob).ToList(); + if (globResults.Count == 0) + { + throw new FileNotFoundException("Python library file not found", searchPath + glob); + } + + // Get first matching file + var match = globResults.Select(path => regex.Match(path.Name)).FirstOrDefault(x => x.Success); + if (match is null) + { + throw new FileNotFoundException( + $"Python library file not found with pattern '{regex}'", + searchPath + glob + ); + } + + return (int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value)); + } + /// /// Creates a new virtual environment runner. /// From 3ff4581d60445d242093478de8f07b097d3488ae Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 20:01:25 -0400 Subject: [PATCH 041/325] Add pinned setuptools to PyRunner.SetupPip --- StabilityMatrix.Core/Python/PyRunner.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Python/PyRunner.cs b/StabilityMatrix.Core/Python/PyRunner.cs index 8afa759c0..ebc8e47f6 100644 --- a/StabilityMatrix.Core/Python/PyRunner.cs +++ b/StabilityMatrix.Core/Python/PyRunner.cs @@ -124,7 +124,10 @@ await ProcessRunner // Pip version 24.1 deprecated numpy star requirement spec used by some packages // So make the base pip less than that for compatibility, venvs can upgrade themselves if needed await ProcessRunner - .GetProcessResultAsync(PythonExePath, ["-m", "pip", "install", "pip==23.3.2"]) + .GetProcessResultAsync( + PythonExePath, + ["-m", "pip", "install", "pip==23.3.2", "setuptools==69.5.1"] + ) .EnsureSuccessExitCode() .ConfigureAwait(false); } From 3d9598be2c438874ba580099447b513abff31e52 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 26 Jun 2024 20:11:09 -0400 Subject: [PATCH 042/325] SetupVenv with more thread safe property update and using SetupVenvPure for logic --- .../Models/Packages/BaseGitPackage.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index 8c2347dbe..999569b97 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO.Compression; using NLog; using Octokit; @@ -152,27 +153,22 @@ public async Task SetupVenv( Action? onConsoleOutput = null ) { - if (VenvRunner != null) + if (Interlocked.Exchange(ref VenvRunner, null) is { } oldRunner) { - await VenvRunner.DisposeAsync().ConfigureAwait(false); + await oldRunner.DisposeAsync().ConfigureAwait(false); } - VenvRunner = await PyBaseInstall - .Default.CreateVenvRunnerAsync( - Path.Combine(installedPackagePath, venvName), - workingDirectory: installedPackagePath, - environmentVariables: SettingsManager.Settings.EnvironmentVariables, - withDefaultTclTkEnv: Compat.IsWindows, - withQueriedTclTkEnv: Compat.IsUnix - ) + var venvRunner = await SetupVenvPure(installedPackagePath, venvName, forceRecreate, onConsoleOutput) .ConfigureAwait(false); - if (forceRecreate || !VenvRunner.Exists()) + if (Interlocked.Exchange(ref VenvRunner, venvRunner) is { } oldRunner2) { - await VenvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); + await oldRunner2.DisposeAsync().ConfigureAwait(false); } - return VenvRunner; + Debug.Assert(VenvRunner != null, "VenvRunner != null"); + + return venvRunner; } /// From b3983fca2ac0220b01fb7b08a1bf3ed3bcd4d398 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 27 Jun 2024 03:27:07 -0400 Subject: [PATCH 043/325] Fix roslyn errors from tuple type alias --- StabilityMatrix.Core/Python/MajorMinorVersion.cs | 3 +++ StabilityMatrix.Core/Python/PyBaseInstall.cs | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 StabilityMatrix.Core/Python/MajorMinorVersion.cs diff --git a/StabilityMatrix.Core/Python/MajorMinorVersion.cs b/StabilityMatrix.Core/Python/MajorMinorVersion.cs new file mode 100644 index 000000000..79b732338 --- /dev/null +++ b/StabilityMatrix.Core/Python/MajorMinorVersion.cs @@ -0,0 +1,3 @@ +namespace StabilityMatrix.Core.Python; + +public readonly record struct MajorMinorVersion(int Major, int Minor); diff --git a/StabilityMatrix.Core/Python/PyBaseInstall.cs b/StabilityMatrix.Core/Python/PyBaseInstall.cs index 474dba024..bb12ff5fa 100644 --- a/StabilityMatrix.Core/Python/PyBaseInstall.cs +++ b/StabilityMatrix.Core/Python/PyBaseInstall.cs @@ -6,7 +6,6 @@ using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Processes; -using MajorMinorVersion = (int Major, int Minor); namespace StabilityMatrix.Core.Python; @@ -50,7 +49,7 @@ public class PyBaseInstall(DirectoryPath rootPath, MajorMinorVersion? version = (PlatformKind.MacOS, RootPath.JoinFile("lib", "tcl8.6")) ); - public static PyBaseInstall Default { get; } = new(PyRunner.PythonDir, (3, 10)); + public static PyBaseInstall Default { get; } = new(PyRunner.PythonDir, new MajorMinorVersion(3, 10)); // Attempt to find the major and minor version of the Python installation. private static MajorMinorVersion FindPythonVersion( @@ -105,7 +104,7 @@ private static MajorMinorVersion FindPythonVersion( ); } - return (int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value)); + return new(int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value)); } /// From fff09486019edd4c90bc330b796690c96dbe9740 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 27 Jun 2024 03:28:21 -0400 Subject: [PATCH 044/325] Fix chagenlog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adbec4967..d41b62f5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,10 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Disable Update Check" option to the package card overflow menu, allowing you to disable update checks for a specific package ## v2.11.4 +### Changed +- Base Python install will now use `setuptools==69.5.1` for compatibility with `torchsde`. Individual Packages can upgrade as required. ### Fixed - Fixed [#719](https://github.com/LykosAI/StabilityMatrix/issues/719) - Fix comments in Inference prompt not being ignored -- Fixed pip requirement syntax for base Python install and override in Fooocus package, should fix issues with `torchsde` install in Fooocus ### Supporters #### Visionaries - Huge thanks to our Visionary-tier supporters on Patreon, **Scopp Mcdee** and **Waterclouds**! Your support helps us continue to improve Stability Matrix! From d51eba590ed3bf0667028e4dce3c0257a163e72b Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 27 Jun 2024 18:59:10 -0700 Subject: [PATCH 045/325] Show warning if the user hasn't extracted the app (or selected Temp dir for some weird reason) --- .../Languages/Resources.Designer.cs | 9 +++++++++ StabilityMatrix.Avalonia/Languages/Resources.resx | 3 +++ .../ViewModels/Dialogs/SelectDataDirectoryViewModel.cs | 10 ++++++++++ .../Views/Dialogs/SelectDataDirectoryDialog.axaml | 9 +++++++++ 4 files changed, 31 insertions(+) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index c8d5754d6..3a3e120cc 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -3082,5 +3082,14 @@ public static string TextTemplate_UpdatingPackage { return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); } } + + /// + /// Looks up a localized string similar to PLEASE EXTRACT THE APP FROM THE ZIP FILE BEFORE RUNNING STABILITY MATRIX. + /// + public static string Warning_PleaseExtractFirst { + get { + return ResourceManager.GetString("Warning_PleaseExtractFirst", resourceCulture); + } + } } } diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index a9b90c3e9..71b30a70d 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1125,4 +1125,7 @@ Disable Update Check + + PLEASE EXTRACT THE APP FROM THE ZIP FILE BEFORE RUNNING STABILITY MATRIX + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs index e882049cf..32201b906 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs @@ -41,6 +41,7 @@ public partial class SelectDataDirectoryViewModel : ContentDialogViewModelBase private const string FatWarningText = "FAT32 / exFAT drives are not supported at this time"; [ObservableProperty] + [NotifyPropertyChangedFor(nameof(IsInTempFolder))] private string dataDirectory = DefaultInstallLocation; [ObservableProperty] @@ -58,6 +59,12 @@ public partial class SelectDataDirectoryViewModel : ContentDialogViewModelBase [ObservableProperty] private bool showFatWarning; + public bool IsInTempFolder => + DataDirectory.StartsWith( + Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar), + StringComparison.OrdinalIgnoreCase + ); + public RefreshBadgeViewModel ValidatorRefreshBadge { get; } = new() { @@ -89,6 +96,9 @@ private async Task ValidateDataDirectory() ShowFatWarning = IsDriveFat(DataDirectory); + if (IsInTempFolder) + return false; + // Doesn't exist, this is fine as a new install, hide badge if (!Directory.Exists(DataDirectory)) { diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml index 48f6a18e6..f85faaade 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml @@ -73,6 +73,15 @@ IsVisible="{Binding ShowFatWarning}" FontSize="14" Margin="0,8,0,0" /> + + From 7aa0e13408b1a8011404fe7fe225ac3c01c1d854 Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 27 Jun 2024 21:30:01 -0700 Subject: [PATCH 046/325] fix cancel button & check AppCurrentDir instead --- .../ViewModels/Dialogs/SelectDataDirectoryViewModel.cs | 10 ++++++---- .../Views/Dialogs/SelectDataDirectoryDialog.axaml | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs index 32201b906..c43b883ea 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs @@ -60,10 +60,12 @@ public partial class SelectDataDirectoryViewModel : ContentDialogViewModelBase private bool showFatWarning; public bool IsInTempFolder => - DataDirectory.StartsWith( - Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar), - StringComparison.OrdinalIgnoreCase - ); + Compat + .AppCurrentDir.ToString() + .StartsWith( + Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar), + StringComparison.OrdinalIgnoreCase + ); public RefreshBadgeViewModel ValidatorRefreshBadge { get; } = new() diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml index f85faaade..7260fb4ee 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/SelectDataDirectoryDialog.axaml @@ -121,7 +121,6 @@ Command="{Binding OnCloseButtonClick}" FontSize="16" HorizontalAlignment="Center" - IsEnabled="{Binding IsDirectoryValid}" Padding="16,8" /> private void UpdateMainCanvasBounds() { - if ( - MainCanvas is null - || DataContext is not PaintCanvasViewModel { BackgroundImage: { } backgroundBitmap } - ) + if (MainCanvas is null || DataContext is not PaintCanvasViewModel vm) { return; } + var canvasSize = vm.CanvasSize; + // Set size if mismatch if ( - Math.Abs(MainCanvas.Width - backgroundBitmap.Width) > 0.1 - || Math.Abs(MainCanvas.Height - backgroundBitmap.Height) > 0.1 + ((int)Math.Round(MainCanvas.Width) != canvasSize.Width) + || ((int)Math.Round(MainCanvas.Height) != canvasSize.Height) ) { - MainCanvas.Width = backgroundBitmap.Width; - MainCanvas.Height = backgroundBitmap.Height; + MainCanvas.Width = vm.CanvasSize.Width; + MainCanvas.Height = vm.CanvasSize.Height; MainCanvas.InvalidateVisual(); } } From 495a43edb0a774e302d145ba24c399a3435059be Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 10:49:47 -0700 Subject: [PATCH 082/325] Fix forge & update invoke dependencies --- CHANGELOG.md | 2 ++ StabilityMatrix.Core/Models/Packages/InvokeAI.cs | 8 ++++---- StabilityMatrix.Core/Models/Packages/SDWebForge.cs | 5 ----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6dd6f5f9..3f3ace7ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.11.5 ### Fixed - Fixed `TaskCanceledException` when adding CivitAI Api key or searching for models when the API takes too long to respond. Retry and timeout behavior has been improved. +- Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge +- Fixed incorrect torch versions being installed for InvokeAI ## v2.11.4 ### Changed diff --git a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs index 33fd6aba7..7e155c056 100644 --- a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs +++ b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs @@ -199,9 +199,9 @@ await SetupAndBuildInvokeFrontend( await venvRunner .PipInstall( new PipInstallArgs(args.Any() ? args.ToArray() : Array.Empty()) - .WithTorch("==2.2.1") - .WithTorchVision("==0.17.1") - .WithXFormers("==0.0.25") + .WithTorch("==2.2.2") + .WithTorchVision("==0.17.2") + .WithXFormers("==0.0.25.post1") .WithTorchExtraIndex("cu121"), onConsoleOutput ) @@ -250,7 +250,7 @@ private async Task SetupAndBuildInvokeFrontend( { await PrerequisiteHelper.InstallNodeIfNecessary(progress).ConfigureAwait(false); await PrerequisiteHelper - .RunNpm(["i", "pnpm"], installLocation, envVars: envVars) + .RunNpm(["i", "pnpm@8"], installLocation, envVars: envVars) .ConfigureAwait(false); if (Compat.IsMacOS || Compat.IsLinux) diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index cde7f3013..4f1314eb3 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -163,11 +163,6 @@ public override async Task InstallPackage( var requirements = new FilePath(installLocation, "requirements_versions.txt"); var requirementsContent = await requirements.ReadAllTextAsync().ConfigureAwait(false); - if (!requirementsContent.Contains("pydantic")) - { - requirementsContent += "pydantic==1.10.15"; - await requirements.WriteAllTextAsync(requirementsContent).ConfigureAwait(false); - } var pipArgs = new PipInstallArgs("setuptools==69.5.1"); if (torchVersion is TorchVersion.DirectMl) From a64f0b6ca55feb1380d4db1cef37ec464560e674 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 10:52:27 -0700 Subject: [PATCH 083/325] chagenlog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f3ace7ef..a3f70b1cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,11 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed `TaskCanceledException` when adding CivitAI Api key or searching for models when the API takes too long to respond. Retry and timeout behavior has been improved. - Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge - Fixed incorrect torch versions being installed for InvokeAI - +### Supporters +#### Visionaries +- Shoutout to our Visionary-tier Patreon supporters, **Scopp Mcdee**, **Waterclouds**, and our newest Visionary, **Akiro_Senkai**! Many thanks for your generous support! +#### Pioneers +- Many thanks to our Pioneer-tier supporters on Patreon, **tankfox**, **tanangular**, and our newest Pioneers, **Mr. Unknown** and **Szir777**! Your support is greatly appreciated! ## v2.11.4 ### Changed - Base Python install will now use `setuptools==69.5.1` for compatibility with `torchsde`. Individual Packages can upgrade as required. From d30bf9adb16cc05a48c746bcf9c991af20ce36d6 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 18:55:34 -0700 Subject: [PATCH 084/325] Add FaceDetailer to inference, fix scrollviewer scrolling on focus change, and fix duplicate custom node installs --- StabilityMatrix.Avalonia/App.axaml | 4 + .../Assets/hf-packages.json | 110 +++++ .../Controls/Inference/FaceDetailerCard.axaml | 377 ++++++++++++++++++ .../Inference/FaceDetailerCard.axaml.cs | 7 + .../Controls/Scroll/BetterScrollViewer.axaml | 1 + .../DesignData/MockInferenceClientManager.cs | 6 + .../HuggingFace/HuggingFaceModelType.cs | 8 + .../Models/Inference/IValidatableModule.cs | 8 + .../Services/IInferenceClientManager.cs | 2 + .../Services/InferenceClientManager.cs | 78 ++++ .../Base/InferenceGenerationViewModelBase.cs | 4 +- .../ViewModels/Base/LoadableViewModelBase.cs | 2 + .../Inference/FaceDetailerViewModel.cs | 141 +++++++ .../InferenceTextToImageViewModel.cs | 17 +- .../Inference/Modules/FaceDetailerModule.cs | 176 ++++++++ .../Extensions/StringExtensions.cs | 14 +- StabilityMatrix.Core/Helper/SharedFolders.cs | 11 + .../Api/Comfy/NodeTypes/NodeConnections.cs | 6 + .../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 98 +++++ .../Api/Comfy/Nodes/ComfyTypedNodeBase.cs | 51 +++ .../Models/Api/Comfy/Nodes/NamedComfyNode.cs | 29 ++ .../Models/HybridModelFile.cs | 5 +- .../Models/Packages/ComfyUI.cs | 75 ++-- .../Models/SharedFolderType.cs | 5 +- 24 files changed, 1196 insertions(+), 39 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml create mode 100644 StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml.cs create mode 100644 StabilityMatrix.Avalonia/Models/Inference/IValidatableModule.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index 345e026d3..045e15f93 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -76,6 +76,7 @@ + @@ -90,5 +91,8 @@ + diff --git a/StabilityMatrix.Avalonia/Assets/hf-packages.json b/StabilityMatrix.Avalonia/Assets/hf-packages.json index 6bbeecbbc..611a3af8d 100644 --- a/StabilityMatrix.Avalonia/Assets/hf-packages.json +++ b/StabilityMatrix.Avalonia/Assets/hf-packages.json @@ -825,5 +825,115 @@ "thibaud_xl_openpose.safetensors" ], "LicenseType": "Unknown" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8m (Face)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "face_yolov8m.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8n (Face)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "face_yolov8n.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8n v2 (Face)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "face_yolov8n_v2.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8s (Face)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "face_yolov8s.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv9c (Face)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "face_yolov9c.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8n (Hand)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "hand_yolov8n.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8s (Hand)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "hand_yolov8s.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv9c (Hand)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "hand_yolov9c.pt" + ], + "Subfolder": "bbox", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8m-seg (Person)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "person_yolov8m-seg.pt" + ], + "Subfolder": "segm", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8n-seg (Person)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "person_yolov8n-seg.pt" + ], + "Subfolder": "segm", + "LicenseType": "Apache 2.0" + }, + { + "ModelCategory": "Ultralytics", + "ModelName": "YOLOv8s-seg (Person)", + "RepositoryPath": "Bingsu/adetailer", + "Files": [ + "person_yolov8s-seg.pt" + ], + "Subfolder": "segm", + "LicenseType": "Apache 2.0" } ] diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml new file mode 100644 index 000000000..31a9c8f7d --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml @@ -0,0 +1,377 @@ + + + + + + + diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml.cs new file mode 100644 index 000000000..a9beb0901 --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml.cs @@ -0,0 +1,7 @@ +using Avalonia.Controls.Primitives; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Controls; + +[Transient] +public class FaceDetailerCard : TemplatedControl { } diff --git a/StabilityMatrix.Avalonia/Controls/Scroll/BetterScrollViewer.axaml b/StabilityMatrix.Avalonia/Controls/Scroll/BetterScrollViewer.axaml index 48f59f053..405cbac37 100644 --- a/StabilityMatrix.Avalonia/Controls/Scroll/BetterScrollViewer.axaml +++ b/StabilityMatrix.Avalonia/Controls/Scroll/BetterScrollViewer.axaml @@ -20,6 +20,7 @@ + diff --git a/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs b/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs index 65abc05c5..79449aef9 100644 --- a/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs @@ -47,6 +47,12 @@ public partial class MockInferenceClientManager : ObservableObject, IInferenceCl public IObservableCollection Preprocessors { get; } = new ObservableCollectionExtended(ComfyAuxPreprocessor.Defaults); + public IObservableCollection UltralyticsModels { get; } = + new ObservableCollectionExtended(); + + public IObservableCollection SamModels { get; } = + new ObservableCollectionExtended(); + [ObservableProperty] [NotifyPropertyChangedFor(nameof(CanUserConnect))] private bool isConnected; diff --git a/StabilityMatrix.Avalonia/Models/HuggingFace/HuggingFaceModelType.cs b/StabilityMatrix.Avalonia/Models/HuggingFace/HuggingFaceModelType.cs index e816a7d75..4085d5df3 100644 --- a/StabilityMatrix.Avalonia/Models/HuggingFace/HuggingFaceModelType.cs +++ b/StabilityMatrix.Avalonia/Models/HuggingFace/HuggingFaceModelType.cs @@ -47,4 +47,12 @@ public enum HuggingFaceModelType [Description("T2I Adapters (Diffusers)")] [ConvertTo(SharedFolderType.T2IAdapter)] DiffusersT2IAdapter, + + [Description("Ultralytics/Segmentation Models")] + [ConvertTo(SharedFolderType.Ultralytics)] + Ultralytics, + + [Description("SAM Models")] + [ConvertTo(SharedFolderType.Sams)] + Sams, } diff --git a/StabilityMatrix.Avalonia/Models/Inference/IValidatableModule.cs b/StabilityMatrix.Avalonia/Models/Inference/IValidatableModule.cs new file mode 100644 index 000000000..871c75073 --- /dev/null +++ b/StabilityMatrix.Avalonia/Models/Inference/IValidatableModule.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace StabilityMatrix.Avalonia.Models.Inference; + +public interface IValidatableModule +{ + public Task Validate(); +} diff --git a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs index d33f93b5a..8dfd8fa0c 100644 --- a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs @@ -46,6 +46,8 @@ public interface IInferenceClientManager : IDisposable, INotifyPropertyChanged, IObservableCollection Upscalers { get; } IObservableCollection Schedulers { get; } IObservableCollection Preprocessors { get; } + IObservableCollection UltralyticsModels { get; } + IObservableCollection SamModels { get; } Task CopyImageToInputAsync(FilePath imageFile, CancellationToken cancellationToken = default); diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index 1909aee27..e839a7ffb 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -115,6 +116,16 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache preprocessorsSource = new(p => p.Value); + public IObservableCollection UltralyticsModels { get; } = + new ObservableCollectionExtended(); + + private readonly SourceCache ultralyticsModelsSource = new(p => p.GetId()); + + public IObservableCollection SamModels { get; } = + new ObservableCollectionExtended(); + + private readonly SourceCache samModelsSource = new(p => p.GetId()); + public InferenceClientManager( ILogger logger, IApiFactory apiFactory, @@ -175,6 +186,28 @@ ICompletionProvider completionProvider .Bind(PromptExpansionModels) .Subscribe(); + ultralyticsModelsSource + .Connect() + .Sort( + SortExpressionComparer + .Ascending(f => f.Type) + .ThenByAscending(f => f.ShortDisplayName) + ) + .DeferUntilLoaded() + .Bind(UltralyticsModels) + .Subscribe(); + + samModelsSource + .Connect() + .Sort( + SortExpressionComparer + .Ascending(f => f.Type) + .ThenByAscending(f => f.ShortDisplayName) + ) + .DeferUntilLoaded() + .Bind(SamModels) + .Subscribe(); + vaeModelsDefaults.AddOrUpdate(HybridModelFile.Default); vaeModelsDefaults.Connect().Or(vaeModelsSource.Connect()).Bind(VaeModels).Subscribe(); @@ -255,6 +288,31 @@ await Client.GetNodeOptionNamesAsync("ControlNetLoader", "control_net_name") is ); } + // Get Ultralytics model names + if ( + await Client.GetNodeOptionNamesAsync("UltralyticsDetectorProvider", "model_name") is + { } ultralyticsModelNames + ) + { + IEnumerable models = + [ + HybridModelFile.None, + ..ultralyticsModelNames.Select(HybridModelFile.FromRemote) + ]; + ultralyticsModelsSource.EditDiff(models, HybridModelFile.Comparer); + } + + // Get SAM model names + if (await Client.GetNodeOptionNamesAsync("SAMLoader", "model_name") is { } samModelNames) + { + IEnumerable models = + [ + HybridModelFile.None, + ..samModelNames.Select(HybridModelFile.FromRemote) + ]; + samModelsSource.EditDiff(models, HybridModelFile.Comparer); + } + // Prompt Expansion indexing is local only // Fetch sampler names from KSampler node @@ -372,6 +430,26 @@ private void ResetSharedProperties() HybridModelFile.Comparer ); + // Load Ultralytics models + IEnumerable ultralyticsModels = + [ + HybridModelFile.None, + ..modelIndexService + .FindByModelType(SharedFolderType.Ultralytics) + .Select(HybridModelFile.FromLocal) + ]; + ultralyticsModelsSource.EditDiff(ultralyticsModels, HybridModelFile.Comparer); + + // Load SAM models + IEnumerable samModels = + [ + HybridModelFile.None, + ..modelIndexService + .FindByModelType(SharedFolderType.Sams) + .Select(HybridModelFile.FromLocal) + ]; + samModelsSource.EditDiff(samModels, HybridModelFile.Comparer); + samplersSource.EditDiff(ComfySampler.Defaults, ComfySampler.Comparer); latentUpscalersSource.EditDiff(ComfyUpscaler.Defaults, ComfyUpscaler.Comparer); diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs index 774e97a70..817cbdfa2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs @@ -656,7 +656,9 @@ private async Task CheckPromptExtensionsInstalled(NodeDictionary nodeDicti { // Get prompt required extensions // Just static for now but could do manifest lookup when we support custom workflows - var requiredExtensionSpecifiers = nodeDictionary.RequiredExtensions.ToList(); + var requiredExtensionSpecifiers = nodeDictionary + .RequiredExtensions.DistinctBy(ext => ext.Name) + .ToList(); // Skip if no extensions required if (requiredExtensionSpecifiers.Count == 0) diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs index cc8893f5e..6c4f4da6e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs @@ -23,6 +23,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base; [JsonDerivedType(typeof(PromptExpansionCardViewModel), PromptExpansionCardViewModel.ModuleKey)] [JsonDerivedType(typeof(ExtraNetworkCardViewModel), ExtraNetworkCardViewModel.ModuleKey)] [JsonDerivedType(typeof(LayerDiffuseCardViewModel), LayerDiffuseCardViewModel.ModuleKey)] +[JsonDerivedType(typeof(FaceDetailerViewModel), FaceDetailerViewModel.ModuleKey)] [JsonDerivedType(typeof(FreeUModule))] [JsonDerivedType(typeof(HiresFixModule))] [JsonDerivedType(typeof(UpscalerModule))] @@ -31,6 +32,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base; [JsonDerivedType(typeof(PromptExpansionModule))] [JsonDerivedType(typeof(LoraModule))] [JsonDerivedType(typeof(LayerDiffuseModule))] +[JsonDerivedType(typeof(FaceDetailerModule))] public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs new file mode 100644 index 000000000..2757e0822 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs @@ -0,0 +1,141 @@ +using System.Collections.ObjectModel; +using System.Text.Json.Serialization; +using CommunityToolkit.Mvvm.ComponentModel; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api.Comfy; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference; + +[View(typeof(FaceDetailerCard))] +[ManagedService] +[Transient] +public partial class FaceDetailerViewModel : LoadableViewModelBase +{ + public const string ModuleKey = "FaceDetailer"; + + [ObservableProperty] + private bool guideSizeFor = true; + + [ObservableProperty] + private int guideSize = 256; + + [ObservableProperty] + private int maxSize = 768; + + [ObservableProperty] + private int steps = 20; + + [ObservableProperty] + private double cfg = 8; + + [ObservableProperty] + private ComfySampler? sampler = ComfySampler.Euler; + + [ObservableProperty] + private ComfyScheduler? scheduler = ComfyScheduler.Normal; + + [ObservableProperty] + private double denoise = 0.5d; + + [ObservableProperty] + private int feather = 5; + + [ObservableProperty] + private bool noiseMask = true; + + [ObservableProperty] + private bool forceInpaint = false; + + [ObservableProperty] + private double bboxThreshold = 0.5d; + + [ObservableProperty] + private int bboxDilation = 10; + + [ObservableProperty] + private int bboxCropFactor = 3; + + [ObservableProperty] + private string samDetectionHint = "center-1"; + + [ObservableProperty] + private int samDilation = 0; + + [ObservableProperty] + private double samThreshold = 0.93d; + + [ObservableProperty] + private int samBboxExpansion = 0; + + [ObservableProperty] + private double samMaskHintThreshold = 0.7d; + + [ObservableProperty] + private string samMaskHintUseNegative = "False"; + + [ObservableProperty] + private int dropSize = 10; + + [ObservableProperty] + private int cycle = 1; + + [ObservableProperty] + private HybridModelFile? bboxModel; + + [ObservableProperty] + private HybridModelFile? segmModel; + + [ObservableProperty] + private HybridModelFile? samModel; + + [ObservableProperty] + private bool showSamModelSelector = true; + + [ObservableProperty] + private bool useSeparatePrompt; + + [ObservableProperty] + private string positivePrompt = string.Empty; + + [ObservableProperty] + private string negativePrompt = string.Empty; + + /// + public FaceDetailerViewModel( + IInferenceClientManager clientManager, + ServiceManager vmFactory + ) + { + ClientManager = clientManager; + SeedCardViewModel = vmFactory.Get(); + SeedCardViewModel.GenerateNewSeed(); + PromptCardViewModel = vmFactory.Get(); + } + + [JsonPropertyName("DetailerSeed")] + public SeedCardViewModel SeedCardViewModel { get; } + + [JsonPropertyName("DetailerPrompt")] + public PromptCardViewModel PromptCardViewModel { get; } + + public ObservableCollection SamDetectionHints { get; set; } = + [ + "center-1", + "horizontal-2", + "vertical-2", + "rect-4", + "diamond-4", + "mask-area", + "mask-points", + "mask-point-bbox", + "none" + ]; + + public ObservableCollection SamMaskHintUseNegatives { get; set; } = ["False", "Small", "Outter"]; + + public IInferenceClientManager ClientManager { get; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 04e46f059..405d08464 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -92,7 +92,8 @@ RunningPackageService runningPackageService { typeof(HiresFixModule), typeof(UpscalerModule), - typeof(SaveImageModule) + typeof(SaveImageModule), + typeof(FaceDetailerModule) }; modulesCard.DefaultModules = new[] { typeof(HiresFixModule), typeof(UpscalerModule) }; modulesCard.InitializeDefaults(); @@ -190,6 +191,20 @@ CancellationToken cancellationToken if (!await ModelCardViewModel.ValidateModel()) return; + foreach (var module in ModulesCardViewModel.Cards.OfType()) + { + if (!module.IsEnabled) + continue; + + if (module is not IValidatableModule validatableModule) + continue; + + if (!await validatableModule.Validate()) + { + return; + } + } + if (!await CheckClientConnectedWithPrompt() || !ClientManager.IsConnected) return; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs new file mode 100644 index 000000000..9b80df42c --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs @@ -0,0 +1,176 @@ +using System; +using System.Threading.Tasks; +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api.Comfy.Nodes; +using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules; + +[ManagedService] +[Transient] +public class FaceDetailerModule : ModuleBase, IValidatableModule +{ + public FaceDetailerModule(ServiceManager vmFactory) + : base(vmFactory) + { + Title = "Face Detailer"; + AddCards(vmFactory.Get()); + } + + protected override void OnApplyStep(ModuleApplyStepEventArgs e) + { + var faceDetailerCard = GetCard(); + + var bboxLoader = new ComfyNodeBuilder.UltralyticsDetectorProvider + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.UltralyticsDetectorProvider)), + ModelName = + GetModelName(faceDetailerCard.BboxModel) ?? throw new ArgumentException("No BboxModel"), + }; + + var faceDetailer = new ComfyNodeBuilder.FaceDetailer + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.FaceDetailer)), + GuideSize = faceDetailerCard.GuideSize, + GuideSizeFor = faceDetailerCard.GuideSizeFor, + MaxSize = faceDetailerCard.MaxSize, + Seed = faceDetailerCard.SeedCardViewModel.Seed, + Steps = faceDetailerCard.Steps, + Cfg = faceDetailerCard.Cfg, + SamplerName = + faceDetailerCard.Sampler?.Name + ?? e.Builder.Connections.PrimarySampler?.Name + ?? throw new ArgumentException("No PrimarySampler"), + Scheduler = + faceDetailerCard.Scheduler?.Name + ?? e.Builder.Connections.PrimaryScheduler?.Name + ?? throw new ArgumentException("No PrimaryScheduler"), + Denoise = faceDetailerCard.Denoise, + Feather = faceDetailerCard.Feather, + NoiseMask = faceDetailerCard.NoiseMask, + ForceInpaint = faceDetailerCard.ForceInpaint, + BboxThreshold = faceDetailerCard.BboxThreshold, + BboxDilation = faceDetailerCard.BboxDilation, + BboxCropFactor = faceDetailerCard.BboxCropFactor, + SamDetectionHint = faceDetailerCard.SamDetectionHint, + SamDilation = faceDetailerCard.SamDilation, + SamThreshold = faceDetailerCard.SamThreshold, + SamBboxExpansion = faceDetailerCard.SamBboxExpansion, + SamMaskHintThreshold = faceDetailerCard.SamMaskHintThreshold, + SamMaskHintUseNegative = faceDetailerCard.SamMaskHintUseNegative, + DropSize = faceDetailerCard.DropSize, + Cycle = faceDetailerCard.Cycle, + Image = e.Builder.GetPrimaryAsImage(), + Model = e.Builder.Connections.GetRefinerOrBaseModel(), + Clip = e.Builder.Connections.Base.Clip ?? throw new ArgumentException("No BaseClip"), + Vae = e.Builder.Connections.GetDefaultVAE(), + Positive = GetPositiveConditioning(faceDetailerCard, e), + Negative = GetNegativeConditioning(faceDetailerCard, e), + BboxDetector = e.Nodes.AddTypedNode(bboxLoader).Output1, + Wildcard = new StringNodeConnection() // TODO put + }; + + var segmModelName = GetModelName(faceDetailerCard.SegmModel); + if (!string.IsNullOrWhiteSpace(segmModelName)) + { + var segmLoader = new ComfyNodeBuilder.UltralyticsDetectorProvider + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.UltralyticsDetectorProvider)), + ModelName = segmModelName + }; + faceDetailer.SegmDetectorOpt = e.Nodes.AddTypedNode(segmLoader).Output2; + } + + var samModelName = GetModelName(faceDetailerCard.SamModel); + if (!string.IsNullOrWhiteSpace(samModelName)) + { + var samLoader = new ComfyNodeBuilder.SamLoader + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.SamLoader)), + ModelName = samModelName, + DeviceMode = "AUTO", + }; + faceDetailer.SamModelOpt = e.Nodes.AddTypedNode(samLoader).Output; + } + + e.Builder.Connections.Primary = e.Nodes.AddTypedNode(faceDetailer).Output; + } + + private string? GetModelName(HybridModelFile? model) => + model switch + { + null => null, + { FileName: "@none" } => null, + { RemoteName: "@none" } => null, + { Local: not null } => model.RelativePath.NormalizePathSeparators(), + { RemoteName: not null } => model.RemoteName, + _ => null + }; + + private ConditioningNodeConnection GetPositiveConditioning( + FaceDetailerViewModel viewModel, + ModuleApplyStepEventArgs e + ) + { + if (!viewModel.UseSeparatePrompt) + { + return e.Builder.Connections.GetRefinerOrBaseConditioning().Positive; + } + + var prompt = viewModel.PromptCardViewModel.GetPrompt(); + prompt.Process(); + var positiveClip = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.CLIPTextEncode + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.CLIPTextEncode)), + Clip = e.Builder.Connections.Base.Clip!, + Text = prompt.ProcessedText + } + ); + + return positiveClip.Output; + } + + private ConditioningNodeConnection GetNegativeConditioning( + FaceDetailerViewModel viewModel, + ModuleApplyStepEventArgs e + ) + { + if (!viewModel.UseSeparatePrompt) + { + return e.Builder.Connections.GetRefinerOrBaseConditioning().Negative; + } + + var prompt = viewModel.PromptCardViewModel.GetNegativePrompt(); + prompt.Process(); + var negativeClip = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.CLIPTextEncode + { + Name = e.Builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.CLIPTextEncode)), + Clip = e.Builder.Connections.Base.Clip!, + Text = prompt.ProcessedText + } + ); + + return negativeClip.Output; + } + + public async Task Validate() + { + var faceDetailerCard = GetCard(); + if (!string.IsNullOrWhiteSpace(GetModelName(faceDetailerCard.BboxModel))) + return true; + + var dialog = DialogHelper.CreateMarkdownDialog( + "Please select a BBox Model to continue.", + "No Model Selected" + ); + await dialog.ShowAsync(); + return false; + } +} diff --git a/StabilityMatrix.Core/Extensions/StringExtensions.cs b/StabilityMatrix.Core/Extensions/StringExtensions.cs index 88e1c6aa8..265c31552 100644 --- a/StabilityMatrix.Core/Extensions/StringExtensions.cs +++ b/StabilityMatrix.Core/Extensions/StringExtensions.cs @@ -103,11 +103,17 @@ public static string StripEnd(this string str, string subString) /// [Pure] // ReSharper disable once ReturnTypeCanBeEnumerable.Global - public static string[] SplitLines( - this string str, - StringSplitOptions options = StringSplitOptions.None - ) + public static string[] SplitLines(this string str, StringSplitOptions options = StringSplitOptions.None) { return str.Split(new[] { "\r\n", "\n" }, options); } + + /// + /// Normalizes directory separator characters in a given path + /// + [Pure] + public static string NormalizePathSeparators(this string path) + { + return path.Replace('\\', '/'); + } } diff --git a/StabilityMatrix.Core/Helper/SharedFolders.cs b/StabilityMatrix.Core/Helper/SharedFolders.cs index d6a80b679..0878308f4 100644 --- a/StabilityMatrix.Core/Helper/SharedFolders.cs +++ b/StabilityMatrix.Core/Helper/SharedFolders.cs @@ -219,8 +219,19 @@ public static void SetupSharedModelFolders(DirectoryPath rootModelsDir) var allSharedFolderTypes = Enum.GetValues(); foreach (var sharedFolder in allSharedFolderTypes) { + if (sharedFolder == SharedFolderType.Unknown) + continue; + var dir = new DirectoryPath(rootModelsDir, sharedFolder.GetStringValue()); dir.Create(); + + if (sharedFolder == SharedFolderType.Ultralytics) + { + var bboxDir = new DirectoryPath(dir, "bbox"); + var segmDir = new DirectoryPath(dir, "segm"); + bboxDir.Create(); + segmDir.Create(); + } } } } diff --git a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs index b0a1d6159..5f04a3651 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs @@ -25,3 +25,9 @@ public class SamplerNodeConnection : NodeConnectionBase; public class SigmasNodeConnection : NodeConnectionBase; public class StringNodeConnection : NodeConnectionBase; + +public class BboxDetectorNodeConnection : NodeConnectionBase; + +public class SegmDetectorNodeConnection : NodeConnectionBase; + +public class SamModelNodeConnection : NodeConnectionBase; diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index 8ec0854b2..bd5a0a9d4 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -454,6 +454,104 @@ public record LayeredDiffusionDecodeRgba : ComfyTypedNodeBase + { + public required string ModelName { get; init; } + } + + [TypedNodeOptions( + Name = "SAMLoader", + RequiredExtensions = ["https://github.com/ltdrdata/ComfyUI-Impact-Pack"] + )] + public record SamLoader : ComfyTypedNodeBase + { + public required string ModelName { get; init; } + + /// + /// options: AUTO, Prefer GPU, CPU + /// + public required string DeviceMode { get; init; } + } + + [TypedNodeOptions( + Name = "FaceDetailer", + RequiredExtensions = ["https://github.com/ltdrdata/ComfyUI-Impact-Pack"] + )] + public record FaceDetailer : ComfyTypedNodeBase + { + public required ImageNodeConnection Image { get; init; } + public required ModelNodeConnection Model { get; init; } + public required ClipNodeConnection Clip { get; init; } + public required VAENodeConnection Vae { get; init; } + public required ConditioningNodeConnection Positive { get; init; } + public required ConditioningNodeConnection Negative { get; init; } + public required BboxDetectorNodeConnection BboxDetector { get; init; } + public required double GuideSize { get; init; } = 512.0; + + /// + /// true: 'bbox' + /// false: 'crop_region' + /// + public required bool GuideSizeFor { get; init; } = true; + public required double MaxSize { get; init; } = 1024.0; + public required long Seed { get; init; } + public required int Steps { get; init; } = 20; + public required double Cfg { get; init; } = 8.0d; + public required string SamplerName { get; init; } + public required string Scheduler { get; init; } + public required double Denoise { get; init; } = 0.5d; + public required int Feather { get; init; } = 5; + public required bool NoiseMask { get; init; } = true; + public required bool ForceInpaint { get; init; } = true; + + [Range(0.0, 1.0)] + public required double BboxThreshold { get; init; } = 0.5d; + + [Range(-512, 512)] + public required int BboxDilation { get; init; } = 10; + + [Range(1.0, 10.0)] + public required double BboxCropFactor { get; init; } = 3.0d; + + /// + /// options: ["center-1", "horizontal-2", "vertical-2", "rect-4", "diamond-4", "mask-area", "mask-points", "mask-point-bbox", "none"] + /// + public required string SamDetectionHint { get; init; } + + [Range(-512, 512)] + public required int SamDilation { get; init; } + + [Range(0.0d, 1.0d)] + public required double SamThreshold { get; init; } = 0.93d; + + [Range(0, 1000)] + public required int SamBboxExpansion { get; init; } + + [Range(0.0d, 1.0d)] + public required double SamMaskHintThreshold { get; init; } = 0.7d; + + /// + /// options: ["False", "Small", "Outter"] + /// + public required string SamMaskHintUseNegative { get; init; } = "False"; + + public required StringNodeConnection Wildcard { get; init; } + + [Range(1, 32768)] + public required int DropSize { get; init; } = 10; + + [Range(1, 10)] + public required int Cycle { get; init; } = 1; + + public SamModelNodeConnection? SamModelOpt { get; set; } + public SegmDetectorNodeConnection? SegmDetectorOpt { get; set; } + } + public ImageNodeConnection Lambda_LatentToImage(LatentNodeConnection latent, VAENodeConnection vae) { var name = GetUniqueName("VAEDecode"); diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyTypedNodeBase.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyTypedNodeBase.cs index 5dc591de7..8b32fc6d3 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyTypedNodeBase.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyTypedNodeBase.cs @@ -132,3 +132,54 @@ public static implicit operator NamedComfyNode( ComfyTypedNodeBase node ) => (NamedComfyNode)node.ToNamedNode(); } + +public abstract record ComfyTypedNodeBase : ComfyTypedNodeBase + where TOutput1 : NodeConnectionBase, new() + where TOutput2 : NodeConnectionBase, new() + where TOutput3 : NodeConnectionBase, new() + where TOutput4 : NodeConnectionBase, new() +{ + [JsonIgnore] + public TOutput1 Output1 => new() { Data = new object[] { Name, 0 } }; + + [JsonIgnore] + public TOutput2 Output2 => new() { Data = new object[] { Name, 1 } }; + + [JsonIgnore] + public TOutput3 Output3 => new() { Data = new object[] { Name, 2 } }; + + [JsonIgnore] + public TOutput4 Output4 => new() { Data = new object[] { Name, 3 } }; + + public static implicit operator NamedComfyNode( + ComfyTypedNodeBase node + ) => (NamedComfyNode)node.ToNamedNode(); +} + +public abstract record ComfyTypedNodeBase + : ComfyTypedNodeBase + where TOutput1 : NodeConnectionBase, new() + where TOutput2 : NodeConnectionBase, new() + where TOutput3 : NodeConnectionBase, new() + where TOutput4 : NodeConnectionBase, new() + where TOutput5 : NodeConnectionBase, new() +{ + [JsonIgnore] + public TOutput1 Output1 => new() { Data = new object[] { Name, 0 } }; + + [JsonIgnore] + public TOutput2 Output2 => new() { Data = new object[] { Name, 1 } }; + + [JsonIgnore] + public TOutput3 Output3 => new() { Data = new object[] { Name, 2 } }; + + [JsonIgnore] + public TOutput4 Output4 => new() { Data = new object[] { Name, 3 } }; + + [JsonIgnore] + public TOutput5 Output5 => new() { Data = new object[] { Name, 4 } }; + + public static implicit operator NamedComfyNode( + ComfyTypedNodeBase node + ) => (NamedComfyNode)node.ToNamedNode(); +} diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/NamedComfyNode.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/NamedComfyNode.cs index d50f6eaf1..d5dff7517 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/NamedComfyNode.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/NamedComfyNode.cs @@ -53,3 +53,32 @@ public record NamedComfyNode(string Name) : NamedC public TOutput3 Output3 => new() { Data = GetOutput(2) }; } + +[JsonSerializable(typeof(NamedComfyNode<>))] +public record NamedComfyNode(string Name) : NamedComfyNode(Name) + where TOutput1 : NodeConnectionBase, new() + where TOutput2 : NodeConnectionBase, new() + where TOutput3 : NodeConnectionBase, new() + where TOutput4 : NodeConnectionBase, new() +{ + public TOutput1 Output1 => new() { Data = GetOutput(0) }; + public TOutput2 Output2 => new() { Data = GetOutput(1) }; + public TOutput3 Output3 => new() { Data = GetOutput(2) }; + public TOutput4 Output4 => new() { Data = GetOutput(3) }; +} + +[JsonSerializable(typeof(NamedComfyNode<>))] +public record NamedComfyNode(string Name) + : NamedComfyNode(Name) + where TOutput1 : NodeConnectionBase, new() + where TOutput2 : NodeConnectionBase, new() + where TOutput3 : NodeConnectionBase, new() + where TOutput4 : NodeConnectionBase, new() + where TOutput5 : NodeConnectionBase, new() +{ + public TOutput1 Output1 => new() { Data = GetOutput(0) }; + public TOutput2 Output2 => new() { Data = GetOutput(1) }; + public TOutput3 Output3 => new() { Data = GetOutput(2) }; + public TOutput4 Output4 => new() { Data = GetOutput(3) }; + public TOutput5 Output5 => new() { Data = GetOutput(4) }; +} diff --git a/StabilityMatrix.Core/Models/HybridModelFile.cs b/StabilityMatrix.Core/Models/HybridModelFile.cs index 8e21cb398..ef9486586 100644 --- a/StabilityMatrix.Core/Models/HybridModelFile.cs +++ b/StabilityMatrix.Core/Models/HybridModelFile.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.Database; @@ -115,7 +116,7 @@ public static HybridModelFile FromDownloadable(RemoteResource resource) public string GetId() { - return $"{RelativePath};{IsNone};{IsDefault}"; + return $"{RelativePath.NormalizePathSeparators()};{IsNone};{IsDefault}"; } private sealed class RemoteNameLocalEqualityComparer : IEqualityComparer @@ -131,7 +132,7 @@ public bool Equals(HybridModelFile? x, HybridModelFile? y) if (x.GetType() != y.GetType()) return false; - if (!Equals(x.RelativePath, y.RelativePath)) + if (!Equals(x.RelativePath.NormalizePathSeparators(), y.RelativePath.NormalizePathSeparators())) return false; // This equality affects replacements of remote over local models diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 31917327d..8971273f3 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -51,27 +51,29 @@ IPrerequisiteHelper prerequisiteHelper public override Dictionary> SharedFolders => new() { - [SharedFolderType.StableDiffusion] = new[] { "models/checkpoints" }, - [SharedFolderType.Diffusers] = new[] { "models/diffusers" }, - [SharedFolderType.Lora] = new[] { "models/loras" }, - [SharedFolderType.CLIP] = new[] { "models/clip" }, - [SharedFolderType.InvokeClipVision] = new[] { "models/clip_vision" }, - [SharedFolderType.TextualInversion] = new[] { "models/embeddings" }, - [SharedFolderType.VAE] = new[] { "models/vae" }, - [SharedFolderType.ApproxVAE] = new[] { "models/vae_approx" }, - [SharedFolderType.ControlNet] = new[] { "models/controlnet/ControlNet" }, - [SharedFolderType.GLIGEN] = new[] { "models/gligen" }, - [SharedFolderType.ESRGAN] = new[] { "models/upscale_models" }, - [SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" }, - [SharedFolderType.IpAdapter] = new[] { "models/ipadapter/base" }, - [SharedFolderType.InvokeIpAdapters15] = new[] { "models/ipadapter/sd15" }, - [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/ipadapter/sdxl" }, - [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, - [SharedFolderType.PromptExpansion] = new[] { "models/prompt_expansion" } + [SharedFolderType.StableDiffusion] = ["models/checkpoints"], + [SharedFolderType.Diffusers] = ["models/diffusers"], + [SharedFolderType.Lora] = ["models/loras"], + [SharedFolderType.CLIP] = ["models/clip"], + [SharedFolderType.InvokeClipVision] = ["models/clip_vision"], + [SharedFolderType.TextualInversion] = ["models/embeddings"], + [SharedFolderType.VAE] = ["models/vae"], + [SharedFolderType.ApproxVAE] = ["models/vae_approx"], + [SharedFolderType.ControlNet] = ["models/controlnet/ControlNet"], + [SharedFolderType.GLIGEN] = ["models/gligen"], + [SharedFolderType.ESRGAN] = ["models/upscale_models"], + [SharedFolderType.Hypernetwork] = ["models/hypernetworks"], + [SharedFolderType.IpAdapter] = ["models/ipadapter/base"], + [SharedFolderType.InvokeIpAdapters15] = ["models/ipadapter/sd15"], + [SharedFolderType.InvokeIpAdaptersXl] = ["models/ipadapter/sdxl"], + [SharedFolderType.T2IAdapter] = ["models/controlnet/T2IAdapter"], + [SharedFolderType.PromptExpansion] = ["models/prompt_expansion"], + [SharedFolderType.Ultralytics] = ["models/ultralytics"], + [SharedFolderType.Sams] = ["models/sams"] }; public override Dictionary>? SharedOutputFolders => - new() { [SharedOutputType.Text2Img] = new[] { "output" } }; + new() { [SharedOutputType.Text2Img] = ["output"] }; public override List LaunchOptions => [ @@ -173,14 +175,7 @@ IPrerequisiteHelper prerequisiteHelper public override string MainBranch => "master"; public override IEnumerable AvailableTorchVersions => - new[] - { - TorchVersion.Cpu, - TorchVersion.Cuda, - TorchVersion.DirectMl, - TorchVersion.Rocm, - TorchVersion.Mps - }; + [TorchVersion.Cpu, TorchVersion.Cuda, TorchVersion.DirectMl, TorchVersion.Rocm, TorchVersion.Mps]; public override async Task InstallPackage( string installLocation, @@ -373,6 +368,10 @@ private async Task SetupModelFoldersConfig(DirectoryPath installDirectory) Path.Combine(modelsDir, "InvokeIpAdaptersXl") ); nodeValue.Children["prompt_expansion"] = Path.Combine(modelsDir, "PromptExpansion"); + nodeValue.Children["ultralytics"] = Path.Combine(modelsDir, "Ultralytics"); + nodeValue.Children["ultralytics_bbox"] = Path.Combine(modelsDir, "Ultralytics", "bbox"); + nodeValue.Children["ultralytics_segm"] = Path.Combine(modelsDir, "Ultralytics", "segm"); + nodeValue.Children["sams"] = Path.Combine(modelsDir, "Sams"); } else { @@ -411,7 +410,11 @@ private async Task SetupModelFoldersConfig(DirectoryPath installDirectory) Path.Combine(modelsDir, "InvokeIpAdaptersXl") ) }, - { "prompt_expansion", Path.Combine(modelsDir, "PromptExpansion") } + { "prompt_expansion", Path.Combine(modelsDir, "PromptExpansion") }, + { "ultralytics", Path.Combine(modelsDir, "Ultralytics") }, + { "ultralytics_bbox", Path.Combine(modelsDir, "Ultralytics", "bbox") }, + { "ultralytics_segm", Path.Combine(modelsDir, "Ultralytics", "segm") }, + { "sams", Path.Combine(modelsDir, "Sams") } } ); } @@ -468,9 +471,10 @@ private static async Task RemoveConfigSection(DirectoryPath installDirectory) await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false); } - public override IPackageExtensionManager ExtensionManager => new ComfyExtensionManager(this); + public override IPackageExtensionManager ExtensionManager => + new ComfyExtensionManager(this, settingsManager); - private class ComfyExtensionManager(ComfyUI package) + private class ComfyExtensionManager(ComfyUI package, ISettingsManager settingsManager) : GitPackageExtensionManager(package.PrerequisiteHelper) { public override string RelativeInstallDirectory => "custom_nodes"; @@ -631,6 +635,19 @@ await venvRunner .ConfigureAwait(false); venvRunner.WorkingDirectory = installScript.Directory; + venvRunner.UpdateEnvironmentVariables(env => + { + // set env vars for Impact Pack for Face Detailer + env = env.SetItem("COMFYUI_PATH", installedPackage.FullPath!); + + var modelPath = + installedPackage.PreferredSharedFolderMethod == SharedFolderMethod.None + ? Path.Combine(installedPackage.FullPath!, "models") + : settingsManager.ModelsDirectory; + + env = env.SetItem("COMFYUI_MODEL_PATH", modelPath); + return env; + }); venvRunner.RunDetached(["install.py"], progress.AsProcessOutputHandler()); diff --git a/StabilityMatrix.Core/Models/SharedFolderType.cs b/StabilityMatrix.Core/Models/SharedFolderType.cs index b8ee29591..8f4848f0e 100644 --- a/StabilityMatrix.Core/Models/SharedFolderType.cs +++ b/StabilityMatrix.Core/Models/SharedFolderType.cs @@ -6,7 +6,7 @@ namespace StabilityMatrix.Core.Models; [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "IdentifierTypo")] [Flags] -public enum SharedFolderType +public enum SharedFolderType : ulong { Unknown = 0, @@ -37,11 +37,12 @@ public enum SharedFolderType AfterDetailer = 1 << 21, IpAdapter = 1 << 22, T2IAdapter = 1 << 23, - InvokeIpAdapters15 = 1 << 24, InvokeIpAdaptersXl = 1 << 25, InvokeClipVision = 1 << 26, SVD = 1 << 27, + Ultralytics = 1 << 28, + Sams = 1 << 29, PromptExpansion = 1 << 30 } From 612e8e15c84499610558b4a489649c3d2853780a Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 19:19:01 -0700 Subject: [PATCH 085/325] chagenlog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f70b1cb..c83a08463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ 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.12.0-dev.2 +### Added +- Added Face Detailer module to Inference +- Added ultralytics models to HuggingFace model browser +### Fixed +- Fixed some ScrollViewers changing scroll position when focus changes +- Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge +- Fixed incorrect torch versions being installed for InvokeAI ## v2.12.0-dev.1 ### Added From ba8d6ad8dd11c93221dd8e64fd1162c40d382ed0 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 19:21:21 -0700 Subject: [PATCH 086/325] more chagenlog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38b919779..69c6e9fff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed some ScrollViewers changing scroll position when focus changes - Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge - Fixed incorrect torch versions being installed for InvokeAI +### Supporters +#### Visionaries +- A huge thank you goes out to our esteemed Visionary-tier Patreon backers: **Scopp Mcdee**, **Waterclouds**, and **Akiro_Senkai**. Your kind support means the world! ## v2.12.0-dev.1 ### Added From 1cf9bea6fa885b65dce277e5f60aabbcae10ea02 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 19:33:28 -0700 Subject: [PATCH 087/325] fix crash when not have extension --- StabilityMatrix.Avalonia/Services/InferenceClientManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index e839a7ffb..b8182e637 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -290,7 +290,7 @@ await Client.GetNodeOptionNamesAsync("ControlNetLoader", "control_net_name") is // Get Ultralytics model names if ( - await Client.GetNodeOptionNamesAsync("UltralyticsDetectorProvider", "model_name") is + await Client.GetOptionalNodeOptionNamesAsync("UltralyticsDetectorProvider", "model_name") is { } ultralyticsModelNames ) { @@ -303,7 +303,7 @@ await Client.GetNodeOptionNamesAsync("UltralyticsDetectorProvider", "model_name" } // Get SAM model names - if (await Client.GetNodeOptionNamesAsync("SAMLoader", "model_name") is { } samModelNames) + if (await Client.GetOptionalNodeOptionNamesAsync("SAMLoader", "model_name") is { } samModelNames) { IEnumerable models = [ From f2529e2509dded86c1c2a12a8c8740a44f73f27d Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 20:53:53 -0700 Subject: [PATCH 088/325] Added RemoteModels for bbox/segm/sam models --- .../Controls/Inference/FaceDetailerCard.axaml | 26 ++++- .../Inference/FaceDetailerCard.axaml.cs | 53 +++++++++- .../Services/InferenceClientManager.cs | 17 ++++ .../Dialogs/DownloadResourceViewModel.cs | 5 + .../Inference/FaceDetailerViewModel.cs | 22 +++++ StabilityMatrix.Core/Helper/RemoteModels.cs | 99 +++++++++++++++++++ .../Models/HybridModelFile.cs | 8 +- StabilityMatrix.Core/Models/RemoteResource.cs | 2 + 8 files changed, 224 insertions(+), 8 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml index 31a9c8f7d..ff3aa7528 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml @@ -7,7 +7,8 @@ xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" xmlns:vmDialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" - xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"> + xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" + xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"> @@ -17,37 +18,52 @@ - + + Theme="{StaticResource BetterComboBoxHybridModelTheme}" > + + + + + Theme="{StaticResource BetterComboBoxHybridModelTheme}"> + + + + + Theme="{StaticResource BetterComboBoxHybridModelTheme}"> + + + + 0 + && e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem + ) + { + (sender as BetterComboBox)!.SelectedItem = removedItem; + } + else + { + (sender as BetterComboBox)!.SelectedItem = null; + } + + // Show dialog to download the model + (DataContext as FaceDetailerViewModel)! + .RemoteDownloadCommand.ExecuteAsync(item) + .SafeFireAndForget(); + } + } +} diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index b8182e637..614000ab9 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -121,11 +121,16 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache ultralyticsModelsSource = new(p => p.GetId()); + private readonly SourceCache downloadableUltralyticsModelsSource = + new(p => p.GetId()); + public IObservableCollection SamModels { get; } = new ObservableCollectionExtended(); private readonly SourceCache samModelsSource = new(p => p.GetId()); + private readonly SourceCache downloadableSamModelsSource = new(p => p.GetId()); + public InferenceClientManager( ILogger logger, IApiFactory apiFactory, @@ -188,6 +193,7 @@ ICompletionProvider completionProvider ultralyticsModelsSource .Connect() + .Or(downloadableUltralyticsModelsSource.Connect()) .Sort( SortExpressionComparer .Ascending(f => f.Type) @@ -199,6 +205,7 @@ ICompletionProvider completionProvider samModelsSource .Connect() + .Or(downloadableSamModelsSource.Connect()) .Sort( SortExpressionComparer .Ascending(f => f.Type) @@ -440,6 +447,11 @@ private void ResetSharedProperties() ]; ultralyticsModelsSource.EditDiff(ultralyticsModels, HybridModelFile.Comparer); + var downloadableUltralyticsModels = RemoteModels.UltralyticsModelFiles.Where( + u => !ultralyticsModelsSource.Lookup(u.GetId()).HasValue + ); + downloadableUltralyticsModelsSource.EditDiff(downloadableUltralyticsModels, HybridModelFile.Comparer); + // Load SAM models IEnumerable samModels = [ @@ -450,6 +462,11 @@ private void ResetSharedProperties() ]; samModelsSource.EditDiff(samModels, HybridModelFile.Comparer); + var downloadableSamModels = RemoteModels.SamModelFiles.Where( + u => !samModelsSource.Lookup(u.GetId()).HasValue + ); + downloadableSamModelsSource.EditDiff(downloadableSamModels, HybridModelFile.Comparer); + samplersSource.EditDiff(ComfySampler.Defaults, ComfySampler.Comparer); latentUpscalersSource.EditDiff(ComfyUpscaler.Defaults, ComfyUpscaler.Comparer); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs index 4aa72db8e..c2d507d41 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs @@ -75,6 +75,11 @@ Resource.ContextType as SharedFolderType? sharedFolderType.GetStringValue() ); + if (Resource.RelativePath is not null) + { + modelsDir = modelsDir.JoinDir(Resource.RelativePath); + } + var download = trackedDownloadService.NewDownload( Resource.Url, modelsDir.JoinFile(Resource.FileName) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs index 2757e0822..3271746f7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs @@ -1,9 +1,13 @@ using System.Collections.ObjectModel; using System.Text.Json.Serialization; +using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy; @@ -15,6 +19,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference; [Transient] public partial class FaceDetailerViewModel : LoadableViewModelBase { + private readonly ServiceManager vmFactory; public const string ModuleKey = "FaceDetailer"; [ObservableProperty] @@ -110,6 +115,7 @@ public FaceDetailerViewModel( ServiceManager vmFactory ) { + this.vmFactory = vmFactory; ClientManager = clientManager; SeedCardViewModel = vmFactory.Get(); SeedCardViewModel.GenerateNewSeed(); @@ -138,4 +144,20 @@ ServiceManager vmFactory public ObservableCollection SamMaskHintUseNegatives { get; set; } = ["False", "Small", "Outter"]; public IInferenceClientManager ClientManager { get; } + + [RelayCommand] + private async Task RemoteDownload(HybridModelFile? modelFile) + { + if (modelFile?.DownloadableResource is not { } resource) + return; + + var confirmDialog = vmFactory.Get(); + confirmDialog.Resource = resource; + confirmDialog.FileName = modelFile.FileName; + + if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) + { + confirmDialog.StartDownload(); + } + } } diff --git a/StabilityMatrix.Core/Helper/RemoteModels.cs b/StabilityMatrix.Core/Helper/RemoteModels.cs index deed5fb17..b5e208c7b 100644 --- a/StabilityMatrix.Core/Helper/RemoteModels.cs +++ b/StabilityMatrix.Core/Helper/RemoteModels.cs @@ -194,4 +194,103 @@ private static RemoteResource ControlNetCommon(string path, string sha256) public static IEnumerable PromptExpansionModels => PromptExpansions.Select(HybridModelFile.FromDownloadable); + + private static IEnumerable UltralyticsModels => + [ + new RemoteResource + { + Url = new Uri("https://huggingface.co/Bingsu/adetailer/resolve/main/face_yolov8m.pt"), + HashSha256 = "f02b8a23e6f12bd2c1b1f6714f66f984c728fa41ed749d033e7d6dea511ef70c", + InfoUrl = new Uri("https://huggingface.co/Bingsu/adetailer"), + Author = "Bingsu", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" + ), + ContextType = SharedFolderType.Ultralytics, + RelativePath = "bbox" + }, + new RemoteResource + { + Url = new Uri("https://huggingface.co/Bingsu/adetailer/resolve/main/hand_yolov8s.pt"), + HashSha256 = "5c4faf8d17286ace2c3d3346c6d0d4a0c8d62404955263a7ae95c1dd7eb877af", + InfoUrl = new Uri("https://huggingface.co/Bingsu/adetailer"), + Author = "Bingsu", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" + ), + ContextType = SharedFolderType.Ultralytics, + RelativePath = "bbox" + }, + new RemoteResource + { + Url = new Uri("https://huggingface.co/Bingsu/adetailer/resolve/main/person_yolov8m-seg.pt"), + HashSha256 = "9d881ec50b831f546e37977081b18f4e3bf65664aec163f97a311b0955499795", + InfoUrl = new Uri("https://huggingface.co/Bingsu/adetailer"), + Author = "Bingsu", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" + ), + ContextType = SharedFolderType.Ultralytics, + RelativePath = "segm" + }, + new RemoteResource + { + Url = new Uri("https://huggingface.co/Bingsu/adetailer/resolve/main/person_yolov8s-seg.pt"), + HashSha256 = "b5684835e79fd8b805459e0f7a0f9daa437e421cb4a214fff45ec4ac61767ef9", + InfoUrl = new Uri("https://huggingface.co/Bingsu/adetailer"), + Author = "Bingsu", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" + ), + ContextType = SharedFolderType.Ultralytics, + RelativePath = "segm" + } + ]; + + public static IEnumerable UltralyticsModelFiles => + UltralyticsModels.Select(HybridModelFile.FromDownloadable); + + private static IEnumerable SamModels => + [ + new RemoteResource + { + Url = new Uri("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth"), + InfoUrl = new Uri("https://github.com/facebookresearch/segment-anything"), + Author = "Facebook Research", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://github.com/facebookresearch/segment-anything/blob/main/LICENSE" + ), + ContextType = SharedFolderType.Sams + }, + new RemoteResource + { + Url = new Uri("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth"), + InfoUrl = new Uri("https://github.com/facebookresearch/segment-anything"), + Author = "Facebook Research", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://github.com/facebookresearch/segment-anything/blob/main/LICENSE" + ), + ContextType = SharedFolderType.Sams + }, + new RemoteResource + { + Url = new Uri("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth"), + InfoUrl = new Uri("https://github.com/facebookresearch/segment-anything"), + Author = "Facebook Research", + LicenseType = "Apache 2.0", + LicenseUrl = new Uri( + "https://github.com/facebookresearch/segment-anything/blob/main/LICENSE" + ), + ContextType = SharedFolderType.Sams + } + ]; + + public static IEnumerable SamModelFiles => + SamModels.Select(HybridModelFile.FromDownloadable); } diff --git a/StabilityMatrix.Core/Models/HybridModelFile.cs b/StabilityMatrix.Core/Models/HybridModelFile.cs index ef9486586..23e16d951 100644 --- a/StabilityMatrix.Core/Models/HybridModelFile.cs +++ b/StabilityMatrix.Core/Models/HybridModelFile.cs @@ -46,7 +46,13 @@ public record HybridModelFile { HybridModelType.Local => Local!.RelativePathFromSharedFolder, HybridModelType.Remote => RemoteName!, - HybridModelType.Downloadable => DownloadableResource!.Value.FileName, + HybridModelType.Downloadable + => DownloadableResource!.Value.RelativePath == null + ? DownloadableResource!.Value.FileName + : Path.Combine( + DownloadableResource!.Value.RelativePath, + DownloadableResource!.Value.FileName + ), HybridModelType.None => throw new InvalidOperationException(), _ => throw new ArgumentOutOfRangeException() }; diff --git a/StabilityMatrix.Core/Models/RemoteResource.cs b/StabilityMatrix.Core/Models/RemoteResource.cs index 6a32ac455..e855110e0 100644 --- a/StabilityMatrix.Core/Models/RemoteResource.cs +++ b/StabilityMatrix.Core/Models/RemoteResource.cs @@ -37,4 +37,6 @@ public readonly record struct RemoteResource /// Optional relative path to extract the archive to, if AutoExtractArchive is true /// public string? ExtractRelativePath { get; init; } + + public string? RelativePath { get; init; } } From 7382fad43aef7254b29e12fc6a76e7e544416e48 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 21:39:30 -0700 Subject: [PATCH 089/325] add inheritSeed toggle to FaceDetailer --- .../Controls/Inference/FaceDetailerCard.axaml | 8 +++++++- .../ViewModels/Inference/FaceDetailerViewModel.cs | 3 +++ .../Inference/InferenceTextToImageViewModel.cs | 11 +++++++++++ .../Inference/Modules/FaceDetailerModule.cs | 4 +++- .../Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs | 2 +- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml index ff3aa7528..bc6c53921 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml @@ -132,9 +132,15 @@ + + + IsVisible="{Binding !$parent[StackPanel].((vmInference:FaceDetailerViewModel)DataContext).InheritSeed, TargetNullValue=False, FallbackValue=False}" + Margin="4,0,4,8" /> diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs index 3271746f7..6aea47c0b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs @@ -109,6 +109,9 @@ public partial class FaceDetailerViewModel : LoadableViewModelBase [ObservableProperty] private string negativePrompt = string.Empty; + [ObservableProperty] + private bool inheritSeed = true; + /// public FaceDetailerViewModel( IInferenceClientManager clientManager, diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 405d08464..9bdb4ed3e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -215,6 +215,17 @@ CancellationToken cancellationToken seedCard.GenerateNewSeed(); } + var faceDetailerCard = ModulesCardViewModel + .GetCard() + .GetCard(); + if ( + overrides is not { UseCurrentSeed: true } + && faceDetailerCard is { InheritSeed: false, SeedCardViewModel.IsRandomizeEnabled: true } + ) + { + faceDetailerCard.SeedCardViewModel.GenerateNewSeed(); + } + var batches = BatchSizeCardViewModel.BatchCount; var batchArgs = new List(); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs index 9b80df42c..aadc23c1f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs @@ -39,7 +39,9 @@ protected override void OnApplyStep(ModuleApplyStepEventArgs e) GuideSize = faceDetailerCard.GuideSize, GuideSizeFor = faceDetailerCard.GuideSizeFor, MaxSize = faceDetailerCard.MaxSize, - Seed = faceDetailerCard.SeedCardViewModel.Seed, + Seed = faceDetailerCard.InheritSeed + ? e.Builder.Connections.Seed + : Convert.ToUInt64(faceDetailerCard.SeedCardViewModel.Seed), Steps = faceDetailerCard.Steps, Cfg = faceDetailerCard.Cfg, SamplerName = diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index bd5a0a9d4..208a6337b 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -499,7 +499,7 @@ public record FaceDetailer : ComfyTypedNodeBase /// public required bool GuideSizeFor { get; init; } = true; public required double MaxSize { get; init; } = 1024.0; - public required long Seed { get; init; } + public required ulong Seed { get; init; } public required int Steps { get; init; } = 20; public required double Cfg { get; init; } = 8.0d; public required string SamplerName { get; init; } From e62748713368c2fa9ab350bb365bb90ea473ea41 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 21:49:58 -0700 Subject: [PATCH 090/325] randomize in module --- .../Inference/InferenceTextToImageViewModel.cs | 11 ----------- .../Inference/Modules/FaceDetailerModule.cs | 4 ++++ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 9bdb4ed3e..405d08464 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -215,17 +215,6 @@ CancellationToken cancellationToken seedCard.GenerateNewSeed(); } - var faceDetailerCard = ModulesCardViewModel - .GetCard() - .GetCard(); - if ( - overrides is not { UseCurrentSeed: true } - && faceDetailerCard is { InheritSeed: false, SeedCardViewModel.IsRandomizeEnabled: true } - ) - { - faceDetailerCard.SeedCardViewModel.GenerateNewSeed(); - } - var batches = BatchSizeCardViewModel.BatchCount; var batchArgs = new List(); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs index aadc23c1f..64130bd0f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FaceDetailerModule.cs @@ -25,6 +25,10 @@ public FaceDetailerModule(ServiceManager vmFactory) protected override void OnApplyStep(ModuleApplyStepEventArgs e) { var faceDetailerCard = GetCard(); + if (faceDetailerCard is { InheritSeed: false, SeedCardViewModel.IsRandomizeEnabled: true }) + { + faceDetailerCard.SeedCardViewModel.GenerateNewSeed(); + } var bboxLoader = new ComfyNodeBuilder.UltralyticsDetectorProvider { From 48b77938483c9d82f7e160d9388514e62c2350f5 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 23:22:37 -0700 Subject: [PATCH 091/325] Add min/max/smallchange values for FaceDetailer params --- .../Controls/Inference/FaceDetailerCard.axaml | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml index bc6c53921..4bbbbb21a 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml @@ -163,7 +163,7 @@ Value="{Binding GuideSize}" Margin="4,4,4,4" Minimum="64" - SmallChange="128" + SmallChange="64" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -178,7 +178,7 @@ Value="{Binding MaxSize}" Margin="4,4,4,4" Minimum="64" - SmallChange="128" + SmallChange="64" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -192,6 +192,10 @@ Grid.Column="1" Value="{Binding BboxThreshold}" Margin="4,4,4,4" + Minimum="0" + Maximum="1" + SmallChange="0.01" + SimpleNumberFormat="F2" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -205,6 +209,9 @@ Grid.Column="1" Value="{Binding BboxDilation}" Margin="4,4,4,4" + Minimum="-512" + Maximum="512" + SmallChange="1" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -218,6 +225,10 @@ Grid.Column="1" Value="{Binding BboxCropFactor}" Margin="4,4,4,4" + SimpleNumberFormat="F2" + Minimum="1" + Maximum="10" + SmallChange="0.1" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -263,6 +274,10 @@ Grid.Column="1" Value="{Binding Denoise}" Margin="4,4,4,4" + SimpleNumberFormat="F2" + Minimum="0" + Maximum="1" + SmallChange="0.01" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> @@ -270,6 +285,7 @@ Grid.Column="0" Grid.ColumnSpan="2" Margin="4,-12,4,0" + Minimum="0" Maximum="1" SmallChange="0.01" TickFrequency="0.01" @@ -319,6 +335,9 @@ @@ -327,6 +346,10 @@ @@ -335,6 +358,9 @@ @@ -343,6 +369,10 @@ @@ -364,6 +394,9 @@ Value="{Binding DropSize}" Margin="4,4,4,8" HorizontalAlignment="Stretch" + Minimum="1" + Maximum="65536" + SmallChange="1" SpinButtonPlacementMode="Inline" /> @@ -376,6 +409,9 @@ Grid.Column="1" Value="{Binding Cycle}" Margin="4,4,4,8" + Minimum="1" + Maximum="10" + SmallChange="1" HorizontalAlignment="Stretch" SpinButtonPlacementMode="Inline" /> From 91abeb6f638e4ef78f7026247441b80eb584b29a Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 23:24:34 -0700 Subject: [PATCH 092/325] Add DoRA CivitModelType --- CHANGELOG.md | 2 ++ StabilityMatrix.Core/Models/Api/CivitModelType.cs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c6e9fff..21feda659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Shoutout to our Visionary-tier Patreon supporters, **Scopp Mcdee**, **Waterclouds**, and our newest Visionary, **Akiro_Senkai**! Many thanks for your generous support! ## v2.11.5 +### Added +- Added DoRA category to CivitAI model browser ### Fixed - Fixed `TaskCanceledException` when adding CivitAI Api key or searching for models when the API takes too long to respond. Retry and timeout behavior has been improved. - Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge diff --git a/StabilityMatrix.Core/Models/Api/CivitModelType.cs b/StabilityMatrix.Core/Models/Api/CivitModelType.cs index 370c93631..1d30cf306 100644 --- a/StabilityMatrix.Core/Models/Api/CivitModelType.cs +++ b/StabilityMatrix.Core/Models/Api/CivitModelType.cs @@ -20,6 +20,9 @@ public enum CivitModelType [ConvertTo(SharedFolderType.Hypernetwork)] Hypernetwork, + [ConvertTo(SharedFolderType.Lora)] + DoRA, + [ConvertTo(SharedFolderType.Lora)] LORA, From c45a8e229ea7b8619a377eb785462410ae520fc0 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 27 Jul 2024 23:46:25 -0700 Subject: [PATCH 093/325] Update Avalonia version & related nugets --- Directory.Build.props | 2 +- StabilityMatrix.Avalonia/App.axaml | 2 +- .../StabilityMatrix.Avalonia.csproj | 22 +++++++++---------- .../Views/Dialogs/PropertyGridDialog.axaml | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e059bd8fd..d5d518c9e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@  - 11.0.9 + 11.1.1 diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index 045e15f93..b967310a1 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -44,7 +44,7 @@ - + diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index e8b8927b5..1b8cd64ef 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -41,33 +41,33 @@ - + - - + + - - + + - - - + + + - - + + @@ -90,7 +90,7 @@ - + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml index e00459fc1..af365d1c4 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml @@ -20,7 +20,7 @@ Date: Sun, 28 Jul 2024 00:03:40 -0700 Subject: [PATCH 094/325] update skia --- Avalonia.Gif/Avalonia.Gif.csproj | 2 +- StabilityMatrix.Core/StabilityMatrix.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Avalonia.Gif/Avalonia.Gif.csproj b/Avalonia.Gif/Avalonia.Gif.csproj index 48a8f9492..c62673009 100644 --- a/Avalonia.Gif/Avalonia.Gif.csproj +++ b/Avalonia.Gif/Avalonia.Gif.csproj @@ -11,7 +11,7 @@ - + diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj index 00f63c9a4..91a0fc804 100644 --- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj +++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj @@ -59,7 +59,7 @@ - + From c5f43e226849df1d021c6732cc1eabc427e7bba4 Mon Sep 17 00:00:00 2001 From: jt Date: Sun, 28 Jul 2024 00:33:21 -0700 Subject: [PATCH 095/325] More nuget upgrades --- .husky/pre-commit | 0 StabilityMatrix.Avalonia/App.axaml.cs | 3 +- .../Helpers/UriHandler.cs | 3 +- .../StabilityMatrix.Avalonia.csproj | 28 ++++++------- .../Database/LiteDbContext.cs | 25 ++++++++++- .../StabilityMatrix.Core.csproj | 42 +++++++++---------- ...StabilityMatrix.Native.Abstractions.csproj | 2 +- .../StabilityMatrix.Tests.csproj | 12 +++--- .../StabilityMatrix.UITests.csproj | 16 +++---- 9 files changed, 75 insertions(+), 56 deletions(-) mode change 100644 => 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index 1b204446c..c87e0eebd 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -402,8 +402,7 @@ internal static IServiceCollection ConfigureServices() services.AddMemoryCache(); services.AddLazyInstance(); - services.AddMessagePipe(); - services.AddMessagePipeNamedPipeInterprocess("StabilityMatrix"); + services.AddMessagePipe().AddNamedPipeInterprocess("StabilityMatrix"); var exportedTypes = AppDomain .CurrentDomain.GetAssemblies() diff --git a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs index 0442466c6..8d92bb9a2 100644 --- a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs +++ b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs @@ -39,8 +39,7 @@ public UriHandler(string scheme, string description) public void SendAndExit(Uri uri) { var services = new ServiceCollection(); - services.AddMessagePipe(); - services.AddMessagePipeNamedPipeInterprocess("StabilityMatrix"); + services.AddMessagePipe().AddNamedPipeInterprocess("StabilityMatrix"); var provider = services.BuildServiceProvider(); var publisher = provider.GetRequiredService>(); diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 1b8cd64ef..c11ec4178 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -61,7 +61,7 @@ - + @@ -69,39 +69,39 @@ - + - - + + - + - + - - + + - - + + - - - + + + - + diff --git a/StabilityMatrix.Core/Database/LiteDbContext.cs b/StabilityMatrix.Core/Database/LiteDbContext.cs index e0eaa3d4b..4e2f07935 100644 --- a/StabilityMatrix.Core/Database/LiteDbContext.cs +++ b/StabilityMatrix.Core/Database/LiteDbContext.cs @@ -163,9 +163,30 @@ public async Task UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCach if (string.IsNullOrEmpty(cacheKey)) return null; - if (await GithubCache.FindByIdAsync(cacheKey).ConfigureAwait(false) is { } result) + try { - return result; + if (await GithubCache.FindByIdAsync(cacheKey).ConfigureAwait(false) is { } result) + { + return result; + } + } + catch (Exception e) + { + if (e is LiteException or LiteAsyncException && e.InnerException is InvalidCastException inner) + { + logger.LogWarning( + e, + "LiteDb Deserialize error while fetching GithubCacheEntry '{Inner}', cache collections will be cleared", + inner.ToString() + ); + + var githubCache = Database.GetCollection(nameof(GithubCache)); + await githubCache.DeleteAllAsync().ConfigureAwait(false); + } + else + { + throw; + } } return null; diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj index 91a0fc804..bc0fb5a6e 100644 --- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj +++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj @@ -20,48 +20,48 @@ - - + + - + - + - - - + + + - - + + - - - - - + + + + + - - + + - - + + - - - + + + diff --git a/StabilityMatrix.Native.Abstractions/StabilityMatrix.Native.Abstractions.csproj b/StabilityMatrix.Native.Abstractions/StabilityMatrix.Native.Abstractions.csproj index cf8f00e6a..ac76dc47e 100644 --- a/StabilityMatrix.Native.Abstractions/StabilityMatrix.Native.Abstractions.csproj +++ b/StabilityMatrix.Native.Abstractions/StabilityMatrix.Native.Abstractions.csproj @@ -8,7 +8,7 @@ - + diff --git a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj index b8309d3e1..acaab190a 100644 --- a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj +++ b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj @@ -17,18 +17,18 @@ - + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj index 2ebeb2e82..caa9290e5 100644 --- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj +++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj @@ -17,20 +17,20 @@ - + - - + + - + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 97f5be205ca3c60af747f90ab768fb0ba1dd0eed Mon Sep 17 00:00:00 2001 From: jt Date: Sun, 28 Jul 2024 01:08:20 -0700 Subject: [PATCH 096/325] rollback TextMateSharp.Grammars for colors --- StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index c11ec4178..8d7d3a5e6 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -101,7 +101,7 @@ - + From 26cb4c0667f57fdc9a983b724ffc9fe344330f08 Mon Sep 17 00:00:00 2001 From: jt Date: Sun, 28 Jul 2024 01:12:58 -0700 Subject: [PATCH 097/325] Add vulkan launch arg --- StabilityMatrix.Avalonia/Models/AppArgs.cs | 6 ++++++ StabilityMatrix.Avalonia/Program.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/StabilityMatrix.Avalonia/Models/AppArgs.cs b/StabilityMatrix.Avalonia/Models/AppArgs.cs index 7f836b112..8464bca99 100644 --- a/StabilityMatrix.Avalonia/Models/AppArgs.cs +++ b/StabilityMatrix.Avalonia/Models/AppArgs.cs @@ -63,6 +63,12 @@ public class AppArgs [Option("opengl", HelpText = "Prefer OpenGL rendering")] public bool UseOpenGlRendering { get; set; } + /// + /// Flag to use Vulkan rendering + /// + [Option("vulkan", HelpText = "Prefer Vulkan rendering")] + public bool UseVulkanRendering { get; set; } + /// /// Override global app home directory /// Defaults to (%APPDATA%|~/.config)/StabilityMatrix diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 2f1488876..9e24a160f 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -165,6 +165,12 @@ public static AppBuilder BuildAvaloniaApp() ); } + if (Args.UseVulkanRendering) + { + app = app.With(new X11PlatformOptions { RenderingMode = [X11RenderingMode.Vulkan] }) + .With(new Win32PlatformOptions { RenderingMode = [Win32RenderingMode.Vulkan] }); + } + if (Args.DisableGpuRendering) { app = app.With(new Win32PlatformOptions { RenderingMode = new[] { Win32RenderingMode.Software } }) From b6ecf40549c97dad0dcf864085babf116e454681 Mon Sep 17 00:00:00 2001 From: jt Date: Sun, 28 Jul 2024 10:51:54 -0700 Subject: [PATCH 098/325] chagenlog & fooocus update for mac --- CHANGELOG.md | 5 +++++ StabilityMatrix.Core/Models/Packages/Fooocus.cs | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21feda659..d641e5b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ### Added - Added Face Detailer module to Inference - Added ultralytics models to HuggingFace model browser +- Added DoRA category to CivitAI model browser +- Added macOS support for Fooocus & related forks +### Changed +- (Internal) Updated Avalonia to 11.1.1 +- (Internal) Updated various other libraries ### Fixed - Fixed some ScrollViewers changing scroll position when focus changes - Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index d74f75280..a79c4ccbd 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -144,6 +144,13 @@ IPrerequisiteHelper prerequisiteHelper InitialValue = !HardwareHelper.HasNvidiaGpu(), Options = { "--disable-xformers" } }, + new LaunchOptionDefinition + { + Name = "Disable Offload from VRAM", + Type = LaunchOptionType.Bool, + InitialValue = Compat.IsMacOS, + Options = { "--disable-offload-from-vram" } + }, LaunchOptionDefinition.Extras }; @@ -250,7 +257,14 @@ IPrerequisiteHelper prerequisiteHelper new() { [SharedOutputType.Text2Img] = new[] { "outputs" } }; public override IEnumerable AvailableTorchVersions => - new[] { TorchVersion.Cpu, TorchVersion.Cuda, TorchVersion.DirectMl, TorchVersion.Rocm }; + new[] + { + TorchVersion.Cpu, + TorchVersion.Cuda, + TorchVersion.DirectMl, + TorchVersion.Rocm, + TorchVersion.Mps + }; public override string MainBranch => "main"; @@ -293,6 +307,7 @@ public override async Task InstallPackage( TorchVersion.Cpu => "cpu", TorchVersion.Cuda => "cu121", TorchVersion.Rocm => "rocm5.6", + TorchVersion.Mps => "cpu", _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) } ); From 35920e710cfb0823b955c2140b9608e0ff7dec24 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 28 Jul 2024 12:33:52 -0700 Subject: [PATCH 099/325] Update CHANGELOG.md Co-authored-by: Ionite --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d641e5b2e..6009a5ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,11 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added ultralytics models to HuggingFace model browser - Added DoRA category to CivitAI model browser - Added macOS support for Fooocus & related forks +- (Windows, Linux) Added Vulkan rendering support using launch argument `--vulkan`. (On Windows, the default WinUI composition renderer is likely still preferrable. Linux users are encouraged to try the new renderer to see if it improves performance and responsiveness.) ### Changed -- (Internal) Updated Avalonia to 11.1.1 -- (Internal) Updated various other libraries +- (Internal) Updated Avalonia to 11.1.1 - Includes major rendering and performance optimizations, animation refinements, improved IME / text selection, and improvements for window sizing / z-order / multi-monitor DPI scaling. ([avaloniaui.net/blog/avalonia-11-1-a-quantum-leap-in-cross-platform-ui-development](https://avaloniaui.net/blog/avalonia-11-1-a-quantum-leap-in-cross-platform-ui-development)) +- (Internal) Updated SkiaSharp (Rendering Backend) to 3.0.0-preview.4.1, potentially fixes issues with window rendering artifacts on some machines. +- (Internal) Updated other dependencies for security and bug fixes. ### Fixed - Fixed some ScrollViewers changing scroll position when focus changes - Fixed [#782](https://github.com/LykosAI/StabilityMatrix/issues/782) - conflict error when launching new versions of Forge From b6a246ba16c2b585b16746e1a2f0bccdd1f04147 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 29 Jul 2024 02:07:16 -0400 Subject: [PATCH 100/325] Add nested expressions support for SettingsManager.RelayPropertyFor and RegisterPropertyChangedHandler --- StabilityMatrix.Core/Helper/Expressions.cs | 33 ------------- .../Services/SettingsManager.cs | 49 +++++++++---------- .../StabilityMatrix.Core.csproj | 1 + .../Core/ExpressionsTests.cs | 41 ---------------- 4 files changed, 25 insertions(+), 99 deletions(-) delete mode 100644 StabilityMatrix.Core/Helper/Expressions.cs delete mode 100644 StabilityMatrix.Tests/Core/ExpressionsTests.cs diff --git a/StabilityMatrix.Core/Helper/Expressions.cs b/StabilityMatrix.Core/Helper/Expressions.cs deleted file mode 100644 index c830d645a..000000000 --- a/StabilityMatrix.Core/Helper/Expressions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Linq.Expressions; -using System.Reflection; - -namespace StabilityMatrix.Core.Helper; - -public static class Expressions -{ - public static (string propertyName, Expression> assigner) - GetAssigner(Expression> propertyAccessor) - { - if (propertyAccessor.Body is not MemberExpression memberExpression) - { - throw new ArgumentException( - $"Expression must be a member expression, not {propertyAccessor.Body.NodeType}"); - } - - var propertyInfo = memberExpression.Member as PropertyInfo; - if (propertyInfo == null) - { - throw new ArgumentException( - $"Expression member must be a property, not {memberExpression.Member.MemberType}"); - } - - var propertyName = propertyInfo.Name; - var typeParam = Expression.Parameter(typeof(T)); - var valueParam = Expression.Parameter(typeof(TValue)); - var expr = Expression.Lambda>( - Expression.Assign( - Expression.MakeMemberAccess(typeParam, propertyInfo), - valueParam), typeParam, valueParam); - return (propertyName, expr); - } -} diff --git a/StabilityMatrix.Core/Services/SettingsManager.cs b/StabilityMatrix.Core/Services/SettingsManager.cs index 23bd3d9f4..992ccace7 100644 --- a/StabilityMatrix.Core/Services/SettingsManager.cs +++ b/StabilityMatrix.Core/Services/SettingsManager.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Text.Json; using AsyncAwaitBestPractices; +using CompiledExpressions; using Microsoft.Extensions.Logging; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; @@ -170,49 +171,48 @@ public void RelayPropertyFor( ) where T : INotifyPropertyChanged { - var sourceGetter = sourceProperty.Compile(); - var (propertyName, assigner) = Expressions.GetAssigner(sourceProperty); - var sourceSetter = assigner.Compile(); + var sourceInstanceAccessor = CompiledExpression.CreateAccessor(sourceProperty).WithInstance(source); + var settingsAccessor = CompiledExpression.CreateAccessor(settingsProperty); - var settingsGetter = settingsProperty.Compile(); - var (targetPropertyName, settingsAssigner) = Expressions.GetAssigner(settingsProperty); - var settingsSetter = settingsAssigner.Compile(); + var sourcePropertyPath = sourceInstanceAccessor.FullName; + var settingsPropertyPath = settingsAccessor.FullName; var sourceTypeName = source.GetType().Name; // Update source when settings change SettingsPropertyChanged += (sender, args) => { - if (args.PropertyName != targetPropertyName) + if (args.PropertyName != settingsPropertyPath) return; // Skip if event is relay and the sender is the source, to prevent duplicate if (args.IsRelay && ReferenceEquals(sender, source)) return; + logger.LogTrace( - "[RelayPropertyFor] " + "Settings.{TargetProperty:l} -> {SourceType:l}.{SourceProperty:l}", - targetPropertyName, + "[RelayPropertyFor] " + "Settings.{SettingsProperty:l} -> {SourceType:l}.{SourceProperty:l}", + settingsPropertyPath, sourceTypeName, - propertyName + sourcePropertyPath ); - sourceSetter(source, settingsGetter(Settings)); + sourceInstanceAccessor.Set(source, settingsAccessor.Get(Settings)); }; // Set and Save settings when source changes source.PropertyChanged += (sender, args) => { - if (args.PropertyName != propertyName) + if (args.PropertyName != sourcePropertyPath) return; logger.LogTrace( - "[RelayPropertyFor] " + "{SourceType:l}.{SourceProperty:l} -> Settings.{TargetProperty:l}", + "[RelayPropertyFor] {SourceType:l}.{SourceProperty:l} -> Settings.{SettingsProperty:l}", sourceTypeName, - propertyName, - targetPropertyName + sourcePropertyPath, + settingsPropertyPath ); - settingsSetter(Settings, sourceGetter(source)); + settingsAccessor.Set(Settings, sourceInstanceAccessor.Get()); if (IsLibraryDirSet) { @@ -228,24 +228,24 @@ public void RelayPropertyFor( else { logger.LogWarning( - "[RelayPropertyFor] LibraryDir not set when saving ({SourceType:l}.{SourceProperty:l} -> Settings.{TargetProperty:l})", + "[RelayPropertyFor] LibraryDir not set when saving ({SourceType:l}.{SourceProperty:l} -> Settings.{SettingsProperty:l})", sourceTypeName, - propertyName, - targetPropertyName + sourcePropertyPath, + settingsPropertyPath ); } // Invoke property changed event, passing along sender SettingsPropertyChanged?.Invoke( sender, - new RelayPropertyChangedEventArgs(targetPropertyName, true) + new RelayPropertyChangedEventArgs(settingsPropertyPath, true) ); }; // Set initial value if requested if (setInitial) { - sourceSetter(source, settingsGetter(Settings)); + sourceInstanceAccessor.Set(settingsAccessor.Get(Settings)); } } @@ -255,16 +255,15 @@ public void RegisterPropertyChangedHandler( Action onPropertyChanged ) { - var settingsGetter = settingsProperty.Compile(); - var (propertyName, _) = Expressions.GetAssigner(settingsProperty); + var settingsAccessor = CompiledExpression.CreateAccessor(settingsProperty); // Invoke handler when settings change SettingsPropertyChanged += (_, args) => { - if (args.PropertyName != propertyName) + if (args.PropertyName != settingsAccessor.FullName) return; - onPropertyChanged(settingsGetter(Settings)); + onPropertyChanged(settingsAccessor.Get(Settings)); }; } diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj index bc0fb5a6e..d256d5f08 100644 --- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj +++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj @@ -23,6 +23,7 @@ + diff --git a/StabilityMatrix.Tests/Core/ExpressionsTests.cs b/StabilityMatrix.Tests/Core/ExpressionsTests.cs deleted file mode 100644 index 4d6f51a0c..000000000 --- a/StabilityMatrix.Tests/Core/ExpressionsTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using StabilityMatrix.Core.Helper; - -namespace StabilityMatrix.Tests.Core; - -[TestClass] -public class ExpressionsTests -{ - private class TestClass - { - public int Id { get; set; } - public NestedTestClass? Nested { get; set; } - } - - private class NestedTestClass - { - public string Text { get; set; } = ""; - } - - [TestMethod] - public void GetAssigner_Simple_PropertyName() - { - var (propertyName, _) = - Expressions.GetAssigner(x => x.Id); - - // Check that the property name is correct - Assert.AreEqual("Id", propertyName); - } - - [TestMethod] - public void GetAssigner_Simple_PropertyAssignment() - { - var obj = new TestClass(); - - var (_, assigner) = - Expressions.GetAssigner(x => x.Id); - - assigner.Compile()(obj, 42); - - Assert.AreEqual(42, obj.Id); - } -} From 644a99efca01c72d09f6041aa7c318c48d28b6a9 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 29 Jul 2024 21:28:06 -0700 Subject: [PATCH 101/325] Added new folder & delete options to Checkpoints Page treeview context menu --- StabilityMatrix.Avalonia/DialogHelper.cs | 7 ++ .../Models/CheckpointCategory.cs | 3 + .../ViewModels/CheckpointsPageViewModel.cs | 97 +++++++++++++++++-- .../Views/CheckpointsPage.axaml | 42 +++++--- 4 files changed, 131 insertions(+), 18 deletions(-) diff --git a/StabilityMatrix.Avalonia/DialogHelper.cs b/StabilityMatrix.Avalonia/DialogHelper.cs index b09d51a95..0b98ddf13 100644 --- a/StabilityMatrix.Avalonia/DialogHelper.cs +++ b/StabilityMatrix.Avalonia/DialogHelper.cs @@ -171,6 +171,11 @@ IReadOnlyList textFields DataContext = field, }; + if (field.MinWidth.HasValue) + { + textBox.MinWidth = field.MinWidth.Value; + } + if (!string.IsNullOrEmpty(field.InnerLeftText)) { textBox.InnerLeftContent = new TextBlock() @@ -617,6 +622,8 @@ public sealed class TextBoxField : INotifyPropertyChanged // Inner left value public string? InnerLeftText { get; init; } + public int? MinWidth { get; init; } + /// /// Validation action on text changes. Throw exception if invalid. /// diff --git a/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs b/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs index 0d1096103..f87c5fd3f 100644 --- a/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs +++ b/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using CommunityToolkit.Mvvm.ComponentModel; namespace StabilityMatrix.Avalonia.Models; @@ -23,4 +24,6 @@ public IEnumerable Flatten() } } } + + public string GetId() => $@"{Name};{Flatten().Count()}"; } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 2d0b3d825..c8bd7781a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -19,6 +19,7 @@ using FluentAvalonia.UI.Controls; using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Services; @@ -37,6 +38,7 @@ using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.PackageModification; using StabilityMatrix.Core.Models.Progress; +using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; using CheckpointSortMode = StabilityMatrix.Core.Models.CheckpointSortMode; using Notification = Avalonia.Controls.Notifications.Notification; @@ -64,7 +66,7 @@ ServiceManager dialogFactory public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Notebook, IsFilled = true }; - private SourceCache categoriesCache = new(category => category.Path); + private SourceCache categoriesCache = new(category => category.GetId()); public IObservableCollection Categories { get; set; } = new ObservableCollectionExtended(); @@ -287,7 +289,17 @@ or nameof(SortConnectedModelsFirst) NumItemsSelected = Models.Count(o => o.IsSelected); }); - categoriesCache.Connect().DeferUntilLoaded().Bind(Categories).Subscribe(); + categoriesCache + .Connect() + .DeferUntilLoaded() + .SortAndBind( + Categories, + SortExpressionComparer + .Descending(x => x.Name == "All Models") + .ThenByAscending(x => x.Name) + ) + .Subscribe(); + settingsManager.RelayPropertyFor( this, vm => vm.IsImportAsConnectedEnabled, @@ -559,6 +571,82 @@ private void ClearOrSelectAllBaseModels() } } + [RelayCommand] + private async Task CreateFolder(object? treeViewItem) + { + if (treeViewItem is not CheckpointCategory category) + return; + + var parentFolder = category.Path; + + if (string.IsNullOrWhiteSpace(parentFolder)) + return; + + var fields = new TextBoxField[] + { + new() + { + Label = "Folder Name", + InnerLeftText = + $@"{parentFolder.Replace(settingsManager.ModelsDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}", + MinWidth = 400 + } + }; + + var dialog = DialogHelper.CreateTextEntryDialog("Create Folder", string.Empty, fields); + var result = await dialog.ShowAsync(); + + if (result != ContentDialogResult.Primary) + return; + + var folderName = fields[0].Text; + var folderPath = Path.Combine(parentFolder, folderName); + + await notificationService.TryAsync( + Task.Run(() => Directory.CreateDirectory(folderPath)), + message: "Could not create folder" + ); + + RefreshCategories(); + } + + [RelayCommand] + private Task OpenFolderFromTreeview(object? treeViewItem) => + treeViewItem is CheckpointCategory category && !string.IsNullOrWhiteSpace(category.Path) + ? ProcessRunner.OpenFolderBrowser(category.Path) + : Task.CompletedTask; + + [RelayCommand] + private async Task DeleteFolderAsync(object? treeViewItem) + { + if (treeViewItem is not CheckpointCategory category) + return; + + var folderPath = category.Path; + if (string.IsNullOrWhiteSpace(folderPath)) + return; + + var confirmDeleteVm = dialogFactory.Get(); + confirmDeleteVm.PathsToDelete = category.Flatten().Select(x => x.Path).ToList(); + + if (await confirmDeleteVm.GetDialog().ShowAsync() != ContentDialogResult.Primary) + return; + + confirmDeleteVm.PathsToDelete = [folderPath]; + + try + { + await confirmDeleteVm.ExecuteCurrentDeleteOperationAsync(failFast: true); + } + catch (Exception e) + { + notificationService.ShowPersistent("Error deleting folder", e.Message, NotificationType.Error); + return; + } + + RefreshCategories(); + } + public async Task ImportFilesAsync(IEnumerable files, DirectoryPath destinationFolder) { if (destinationFolder.FullPath == settingsManager.ModelsDirectory) @@ -710,10 +798,7 @@ private void RefreshCategories() Count = modelIndexService.ModelIndex.Values.SelectMany(x => x).Count(), }; - categoriesCache.EditDiff( - [rootCategory, ..modelCategories], - (a, b) => a.Path == b.Path && a.SubDirectories.Count == b.SubDirectories.Count - ); + categoriesCache.EditDiff([rootCategory, ..modelCategories], (a, b) => a.GetId() == b.GetId()); SelectedCategory = previouslySelectedCategory diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 86b7a0f22..178c5d422 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -29,6 +29,8 @@ True + @@ -285,6 +287,34 @@ DragDrop.AllowDrop="True" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedCategory}"> + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - From a74558e5af1c69db1bcc25e04c0bba653754a216 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 30 Jul 2024 01:11:47 -0400 Subject: [PATCH 102/325] Add IDisposable return for RegisterPropertyChangedHandler --- .../Services/ISettingsManager.cs | 2 +- .../Services/SettingsManager.cs | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/StabilityMatrix.Core/Services/ISettingsManager.cs b/StabilityMatrix.Core/Services/ISettingsManager.cs index d0970f06b..335adb7bb 100644 --- a/StabilityMatrix.Core/Services/ISettingsManager.cs +++ b/StabilityMatrix.Core/Services/ISettingsManager.cs @@ -85,7 +85,7 @@ void RelayPropertyFor( /// /// Register an Action to be called on change of the settings property. /// - void RegisterPropertyChangedHandler( + IDisposable RegisterPropertyChangedHandler( Expression> settingsProperty, Action onPropertyChanged ); diff --git a/StabilityMatrix.Core/Services/SettingsManager.cs b/StabilityMatrix.Core/Services/SettingsManager.cs index 992ccace7..485db7221 100644 --- a/StabilityMatrix.Core/Services/SettingsManager.cs +++ b/StabilityMatrix.Core/Services/SettingsManager.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using System.Reactive.Linq; using System.Reflection; using System.Text.Json; using AsyncAwaitBestPractices; @@ -250,21 +251,30 @@ public void RelayPropertyFor( } /// - public void RegisterPropertyChangedHandler( + public IDisposable RegisterPropertyChangedHandler( Expression> settingsProperty, Action onPropertyChanged ) { + var handlerName = onPropertyChanged.Method.Name; var settingsAccessor = CompiledExpression.CreateAccessor(settingsProperty); - // Invoke handler when settings change - SettingsPropertyChanged += (_, args) => - { - if (args.PropertyName != settingsAccessor.FullName) - return; + return Observable + .FromEventPattern, RelayPropertyChangedEventArgs>( + h => SettingsPropertyChanged += h, + h => SettingsPropertyChanged -= h + ) + .Where(args => args.EventArgs.PropertyName == settingsAccessor.FullName) + .Subscribe(_ => + { + logger.LogTrace( + "[RegisterPropertyChangedHandler] Settings.{SettingsProperty:l} -> Handler ({Action})", + settingsAccessor.FullName, + handlerName + ); - onPropertyChanged(settingsAccessor.Get(Settings)); - }; + onPropertyChanged(settingsAccessor.Get(Settings)); + }); } /// From e31ccb2035a1fbf6a651203d0b1f641e6f16b38c Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 30 Jul 2024 01:12:40 -0400 Subject: [PATCH 103/325] Add MaxLines option for ConsoleViewModel --- .../ViewModels/ConsoleViewModel.cs | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs index f68934004..c180ea4ac 100644 --- a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs @@ -7,9 +7,9 @@ using Avalonia.Threading; using AvaloniaEdit.Document; using CommunityToolkit.Mvvm.ComponentModel; -using NLog; using Nito.AsyncEx; using Nito.AsyncEx.Synchronous; +using NLog; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Processes; @@ -30,6 +30,8 @@ public partial class ConsoleViewModel : ObservableObject, IDisposable, IAsyncDis // Cancellation token source for updateTask private CancellationTokenSource? updateCts; + public int MaxLines { get; set; } = -1; + public bool IsUpdatesRunning => updateTask?.IsCompleted == false; [ObservableProperty] @@ -54,7 +56,8 @@ public partial class ConsoleViewModel : ObservableObject, IDisposable, IAsyncDis /// /// Gets a cancellation token using the cursor lock timeout /// - private CancellationToken WriteCursorLockTimeoutToken => new CancellationTokenSource(WriteCursorLockTimeout).Token; + private CancellationToken WriteCursorLockTimeoutToken => + new CancellationTokenSource(WriteCursorLockTimeout).Token; /// /// Event invoked when an ApcMessage of type Input is received. @@ -143,7 +146,8 @@ private async Task ConsoleUpdateLoop() Dispatcher.UIThread.VerifyAccess(); // Get cancellation token - var ct = updateCts?.Token ?? throw new InvalidOperationException("Update cancellation token must be set"); + var ct = + updateCts?.Token ?? throw new InvalidOperationException("Update cancellation token must be set"); try { @@ -171,7 +175,9 @@ private async Task ConsoleUpdateLoop() ); // Link the cancellation token to the write cursor lock timeout - var linkedCt = CancellationTokenSource.CreateLinkedTokenSource(ct, WriteCursorLockTimeoutToken).Token; + var linkedCt = CancellationTokenSource + .CreateLinkedTokenSource(ct, WriteCursorLockTimeoutToken) + .Token; using (await writeCursorLock.LockAsync(linkedCt)) { @@ -293,7 +299,9 @@ private void ConsoleUpdateOne(ProcessOutput output) var spaces = new string(' ', currentLine.Length); // Insert the text - Logger.ConditionalTrace($"Erasing line {currentLine.LineNumber}: (length = {currentLine.Length})"); + Logger.ConditionalTrace( + $"Erasing line {currentLine.LineNumber}: (length = {currentLine.Length})" + ); using (Document.RunUpdate()) { Document.Replace(currentLine.Offset, currentLine.Length, spaces); @@ -360,6 +368,8 @@ private void DirectWriteLinesToConsole(string text) /// private void DirectWriteToConsole(string text) { + CheckMaxLines(); + using (Document.RunUpdate()) { // Need to replace text first if cursor lower than document length @@ -382,7 +392,9 @@ private void DirectWriteToConsole(string text) if (remainingLength > 0) { var textToInsert = text[replaceLength..]; - Logger.ConditionalTrace($"Inserting: (cursor = {writeCursor}, " + $"text = {textToInsert.ToRepr()})"); + Logger.ConditionalTrace( + $"Inserting: (cursor = {writeCursor}, " + $"text = {textToInsert.ToRepr()})" + ); Document.Insert(writeCursor, textToInsert); writeCursor += textToInsert.Length; @@ -390,6 +402,59 @@ private void DirectWriteToConsole(string text) } } + private void CheckMaxLines() + { + // Ignore when MaxLines is -1 + if (MaxLines == -1) + return; + + if (Document.LineCount <= MaxLines) + return; + + // Minimum lines to remove + const int removeLinesBatchSize = 1; + + using (Document.RunUpdate()) + { + var currentLines = Document.LineCount; + var linesExceeded = currentLines - MaxLines; + var linesToRemove = Math.Min(currentLines, Math.Max(linesExceeded, removeLinesBatchSize)); + + Logger.ConditionalTrace( + "Exceeded max lines ({Current} > {Max}), removing {Remove} lines", + currentLines, + MaxLines, + linesToRemove + ); + + // Remove lines from the start + var firstLine = Document.GetLineByNumber(1); + var lastLine = Document.GetLineByNumber(linesToRemove); + var removeStart = firstLine.Offset; + + // If a next line exists, use the start offset of that instead in case of weird newlines + var removeEnd = lastLine.EndOffset; + if (lastLine.NextLine is not null) + { + removeEnd = lastLine.NextLine.Offset; + } + + var removeLength = removeEnd - removeStart; + + Logger.ConditionalTrace( + "Removing {LinesExceeded} lines from start: ({RemoveStart} -> {RemoveEnd})", + linesExceeded, + removeStart, + removeEnd + ); + + Document.Remove(removeStart, removeLength); + + // Update cursor position + writeCursor -= removeLength; + } + } + /// /// Debug function to print the current document to the console. /// Includes formatted cursor position. From 7f5f356e0a331bf9685be89e0d1b8ba3adab3c75 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 30 Jul 2024 01:13:17 -0400 Subject: [PATCH 104/325] Add ConsoleLogHistorySize Setting --- .../Languages/Resources.Designer.cs | 18 ++++++++++++++++++ .../Languages/Resources.resx | 6 ++++++ .../Settings/MainSettingsViewModel.cs | 11 +++++++++++ .../Views/Settings/MainSettingsPage.axaml | 1 + .../Models/Settings/Settings.cs | 2 ++ 5 files changed, 38 insertions(+) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 3a3e120cc..8eed33a34 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -1544,6 +1544,24 @@ public static string Label_Height { } } + /// + /// Looks up a localized string similar to History Size. + /// + public static string Label_HistorySize { + get { + return ResourceManager.GetString("Label_HistorySize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The number of lines above the ones displayed in the window you can scroll back to. + /// + public static string Label_HistorySize_Description { + get { + return ResourceManager.GetString("Label_HistorySize_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to Holiday Mode. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 71b30a70d..141044da3 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1128,4 +1128,10 @@ PLEASE EXTRACT THE APP FROM THE ZIP FILE BEFORE RUNNING STABILITY MATRIX + + History Size + + + The number of lines above the ones displayed in the window you can scroll back to + diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs index 95f25f7a8..96531fded 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs @@ -118,6 +118,10 @@ public partial class MainSettingsViewModel : PageViewModelBase [ObservableProperty] private bool isDiscordRichPresenceEnabled; + // Console section + [ObservableProperty] + private int consoleLogHistorySize; + // Debug section [ObservableProperty] private string? debugPaths; @@ -256,6 +260,13 @@ IAccountsService accountsService true ); + settingsManager.RelayPropertyFor( + this, + vm => vm.ConsoleLogHistorySize, + settings => settings.ConsoleLogHistorySize, + true + ); + DebugThrowAsyncExceptionCommand.WithNotificationErrorHandler(notificationService, LogLevel.Warn); hardwareInfoUpdateTimer.Tick += OnHardwareInfoUpdateTimerTick; diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index f45af3ef1..6f5a5d90f 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -257,6 +257,7 @@ + EnvironmentVariables public bool AutoScrollLaunchConsoleToEnd { get; set; } = true; + public int ConsoleLogHistorySize { get; set; } = 9001; + public HashSet FavoriteModels { get; set; } = new(); public HashSet SeenTeachingTips { get; set; } = new(); From a76f0a98ecb6e6f6bcecee2714716c85a8c03187 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 30 Jul 2024 01:13:39 -0400 Subject: [PATCH 105/325] Add settings ui for ConsoleLogHistorySize --- .../Views/Settings/MainSettingsPage.axaml | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index 6f5a5d90f..6c6a99c44 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -109,7 +109,7 @@ - + + + + + + + + + + + + + Date: Tue, 30 Jul 2024 01:14:38 -0400 Subject: [PATCH 106/325] Add ConsoleLogHistorySize setting and subscription update for RunningPackageViewModel --- .../ViewModels/RunningPackageViewModel.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs index c659c57c1..e68559ec9 100644 --- a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Reactive.Disposables; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -24,6 +25,8 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I private readonly INotificationService notificationService; private readonly RunningPackageService runningPackageService; + private readonly CompositeDisposable subscriptions = new(); + public PackagePair RunningPackage { get; } public ConsoleViewModel Console { get; } public override string Title => RunningPackage.InstalledPackage.DisplayName ?? "Running Package"; @@ -62,10 +65,21 @@ ConsoleViewModel console RunningPackage = runningPackage; Console = console; + Console.MaxLines = settingsManager.Settings.ConsoleLogHistorySize; Console.Document.LineCountChanged += DocumentOnLineCountChanged; RunningPackage.BasePackage.StartupComplete += BasePackageOnStartupComplete; RunningPackage.BasePackage.Exited += BasePackageOnExited; + subscriptions.Add( + settingsManager.RegisterPropertyChangedHandler( + settings => settings.ConsoleLogHistorySize, + newValue => + { + Console.MaxLines = newValue; + } + ) + ); + settingsManager.RelayPropertyFor( this, vm => vm.AutoScrollToEnd, @@ -177,6 +191,7 @@ public void Dispose() { RunningPackage.BasePackage.Shutdown(); Console.Dispose(); + subscriptions.Dispose(); GC.SuppressFinalize(this); } @@ -184,6 +199,7 @@ public async ValueTask DisposeAsync() { RunningPackage.BasePackage.Shutdown(); await Console.DisposeAsync(); + subscriptions.Dispose(); GC.SuppressFinalize(this); } } From a36a92f4689f91284bd277a12d8f2cab5318c237 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 30 Jul 2024 01:20:32 -0400 Subject: [PATCH 107/325] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6009a5ae3..9e5d8d0dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.12.0-dev.3 +### Added +- Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. + ## v2.12.0-dev.2 ### Added - Added Face Detailer module to Inference From 3d1ba42edb81624c0e6b3184b86a95e8c69e749e Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 30 Jul 2024 01:02:47 -0700 Subject: [PATCH 108/325] sorta fixed the category select thing but still needs some work for the highlight --- .../Models/CheckpointCategory.cs | 3 +++ .../ViewModels/CheckpointsPageViewModel.cs | 21 +++++++++++++++++++ .../Views/CheckpointsPage.axaml | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs b/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs index f87c5fd3f..7b4a8d058 100644 --- a/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs +++ b/StabilityMatrix.Avalonia/Models/CheckpointCategory.cs @@ -10,6 +10,9 @@ public partial class CheckpointCategory : TreeViewDirectory [ObservableProperty] private int count; + [ObservableProperty] + private bool isExpanded; + public new ObservableCollection SubDirectories { get; set; } = new(); public IEnumerable Flatten() diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index c8bd7781a..cfd78e10e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -800,6 +800,27 @@ private void RefreshCategories() categoriesCache.EditDiff([rootCategory, ..modelCategories], (a, b) => a.GetId() == b.GetId()); + SelectedCategory = + previouslySelectedCategory + ?? Categories.FirstOrDefault(x => x.Path == previouslySelectedCategory?.Path) + ?? Categories.First(); + + var dirPath = new DirectoryPath(SelectedCategory.Path); + + while (dirPath.FullPath != settingsManager.ModelsDirectory && dirPath.Parent != null) + { + var category = Categories + .SelectMany(x => x.Flatten()) + .FirstOrDefault(x => x.Path == dirPath.FullPath); + if (category != null) + { + category.IsExpanded = true; + } + + dirPath = dirPath.Parent; + } + + // one more time for good measure?? SelectedCategory = previouslySelectedCategory ?? Categories.FirstOrDefault(x => x.Path == previouslySelectedCategory?.Path) diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 178c5d422..4e714f7af 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -16,6 +16,7 @@ xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:helpers="clr-namespace:StabilityMatrix.Avalonia.Helpers" xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia" + xmlns:models1="clr-namespace:StabilityMatrix.Avalonia.Models" mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="650" x:Class="StabilityMatrix.Avalonia.Views.CheckpointsPage" d:DataContext="{x:Static mocks:DesignData.CheckpointsPageViewModel}" @@ -287,6 +288,11 @@ DragDrop.AllowDrop="True" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedCategory}"> + + + Date: Tue, 30 Jul 2024 04:05:37 -0400 Subject: [PATCH 109/325] Fix description --- StabilityMatrix.Avalonia/Languages/Resources.Designer.cs | 2 +- StabilityMatrix.Avalonia/Languages/Resources.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 8eed33a34..9114e0d0e 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -1554,7 +1554,7 @@ public static string Label_HistorySize { } /// - /// Looks up a localized string similar to The number of lines above the ones displayed in the window you can scroll back to. + /// Looks up a localized string similar to The number of lines above the ones displayed in the console you can scroll back to. /// public static string Label_HistorySize_Description { get { diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 141044da3..af0451a28 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1132,6 +1132,6 @@ History Size - The number of lines above the ones displayed in the window you can scroll back to + The number of lines above the ones displayed in the console you can scroll back to From 7b3a6d375c04f596320315608a69aea44a5d8a3a Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 30 Jul 2024 20:31:51 -0700 Subject: [PATCH 110/325] fixed category selection after new folder creation & allow Selected items to come along for the ride when dragged n dropped --- .../ViewModels/CheckpointsPageViewModel.cs | 2 ++ .../Views/CheckpointsPage.axaml.cs | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index cfd78e10e..949d68b06 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -608,6 +608,8 @@ await notificationService.TryAsync( ); RefreshCategories(); + + SelectedCategory = Categories.SelectMany(c => c.Flatten()).FirstOrDefault(x => x.Path == folderPath); } [RelayCommand] diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs index d36ecbca2..de5426035 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs @@ -196,7 +196,24 @@ private async void OnDrop(object? sender, DragEventArgs e) case CheckpointCategory category: if (e.Data.GetContext() is { } vm) { - await checkpointsVm.MoveBetweenFolders(vm.CheckpointFile, category.Path); + var allSelectedCheckpoints = checkpointsVm.Models.Where(x => x.IsSelected).ToList(); + + if (allSelectedCheckpoints.Any()) + { + if (!allSelectedCheckpoints.Contains(vm)) + { + allSelectedCheckpoints.Add(vm); + } + + foreach (var checkpoint in allSelectedCheckpoints) + { + await checkpointsVm.MoveBetweenFolders(checkpoint.CheckpointFile, category.Path); + } + } + else + { + await checkpointsVm.MoveBetweenFolders(vm.CheckpointFile, category.Path); + } } else if (e.Data.Get(DataFormats.Files) is IEnumerable files) { From 385169e2776ac3043099544f246dc0e21a82718c Mon Sep 17 00:00:00 2001 From: jt Date: Tue, 30 Jul 2024 21:22:19 -0700 Subject: [PATCH 111/325] Updated Skia native nuget for Linux since that's not implicit for some reason --- CHANGELOG.md | 4 ++++ StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6009a5ae3..c79f196e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.12.0-dev.3 +### Fixed +- Fixed "The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp." error for Linux users + ## v2.12.0-dev.2 ### Added - Added Face Detailer module to Inference diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 8d7d3a5e6..60fd0db69 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -103,6 +103,7 @@ + From f88b8dcbd1d0870ae31cd2abe0ce2cc0dc424f86 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 31 Jul 2024 00:32:39 -0400 Subject: [PATCH 112/325] Allow negative HistorySize settings + input validation --- .../Views/Settings/MainSettingsPage.axaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index 6c6a99c44..a25cc9a43 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -276,7 +276,10 @@ From 68be325bb822c3a729f5ee1d4f69a58b6eeabe27 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 31 Jul 2024 00:34:49 -0400 Subject: [PATCH 113/325] Ignore limit for all negative ints --- StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs index c180ea4ac..65a3bc1a0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs @@ -404,8 +404,8 @@ private void DirectWriteToConsole(string text) private void CheckMaxLines() { - // Ignore when MaxLines is -1 - if (MaxLines == -1) + // Ignore limit if MaxLines is negative + if (MaxLines < 0) return; if (Document.LineCount <= MaxLines) From 60ba17330d3de1ea530abe78e7a656027d25043b Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 31 Jul 2024 00:37:26 -0400 Subject: [PATCH 114/325] Fix invalid number format --- StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index a25cc9a43..a05d4126e 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -276,7 +276,7 @@ Date: Tue, 30 Jul 2024 21:48:00 -0700 Subject: [PATCH 115/325] chagenlog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de95c37a2..dfa847b6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.12.0-dev.3 ### Added - Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. +- Added "New Directory" and "Delete" options to the context menu of the tree view on the Checkpoints page. +### Changed +- When dragging and dropping on the Checkpoints page, all selected models will now move together with the dragged model. ### Fixed - Fixed "The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp." error for Linux users From 68df969cf278331e3059a540e21ba37f937eefc6 Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 1 Aug 2024 17:57:19 -0700 Subject: [PATCH 116/325] add filesize sort & toggle for moving all selected models --- CHANGELOG.md | 5 +++- .../Assets/hf-packages.json | 27 +++++-------------- .../CheckpointFileViewModel.cs | 19 +++++++++++++ .../ViewModels/CheckpointsPageViewModel.cs | 9 +++++++ .../Progress/ProgressManagerViewModel.cs | 2 +- .../Views/CheckpointsPage.axaml | 5 ++++ .../Views/CheckpointsPage.axaml.cs | 2 +- .../Models/CheckpointSortMode.cs | 3 +++ 8 files changed, 49 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa847b6e..8bccb5e3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,13 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ### Added - Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. - Added "New Directory" and "Delete" options to the context menu of the tree view on the Checkpoints page. +- Added new toggle for dragging and dropping models on the Checkpoints page, when enabled, all selected models will now move together with the dragged model +- Added "File Size" sorting option to the Checkpoints page ### Changed -- When dragging and dropping on the Checkpoints page, all selected models will now move together with the dragged model. +- The "Download Failed" message for model downloads is now persistent until dismissed ### Fixed - Fixed "The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp." error for Linux users +- Fixed download links for IPAdapters in the HuggingFace model browser ## v2.12.0-dev.2 ### Added diff --git a/StabilityMatrix.Avalonia/Assets/hf-packages.json b/StabilityMatrix.Avalonia/Assets/hf-packages.json index 611a3af8d..0b97b8e12 100644 --- a/StabilityMatrix.Avalonia/Assets/hf-packages.json +++ b/StabilityMatrix.Avalonia/Assets/hf-packages.json @@ -390,10 +390,8 @@ "ModelName": "SD 1.5 Adapter", "RepositoryPath": "InvokeAI/ip_adapter_sd15", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter_sd15.safetensors" ], - "Subfolder": "ip_adapter_sd15", "LicenseType": "Apache 2.0" }, { @@ -401,8 +399,7 @@ "ModelName": "SD 1.5 Light Adapter", "RepositoryPath": "InvokeAI/ip_adapter_sd15_light", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter_sd15_light.safetensors" ], "Subfolder": "ip_adapter_sd15_light", "LicenseType": "Apache 2.0" @@ -412,10 +409,8 @@ "ModelName": "SD 1.5 Plus Adapter", "RepositoryPath": "InvokeAI/ip_adapter_plus_sd15", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter-plus_sd15.safetensors" ], - "Subfolder": "ip_adapter_plus_sd15", "LicenseType": "Apache 2.0" }, { @@ -423,10 +418,8 @@ "ModelName": "SD 1.5 Face Plus Adapter", "RepositoryPath": "InvokeAI/ip_adapter_plus_face_sd15", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter-plus-face_sd15.safetensors" ], - "Subfolder": "ip_adapter_plus_face_sd15", "LicenseType": "Apache 2.0" }, { @@ -434,10 +427,8 @@ "ModelName": "SDXL Adapter", "RepositoryPath": "InvokeAI/ip_adapter_sdxl", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter_sdxl.safetensors" ], - "Subfolder": "ip_adapter_sdxl", "LicenseType": "Apache 2.0" }, { @@ -445,10 +436,8 @@ "ModelName": "SDXL Plus Adapter", "RepositoryPath": "InvokeAI/ip-adapter-plus_sdxl_vit-h", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter-plus_sdxl_vit-h.safetensors" ], - "Subfolder": "ip_adapter_plus_sdxl_vit-h", "LicenseType": "Apache 2.0" }, { @@ -456,10 +445,8 @@ "ModelName": "SDXL Face Plus Adapter", "RepositoryPath": "InvokeAI/ip-adapter-plus-face_sdxl_vit-h", "Files": [ - "image_encoder.txt", - "ip_adapter.bin" + "ip-adapter-plus-face_sdxl_vit-h.safetensors" ], - "Subfolder": "ip_adapter_plus_face_sdxl_vit-h", "LicenseType": "CreativeML Open RAIL-M" }, { diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index 0264b9ca4..ea37d1b18 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.IO; using System.Threading.Tasks; +using Avalonia.Controls; using Avalonia.Controls.Notifications; using Avalonia.Data; using CommunityToolkit.Mvvm.ComponentModel; @@ -13,6 +14,7 @@ using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.Progress; @@ -35,6 +37,9 @@ public partial class CheckpointFileViewModel : SelectableViewModelBase [ObservableProperty] private bool isLoading; + [ObservableProperty] + private long fileSize; + private readonly ISettingsManager settingsManager; private readonly IModelIndexService modelIndexService; private readonly INotificationService notificationService; @@ -66,6 +71,11 @@ LocalModelFile checkpointFile ?? CheckpointFile.ConnectedModelInfo?.ThumbnailImageUrl ?? Assets.NoImage.ToString() : string.Empty; + + if (Design.IsDesignMode) + return; + + FileSize = GetFileSize(CheckpointFile.GetFullPath(settingsManager.ModelsDirectory)); } [RelayCommand] @@ -259,4 +269,13 @@ private async Task RenameAsync() } } } + + private long GetFileSize(string filePath) + { + if (!File.Exists(filePath)) + return 0; + + var fileInfo = new FileInfo(filePath); + return fileInfo.Length; + } } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 949d68b06..8192d3ca3 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -126,6 +126,9 @@ ServiceManager dialogFactory [ObservableProperty] private ObservableCollection selectedBaseModels = []; + [ObservableProperty] + private bool dragMovesAllSelected = true; + public string ClearButtonText => SelectedBaseModels.Count == BaseModelOptions.Count ? Resources.Action_ClearSelection @@ -256,6 +259,12 @@ or nameof(SortConnectedModelsFirst) comparer = comparer.ThenByAscending(vm => vm.CheckpointFile.DisplayModelName); comparer = comparer.ThenByDescending(vm => vm.CheckpointFile.DisplayModelVersion); break; + case CheckpointSortMode.FileSize: + comparer = + SelectedSortDirection == ListSortDirection.Ascending + ? comparer.ThenByAscending(vm => vm.FileSize) + : comparer.ThenByDescending(vm => vm.FileSize); + break; default: throw new ArgumentOutOfRangeException(); } diff --git a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs index 4e9f36caa..1ccdb1ed8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs @@ -149,7 +149,7 @@ exception is UnauthorizedAccessException } notificationService - .ShowAsync( + .ShowPersistentAsync( NotificationKey.Download_Failed, new Notification { diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 4e714f7af..05a933739 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -275,6 +275,11 @@ IconSource="Cloud" Label="{x:Static lang:Resources.Label_ImportAsConnected}" IsChecked="{Binding IsImportAsConnectedEnabled, Mode=TwoWay}" /> + diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs index de5426035..4f3d79abd 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs @@ -198,7 +198,7 @@ private async void OnDrop(object? sender, DragEventArgs e) { var allSelectedCheckpoints = checkpointsVm.Models.Where(x => x.IsSelected).ToList(); - if (allSelectedCheckpoints.Any()) + if (allSelectedCheckpoints.Any() && checkpointsVm.DragMovesAllSelected) { if (!allSelectedCheckpoints.Contains(vm)) { diff --git a/StabilityMatrix.Core/Models/CheckpointSortMode.cs b/StabilityMatrix.Core/Models/CheckpointSortMode.cs index fe1a72a26..ff7fc4180 100644 --- a/StabilityMatrix.Core/Models/CheckpointSortMode.cs +++ b/StabilityMatrix.Core/Models/CheckpointSortMode.cs @@ -10,6 +10,9 @@ public enum CheckpointSortMode [StringValue("File Name")] FileName, + [StringValue("File Size")] + FileSize, + [StringValue("Title")] Title, From be47e37a968734262ea904d17013c40c7a96d4f6 Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 1 Aug 2024 18:09:38 -0700 Subject: [PATCH 117/325] fix test --- .../ViewModels/CheckpointManager/CheckpointFileViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index ea37d1b18..ad8e2305b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -72,7 +72,7 @@ LocalModelFile checkpointFile ?? Assets.NoImage.ToString() : string.Empty; - if (Design.IsDesignMode) + if (!settingsManager.IsLibraryDirSet) return; FileSize = GetFileSize(CheckpointFile.GetFullPath(settingsManager.ModelsDirectory)); From ad067c409507d2af9f95a702e5152ac32914ae5c Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 1 Aug 2024 18:16:10 -0700 Subject: [PATCH 118/325] settings --- .../ViewModels/CheckpointsPageViewModel.cs | 7 +++++++ StabilityMatrix.Core/Models/Settings/Settings.cs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 8192d3ca3..29acccc3f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -355,6 +355,13 @@ or nameof(SortConnectedModelsFirst) true ); + settingsManager.RelayPropertyFor( + this, + vm => vm.DragMovesAllSelected, + settings => settings.DragMovesAllSelected, + true + ); + // make sure a sort happens OnPropertyChanged(nameof(SortConnectedModelsFirst)); } diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index 612497d32..ecd69b3d1 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -192,6 +192,8 @@ public IReadOnlyDictionary EnvironmentVariables /// public bool MoveFilesOnImport { get; set; } = true; + public bool DragMovesAllSelected { get; set; } = true; + [JsonIgnore] public bool IsHolidayModeActive => HolidayModeSetting == HolidayMode.Automatic From 8b6d9d68cb9e40dd6d04ddbb7e5601797f857f4b Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 1 Aug 2024 23:33:16 -0700 Subject: [PATCH 119/325] add hide empty categories toggle & add select all button on Checkpoints page InfoBar --- CHANGELOG.md | 9 ++-- .../ViewModels/CheckpointsPageViewModel.cs | 46 +++++++++++++++---- .../Views/CheckpointsPage.axaml | 23 ++++++++-- .../Models/Settings/Settings.cs | 2 + 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bccb5e3e..97e04675f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,12 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.12.0-dev.3 ### Added - Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. -- Added "New Directory" and "Delete" options to the context menu of the tree view on the Checkpoints page. -- Added new toggle for dragging and dropping models on the Checkpoints page, when enabled, all selected models will now move together with the dragged model -- Added "File Size" sorting option to the Checkpoints page +#### Checkpoint Manager +- Added "New Directory" and "Delete" options to the context menu of the tree view. +- Added new toggle for drag & drop - when enabled, all selected models will now move together with the dragged model +- Added "File Size" sorting option +- Added "Hide Empty Categories" toggle +- Added "Select All" button to the InfoBar (shown when at least one model is selected) ### Changed - The "Download Failed" message for model downloads is now persistent until dismissed ### Fixed diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 29acccc3f..2172f0296 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -129,6 +129,9 @@ ServiceManager dialogFactory [ObservableProperty] private bool dragMovesAllSelected = true; + [ObservableProperty] + private bool hideEmptyRootCategories; + public string ClearButtonText => SelectedBaseModels.Count == BaseModelOptions.Count ? Resources.Action_ClearSelection @@ -289,8 +292,7 @@ or nameof(SortConnectedModelsFirst) x ) ) - .Sort(comparerObservable) - .Bind(Models) + .SortAndBind(Models, comparerObservable) .WhenPropertyChanged(p => p.IsSelected) .Throttle(TimeSpan.FromMilliseconds(50)) .Subscribe(_ => @@ -298,9 +300,17 @@ or nameof(SortConnectedModelsFirst) NumItemsSelected = Models.Count(o => o.IsSelected); }); + var categoryFilterPredicate = Observable + .FromEventPattern(this, nameof(PropertyChanged)) + .Where(x => x.EventArgs.PropertyName is nameof(HideEmptyRootCategories)) + .Throttle(TimeSpan.FromMilliseconds(50)) + .Select(_ => (Func)FilterCategories) + .AsObservable(); + categoriesCache .Connect() .DeferUntilLoaded() + .Filter(categoryFilterPredicate) .SortAndBind( Categories, SortExpressionComparer @@ -362,6 +372,13 @@ or nameof(SortConnectedModelsFirst) true ); + settingsManager.RelayPropertyFor( + this, + vm => vm.HideEmptyRootCategories, + settings => settings.HideEmptyRootCategories, + true + ); + // make sure a sort happens OnPropertyChanged(nameof(SortConnectedModelsFirst)); } @@ -665,6 +682,12 @@ private async Task DeleteFolderAsync(object? treeViewItem) RefreshCategories(); } + [RelayCommand] + private void SelectAll() + { + Models.ForEach(x => x.IsSelected = true); + } + public async Task ImportFilesAsync(IEnumerable files, DirectoryPath destinationFolder) { if (destinationFolder.FullPath == settingsManager.ModelsDirectory) @@ -809,6 +832,13 @@ private void RefreshCategories() ) .ToList(); + foreach (var checkpointCategory in modelCategories.SelectMany(c => c.Flatten())) + { + checkpointCategory.Count = Directory + .EnumerateFileSystemEntries(checkpointCategory.Path, "*", SearchOption.AllDirectories) + .Count(x => LocalModelFile.SupportedCheckpointExtensions.Contains(Path.GetExtension(x))); + } + var rootCategory = new CheckpointCategory { Path = settingsManager.ModelsDirectory, @@ -843,13 +873,6 @@ private void RefreshCategories() previouslySelectedCategory ?? Categories.FirstOrDefault(x => x.Path == previouslySelectedCategory?.Path) ?? Categories.First(); - - foreach (var checkpointCategory in Categories.SelectMany(c => c.Flatten())) - { - checkpointCategory.Count = Directory - .EnumerateFileSystemEntries(checkpointCategory.Path, "*", SearchOption.AllDirectories) - .Count(x => LocalModelFile.SupportedCheckpointExtensions.Contains(Path.GetExtension(x))); - } } private ObservableCollection GetSubfolders(string strPath) @@ -953,4 +976,9 @@ is false ? folderPath.Contains(categoryRelativePath) : categoryRelativePath.Equals(folderPath); } + + private bool FilterCategories(CheckpointCategory category) + { + return !HideEmptyRootCategories || category is { Count: > 0 }; + } } diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 05a933739..c74b733ca 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -280,6 +280,13 @@ Label="Move All Selected Models" ToolTip.Tip="When enabled, dragging and dropping a model will also move any selected models to the drop location." IsChecked="{Binding DragMovesAllSelected, Mode=TwoWay}" /> + + + + + @@ -619,10 +626,18 @@ - @@ -106,7 +106,7 @@ VerticalAlignment="Center" FontSize="18" Foreground="{DynamicResource ThemeGreyColor}" - IsFilled="True" + IconVariant="Filled" Symbol="CloudArrowDown" /> diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml index b44d6d516..83c1d0fa0 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml @@ -24,15 +24,15 @@ diff --git a/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml index 3332c1a5a..c580af176 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml @@ -67,7 +67,7 @@ VerticalAlignment="Center" FontSize="18" Foreground="{DynamicResource ThemeGreyColor}" - IsFilled="True" + IconVariant="Filled" Symbol="CloudArrowDown" /> diff --git a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml index 1c75c8161..0aa53b84c 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml @@ -80,7 +80,7 @@ @@ -174,7 +174,7 @@ @@ -204,7 +204,7 @@ @@ -228,7 +228,7 @@ - + diff --git a/StabilityMatrix.Avalonia/Controls/Inference/StackEditableCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/StackEditableCard.axaml.cs index 3a0ea84aa..1dbaf9279 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/StackEditableCard.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/Inference/StackEditableCard.axaml.cs @@ -1,17 +1,11 @@ using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text.RegularExpressions; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; using Avalonia.LogicalTree; -using DynamicData.Binding; using FluentAvalonia.UI.Controls; -using Nito.Disposables.Internals; using StabilityMatrix.Avalonia.ViewModels.Inference; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; @@ -26,8 +20,10 @@ public class StackEditableCard : TemplatedControl private ListBox? listBoxPart; // ReSharper disable once MemberCanBePrivate.Global - public static readonly StyledProperty IsListBoxEditEnabledProperty = - AvaloniaProperty.Register("IsListBoxEditEnabled"); + public static readonly StyledProperty IsListBoxEditEnabledProperty = AvaloniaProperty.Register< + StackEditableCard, + bool + >("IsListBoxEditEnabled"); public bool IsListBoxEditEnabled { diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml index a71c8cdc5..8902d0088 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml @@ -65,7 +65,7 @@ VerticalAlignment="Center" FontSize="18" Foreground="{DynamicResource ThemeGreyColor}" - IsFilled="True" + IconVariant="Filled" Symbol="CloudArrowDown" /> diff --git a/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs b/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs index a2f4dcc15..41a69002f 100644 --- a/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs +++ b/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs @@ -1,5 +1,4 @@ using System; -using AsyncImageLoader; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; diff --git a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml index 5f156f844..2f25686b3 100644 --- a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml +++ b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml @@ -32,7 +32,7 @@ Margin="8,0" VerticalAlignment="Center" Symbol="Star" - IsFilled="True"/> + IconVariant="Filled"/> --> + diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs new file mode 100644 index 000000000..48911a44a --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs @@ -0,0 +1,7 @@ +using Avalonia.Controls.Primitives; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Controls; + +[Transient] +public class UnetModelCard : TemplatedControl; diff --git a/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs b/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs index 79449aef9..ce1cfb636 100644 --- a/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/DesignData/MockInferenceClientManager.cs @@ -53,6 +53,12 @@ public partial class MockInferenceClientManager : ObservableObject, IInferenceCl public IObservableCollection SamModels { get; } = new ObservableCollectionExtended(); + public IObservableCollection UnetModels { get; } = + new ObservableCollectionExtended(); + + public IObservableCollection ClipModels { get; } = + new ObservableCollectionExtended(); + [ObservableProperty] [NotifyPropertyChangedFor(nameof(CanUserConnect))] private bool isConnected; diff --git a/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs b/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs index 77d4ddf34..d3555d523 100644 --- a/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs +++ b/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs @@ -47,6 +47,45 @@ public static void SetupEmptyLatentSource( } } + public static void SetupEmptySd3LatentSource( + this ComfyNodeBuilder builder, + int width, + int height, + int batchSize = 1, + int? batchIndex = null + ) + { + var emptyLatent = builder.Nodes.AddTypedNode( + new ComfyNodeBuilder.EmptySD3LatentImage + { + Name = builder.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.EmptySD3LatentImage)), + BatchSize = batchSize, + Height = height, + Width = width + } + ); + + builder.Connections.Primary = emptyLatent.Output; + builder.Connections.PrimarySize = new Size(width, height); + + // If batch index is selected, add a LatentFromBatch + if (batchIndex is not null) + { + builder.Connections.Primary = builder + .Nodes.AddTypedNode( + new ComfyNodeBuilder.LatentFromBatch + { + Name = "LatentFromBatch", + Samples = builder.GetPrimaryAsLatent(), + // remote expects a 0-based index, vm is 1-based + BatchIndex = batchIndex.Value - 1, + Length = 1 + } + ) + .Output; + } + } + /// /// Setup an image as the connection /// diff --git a/StabilityMatrix.Avalonia/Extensions/InferenceProjectTypeExtensions.cs b/StabilityMatrix.Avalonia/Extensions/InferenceProjectTypeExtensions.cs index f859414bb..caf2d817e 100644 --- a/StabilityMatrix.Avalonia/Extensions/InferenceProjectTypeExtensions.cs +++ b/StabilityMatrix.Avalonia/Extensions/InferenceProjectTypeExtensions.cs @@ -3,6 +3,7 @@ using StabilityMatrix.Core.Models.Inference; namespace StabilityMatrix.Avalonia.Extensions; + public static class InferenceProjectTypeExtensions { public static Type? ToViewModelType(this InferenceProjectType type) @@ -14,6 +15,7 @@ public static class InferenceProjectTypeExtensions InferenceProjectType.Inpainting => null, InferenceProjectType.Upscale => typeof(InferenceImageUpscaleViewModel), InferenceProjectType.ImageToVideo => typeof(InferenceImageToVideoViewModel), + InferenceProjectType.FluxTextToImage => typeof(InferenceFluxTextToImageViewModel), InferenceProjectType.Unknown => null, _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; diff --git a/StabilityMatrix.Avalonia/Models/InferenceProjectDocument.cs b/StabilityMatrix.Avalonia/Models/InferenceProjectDocument.cs index 24b35bf92..dc929f3c0 100644 --- a/StabilityMatrix.Avalonia/Models/InferenceProjectDocument.cs +++ b/StabilityMatrix.Avalonia/Models/InferenceProjectDocument.cs @@ -34,6 +34,7 @@ public static InferenceProjectDocument FromLoadable(IJsonLoadableState loadableM InferenceTextToImageViewModel => InferenceProjectType.TextToImage, InferenceImageUpscaleViewModel => InferenceProjectType.Upscale, InferenceImageToVideoViewModel => InferenceProjectType.ImageToVideo, + InferenceFluxTextToImageViewModel => InferenceProjectType.FluxTextToImage }, State = loadableModel.SaveStateToJsonObject() }; diff --git a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs index 8dfd8fa0c..16775493e 100644 --- a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs @@ -48,6 +48,8 @@ public interface IInferenceClientManager : IDisposable, INotifyPropertyChanged, IObservableCollection Preprocessors { get; } IObservableCollection UltralyticsModels { get; } IObservableCollection SamModels { get; } + IObservableCollection UnetModels { get; } + IObservableCollection ClipModels { get; } Task CopyImageToInputAsync(FilePath imageFile, CancellationToken cancellationToken = default); diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index 27716ab76..0caeed753 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -130,6 +130,16 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache downloadableSamModelsSource = new(p => p.GetId()); + private readonly SourceCache unetModelsSource = new(p => p.GetId()); + + public IObservableCollection UnetModels { get; } = + new ObservableCollectionExtended(); + + private readonly SourceCache clipModelsSource = new(p => p.GetId()); + + public IObservableCollection ClipModels { get; } = + new ObservableCollectionExtended(); + public InferenceClientManager( ILogger logger, IApiFactory apiFactory, @@ -169,13 +179,13 @@ ICompletionProvider completionProvider loraModelsSource .Connect() - .Sort( + .DeferUntilLoaded() + .SortAndBind( + LoraModels, SortExpressionComparer - .Ascending(f => f.Type) - .ThenByAscending(f => f.ShortDisplayName) + .Ascending(f => f.ShortDisplayName) + .ThenByAscending(f => f.Type) ) - .DeferUntilLoaded() - .Bind(LoraModels) .Subscribe(); promptExpansionModelsSource @@ -214,6 +224,28 @@ ICompletionProvider completionProvider .Bind(SamModels) .Subscribe(); + unetModelsSource + .Connect() + .SortBy( + f => f.ShortDisplayName, + SortDirection.Ascending, + SortOptimisations.ComparesImmutableValuesOnly + ) + .DeferUntilLoaded() + .Bind(UnetModels) + .Subscribe(); + + clipModelsSource + .Connect() + .SortBy( + f => f.ShortDisplayName, + SortDirection.Ascending, + SortOptimisations.ComparesImmutableValuesOnly + ) + .DeferUntilLoaded() + .Bind(ClipModels) + .Subscribe(); + vaeModelsDefaults.AddOrUpdate(HybridModelFile.Default); vaeModelsDefaults.Connect().Or(vaeModelsSource.Connect()).Bind(VaeModels).Subscribe(); @@ -379,6 +411,24 @@ await Client.GetOptionalNodeOptionNamesAsync("Inference_Core_AIO_Preprocessor", { preprocessorsSource.EditDiff(preprocessorNames.Select(n => new ComfyAuxPreprocessor(n))); } + + // Get Unet model names from UNETLoader node + if (await Client.GetNodeOptionNamesAsync("UNETLoader", "unet_name") is { } unetModelNames) + { + unetModelsSource.EditDiff( + unetModelNames.Select(HybridModelFile.FromRemote), + HybridModelFile.Comparer + ); + } + + // Get CLIP model names from DualCLIPLoader node + if (await Client.GetNodeOptionNamesAsync("DualCLIPLoader", "clip_name1") is { } clipModelNames) + { + clipModelsSource.EditDiff( + clipModelNames.Select(HybridModelFile.FromRemote), + HybridModelFile.Comparer + ); + } } /// @@ -456,8 +506,8 @@ private void ResetSharedProperties() [ HybridModelFile.None, ..modelIndexService - .FindByModelType(SharedFolderType.Sams) - .Select(HybridModelFile.FromLocal) + .FindByModelType(SharedFolderType.Sams) + .Select(HybridModelFile.FromLocal) ]; samModelsSource.EditDiff(samModels, HybridModelFile.Comparer); @@ -466,6 +516,16 @@ private void ResetSharedProperties() ); downloadableSamModelsSource.EditDiff(downloadableSamModels, HybridModelFile.Comparer); + unetModelsSource.EditDiff( + modelIndexService.FindByModelType(SharedFolderType.Unet).Select(HybridModelFile.FromLocal), + HybridModelFile.Comparer + ); + + clipModelsSource.EditDiff( + modelIndexService.FindByModelType(SharedFolderType.CLIP).Select(HybridModelFile.FromLocal), + HybridModelFile.Comparer + ); + samplersSource.EditDiff(ComfySampler.Defaults, ComfySampler.Comparer); latentUpscalersSource.EditDiff(ComfyUpscaler.Defaults, ComfyUpscaler.Comparer); diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs index c01895be1..7235efb45 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs @@ -24,6 +24,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base; [JsonDerivedType(typeof(FaceDetailerViewModel), FaceDetailerViewModel.ModuleKey)] [JsonDerivedType(typeof(FreeUModule))] [JsonDerivedType(typeof(HiresFixModule))] +[JsonDerivedType(typeof(FluxHiresFixModule))] [JsonDerivedType(typeof(UpscalerModule))] [JsonDerivedType(typeof(ControlNetModule))] [JsonDerivedType(typeof(SaveImageModule))] diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs new file mode 100644 index 000000000..d2e96ab44 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using StabilityMatrix.Avalonia.Extensions; +using StabilityMatrix.Avalonia.Models; +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Inference.Modules; +using StabilityMatrix.Avalonia.Views.Inference; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api.Comfy; +using StabilityMatrix.Core.Services; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference; + +[View(typeof(InferenceTextToImageView), IsPersistent = true)] +[ManagedService] +[Transient] +public class InferenceFluxTextToImageViewModel : InferenceGenerationViewModelBase, IParametersLoadableState +{ + private readonly INotificationService notificationService; + private readonly IModelIndexService modelIndexService; + + [JsonIgnore] + public StackCardViewModel StackCardViewModel { get; } + + [JsonPropertyName("Modules")] + public StackEditableCardViewModel ModulesCardViewModel { get; } + + [JsonPropertyName("Model")] + public UnetModelCardViewModel ModelCardViewModel { get; } + + [JsonPropertyName("Sampler")] + public SamplerCardViewModel SamplerCardViewModel { get; } + + [JsonPropertyName("Prompt")] + public PromptCardViewModel PromptCardViewModel { get; } + + [JsonPropertyName("BatchSize")] + public BatchSizeCardViewModel BatchSizeCardViewModel { get; } + + [JsonPropertyName("Seed")] + public SeedCardViewModel SeedCardViewModel { get; } + + public InferenceFluxTextToImageViewModel( + ServiceManager vmFactory, + IInferenceClientManager inferenceClientManager, + INotificationService notificationService, + ISettingsManager settingsManager, + RunningPackageService runningPackageService + ) + : base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService) + { + this.notificationService = notificationService; + this.modelIndexService = modelIndexService; + + SeedCardViewModel = vmFactory.Get(); + SeedCardViewModel.GenerateNewSeed(); + + ModelCardViewModel = vmFactory.Get(); + + SamplerCardViewModel = vmFactory.Get(samplerCard => + { + samplerCard.IsDimensionsEnabled = true; + samplerCard.IsCfgScaleEnabled = true; + samplerCard.IsSamplerSelectionEnabled = true; + samplerCard.IsSchedulerSelectionEnabled = true; + samplerCard.DenoiseStrength = 1.0d; + samplerCard.EnableAddons = false; + samplerCard.SelectedSampler = ComfySampler.Euler; + samplerCard.SelectedScheduler = ComfyScheduler.Simple; + samplerCard.CfgScale = 3.5d; + samplerCard.Width = 1024; + samplerCard.Height = 1024; + }); + + PromptCardViewModel = vmFactory.Get(promptCard => + { + promptCard.IsNegativePromptEnabled = false; + }); + + BatchSizeCardViewModel = vmFactory.Get(); + + ModulesCardViewModel = vmFactory.Get(modulesCard => + { + modulesCard.AvailableModules = new[] + { + typeof(FluxHiresFixModule), + typeof(UpscalerModule), + typeof(SaveImageModule), + typeof(FaceDetailerModule) + }; + modulesCard.DefaultModules = new[] { typeof(FluxHiresFixModule), typeof(UpscalerModule) }; + modulesCard.InitializeDefaults(); + }); + + StackCardViewModel = vmFactory.Get(); + StackCardViewModel.AddCards( + ModelCardViewModel, + SamplerCardViewModel, + ModulesCardViewModel, + SeedCardViewModel, + BatchSizeCardViewModel + ); + } + + protected override void BuildPrompt(BuildPromptEventArgs args) + { + base.BuildPrompt(args); + + var builder = args.Builder; + + builder.Connections.Seed = args.SeedOverride switch + { + { } seed => Convert.ToUInt64(seed), + _ => Convert.ToUInt64(SeedCardViewModel.Seed) + }; + + var applyArgs = args.ToModuleApplyStepEventArgs(); + BatchSizeCardViewModel.ApplyStep(applyArgs); + ModelCardViewModel.ApplyStep(applyArgs); + + builder.SetupEmptySd3LatentSource( + SamplerCardViewModel.Width, + SamplerCardViewModel.Height, + BatchSizeCardViewModel.BatchSize, + BatchSizeCardViewModel.BatchIndex + ); + + PromptCardViewModel.ApplyStep(applyArgs); + + // Do custom Sampler setup + SamplerCardViewModel.ApplyStepsInitialFluxSampler(applyArgs); + + // Apply steps from our modules + foreach (var module in ModulesCardViewModel.Cards.Cast()) + { + module.ApplyStep(applyArgs); + } + + applyArgs.InvokeAllPreOutputActions(); + + builder.SetupOutputImage(); + } + + /// + protected override async Task GenerateImageImpl( + GenerateOverrides overrides, + CancellationToken cancellationToken + ) + { + // Validate the prompts + if (!await PromptCardViewModel.ValidatePrompts()) + return; + + if (!await ModelCardViewModel.ValidateModel()) + return; + + foreach (var module in ModulesCardViewModel.Cards.OfType()) + { + if (!module.IsEnabled) + continue; + + if (module is not IValidatableModule validatableModule) + continue; + + if (!await validatableModule.Validate()) + { + return; + } + } + + if (!await CheckClientConnectedWithPrompt() || !ClientManager.IsConnected) + return; + + // If enabled, randomize the seed + var seedCard = StackCardViewModel.GetCard(); + if (overrides is not { UseCurrentSeed: true } && seedCard.IsRandomizeEnabled) + { + seedCard.GenerateNewSeed(); + } + + var batches = BatchSizeCardViewModel.BatchCount; + + var batchArgs = new List(); + + for (var i = 0; i < batches; i++) + { + var seed = seedCard.Seed + i; + + var buildPromptArgs = new BuildPromptEventArgs { Overrides = overrides, SeedOverride = seed }; + BuildPrompt(buildPromptArgs); + + var generationArgs = new ImageGenerationEventArgs + { + Client = ClientManager.Client, + Nodes = buildPromptArgs.Builder.ToNodeDictionary(), + OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(), + Parameters = SaveStateToParameters(new GenerationParameters()), + Project = InferenceProjectDocument.FromLoadable(this), + FilesToTransfer = buildPromptArgs.FilesToTransfer, + BatchIndex = i, + // Only clear output images on the first batch + ClearOutputImages = i == 0 + }; + + batchArgs.Add(generationArgs); + } + + // Run batches + foreach (var args in batchArgs) + { + await RunGeneration(args, cancellationToken); + } + } + + public void LoadStateFromParameters(GenerationParameters parameters) + { + PromptCardViewModel.LoadStateFromParameters(parameters); + SamplerCardViewModel.LoadStateFromParameters(parameters); + ModelCardViewModel.LoadStateFromParameters(parameters); + + SeedCardViewModel.Seed = Convert.ToInt64(parameters.Seed); + + if (Math.Abs(SamplerCardViewModel.DenoiseStrength - 1.0d) > 0.01d) + { + SamplerCardViewModel.DenoiseStrength = 1.0d; + } + } + + /// + public GenerationParameters SaveStateToParameters(GenerationParameters parameters) + { + parameters = PromptCardViewModel.SaveStateToParameters(parameters); + parameters = SamplerCardViewModel.SaveStateToParameters(parameters); + parameters = ModelCardViewModel.SaveStateToParameters(parameters); + + parameters.Seed = (ulong)SeedCardViewModel.Seed; + + return parameters; + } + + // Deserialization overrides + public override void LoadStateFromJsonObject(JsonObject state, int version) + { + // For v2 and below, do migration + if (version <= 2) + { + ModulesCardViewModel.Clear(); + + // Add by default the original cards as steps - HiresFix, Upscaler + ModulesCardViewModel.AddModule(module => + { + module.IsEnabled = state.GetPropertyValueOrDefault("IsHiresFixEnabled"); + + if (state.TryGetPropertyValue("HiresSampler", out var hiresSamplerState)) + { + module + .GetCard() + .LoadStateFromJsonObject(hiresSamplerState!.AsObject()); + } + + if (state.TryGetPropertyValue("HiresUpscaler", out var hiresUpscalerState)) + { + module + .GetCard() + .LoadStateFromJsonObject(hiresUpscalerState!.AsObject()); + } + }); + + ModulesCardViewModel.AddModule(module => + { + module.IsEnabled = state.GetPropertyValueOrDefault("IsUpscaleEnabled"); + + if (state.TryGetPropertyValue("Upscaler", out var upscalerState)) + { + module + .GetCard() + .LoadStateFromJsonObject(upscalerState!.AsObject()); + } + }); + + // Add FreeU to sampler + SamplerCardViewModel.ModulesCardViewModel.AddModule(module => + { + module.IsEnabled = state.GetPropertyValueOrDefault("IsFreeUEnabled"); + }); + } + + base.LoadStateFromJsonObject(state); + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxHiresFixModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxHiresFixModule.cs new file mode 100644 index 000000000..6472ae07b --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxHiresFixModule.cs @@ -0,0 +1,68 @@ +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models.Api.Comfy; +using StabilityMatrix.Core.Models.Api.Comfy.Nodes; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules; + +[ManagedService] +[Transient] +public class FluxHiresFixModule(ServiceManager vmFactory) : HiresFixModule(vmFactory) +{ + protected override void OnApplyStep(ModuleApplyStepEventArgs e) + { + var builder = e.Builder; + + var upscaleCard = GetCard(); + var samplerCard = GetCard(); + + // Get new latent size + var hiresSize = builder.Connections.PrimarySize.WithScale(upscaleCard.Scale); + + // Select between latent upscale and normal upscale based on the upscale method + var selectedUpscaler = upscaleCard.SelectedUpscaler!.Value; + + // If upscaler selected, upscale latent image first + if (selectedUpscaler.Type != ComfyUpscalerType.None) + { + builder.Connections.Primary = builder.Group_Upscale( + builder.Nodes.GetUniqueName("HiresFix"), + builder.Connections.Primary.Unwrap(), + builder.Connections.GetDefaultVAE(), + selectedUpscaler, + hiresSize.Width, + hiresSize.Height + ); + } + + // If we need to inherit primary sampler addons, use their temp args + if (samplerCard.InheritPrimarySamplerAddons) + { + e.Temp = e.Builder.Connections.BaseSamplerTemporaryArgs ?? e.CreateTempFromBuilder(); + } + else + { + // otherwise just use new ones + e.Temp = e.CreateTempFromBuilder(); + } + + var hiresSampler = builder.Nodes.AddTypedNode( + new ComfyNodeBuilder.SamplerCustomAdvanced + { + Name = builder.Nodes.GetUniqueName("HiresFix_Sampler"), + Guider = builder.Connections.PrimaryGuider, + Noise = builder.Connections.PrimaryNoise, + Sampler = builder.Connections.PrimarySamplerNode, + Sigmas = builder.Connections.PrimarySigmas, + LatentImage = builder.GetPrimaryAsLatent() + } + ); + + // Set as primary + builder.Connections.Primary = hiresSampler.Output1; + builder.Connections.PrimarySize = hiresSize; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs index 919e4e309..0c501ee2e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs @@ -53,6 +53,9 @@ public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoa [ObservableProperty] private bool isHelpButtonTeachingTipOpen; + [ObservableProperty] + private bool isNegativePromptEnabled = true; + /// public PromptCardViewModel( ICompletionProvider completionProvider, diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index 664ab0c88..c56542b52 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -17,6 +17,7 @@ using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; +using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; using Size = System.Drawing.Size; #pragma warning disable CS0657 // Not a valid attribute location for this declaration @@ -92,6 +93,9 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo [property: DisplayName("Inherit Primary Sampler Addons")] private bool inheritPrimarySamplerAddons = true; + [ObservableProperty] + private bool enableAddons = true; + [JsonPropertyName("Modules")] public StackEditableCardViewModel ModulesCardViewModel { get; } @@ -164,6 +168,105 @@ public void ApplyStep(ModuleApplyStepEventArgs e) } } + public void ApplyStepsInitialFluxSampler(ModuleApplyStepEventArgs e) + { + // Provide temp values + e.Temp = e.CreateTempFromBuilder(); + + // Get primary as latent using vae + var primaryLatent = e.Builder.GetPrimaryAsLatent( + e.Temp.Primary!.Unwrap(), + e.Builder.Connections.GetDefaultVAE() + ); + + // Set primary sampler and scheduler + var primarySampler = SelectedSampler ?? throw new ValidationException("Sampler not selected"); + e.Builder.Connections.PrimarySampler = primarySampler; + + var primaryScheduler = SelectedScheduler ?? throw new ValidationException("Scheduler not selected"); + e.Builder.Connections.PrimaryScheduler = primaryScheduler; + + // KSamplerSelect + var kSamplerSelect = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.KSamplerSelect + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.KSamplerSelect)), + SamplerName = e.Builder.Connections.PrimarySampler?.Name! + } + ); + + e.Builder.Connections.PrimarySamplerNode = kSamplerSelect.Output; + + // Scheduler/Sigmas + var basicScheduler = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.BasicScheduler + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.BasicScheduler)), + Model = e.Builder.Connections.Base.Model.Unwrap(), + Scheduler = e.Builder.Connections.PrimaryScheduler?.Name!, + Denoise = IsDenoiseStrengthEnabled ? DenoiseStrength : 1.0d, + Steps = Steps + } + ); + + e.Builder.Connections.PrimarySigmas = basicScheduler.Output; + + // Noise + var randomNoise = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.RandomNoise + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.RandomNoise)), + NoiseSeed = e.Builder.Connections.Seed + } + ); + + e.Builder.Connections.PrimaryNoise = randomNoise.Output; + + // Guidance + var fluxGuidance = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.FluxGuidance + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.FluxGuidance)), + Conditioning = e.Builder.Connections.GetRefinerOrBaseConditioning().Positive, + Guidance = CfgScale + } + ); + + e.Builder.Connections.Base.Conditioning = new ConditioningConnections( + fluxGuidance.Output, + e.Builder.Connections.GetRefinerOrBaseConditioning().Negative + ); + + // Guider + var basicGuider = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.BasicGuider + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.BasicGuider)), + Model = e.Builder.Connections.Base.Model.Unwrap(), + Conditioning = e.Builder.Connections.GetRefinerOrBaseConditioning().Positive + } + ); + + e.Builder.Connections.PrimaryGuider = basicGuider.Output; + + // SamplerCustomAdvanced + var sampler = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.SamplerCustomAdvanced + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.SamplerCustomAdvanced)), + Guider = e.Builder.Connections.PrimaryGuider, + Noise = e.Builder.Connections.PrimaryNoise, + Sampler = e.Builder.Connections.PrimarySamplerNode, + Sigmas = e.Builder.Connections.PrimarySigmas, + LatentImage = primaryLatent + } + ); + + e.Builder.Connections.Primary = sampler.Output1; + + e.Builder.Connections.BaseSamplerTemporaryArgs = e.Temp; + } + private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) { // Get primary as latent using vae diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs new file mode 100644 index 000000000..d95bf6608 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.Json.Nodes; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Models; +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api.Comfy.Nodes; +using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference; + +[View(typeof(UnetModelCard))] +[ManagedService] +[Transient] +public partial class UnetModelCardViewModel( + IInferenceClientManager clientManager, + ServiceManager vmFactory +) : LoadableViewModelBase, IParametersLoadableState, IComfyStep +{ + [ObservableProperty] + private HybridModelFile? selectedModel; + + [ObservableProperty] + private HybridModelFile? selectedVae; + + [ObservableProperty] + private HybridModelFile? selectedClip1; + + [ObservableProperty] + private HybridModelFile? selectedClip2; + + [ObservableProperty] + private string selectedDType = "default"; + + public List WeightDTypes { get; set; } = ["default", "fp8_e4m3fn", "fp8_e5m2"]; + + public IInferenceClientManager ClientManager { get; } = clientManager; + + public async Task ValidateModel() + { + if (SelectedModel != null) + return true; + + var dialog = DialogHelper.CreateMarkdownDialog( + "Please select a model to continue.", + "No Model Selected" + ); + await dialog.ShowAsync(); + return false; + } + + public void ApplyStep(ModuleApplyStepEventArgs e) + { + var checkpointLoader = e.Nodes.AddTypedNode(GetModelLoader(e, SelectedModel!, SelectedDType)); + e.Builder.Connections.Base.Model = checkpointLoader.Output; + + var vaeLoader = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.VAELoader + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.VAELoader)), + VaeName = SelectedVae?.RelativePath ?? throw new ValidationException("No VAE Selected") + } + ); + e.Builder.Connections.Base.VAE = vaeLoader.Output; + + // DualCLIPLoader + var clipLoader = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.DualCLIPLoader + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.DualCLIPLoader)), + ClipName1 = SelectedClip1?.RelativePath ?? throw new ValidationException("No Clip1 Selected"), + ClipName2 = SelectedClip2?.RelativePath ?? throw new ValidationException("No Clip2 Selected"), + Type = "flux" + } + ); + e.Builder.Connections.Base.Clip = clipLoader.Output; + } + + private static ComfyTypedNodeBase GetModelLoader( + ModuleApplyStepEventArgs e, + HybridModelFile model, + string selectedDType + ) + { + // Simple loader for UNET + return new ComfyNodeBuilder.UNETLoader + { + Name = e.Nodes.GetUniqueName(nameof(ComfyNodeBuilder.UNETLoader)), + UnetName = model.RelativePath, + WeightDtype = selectedDType + }; + } + + /// + public override JsonObject SaveStateToJsonObject() + { + return SerializeModel( + new UnetModelCardModel + { + SelectedModelName = SelectedModel?.RelativePath, + SelectedVaeName = SelectedVae?.RelativePath, + SelectedClip1Name = SelectedClip1?.RelativePath, + SelectedClip2Name = SelectedClip2?.RelativePath + } + ); + } + + /// + public override void LoadStateFromJsonObject(JsonObject state) + { + var model = DeserializeModel(state); + + SelectedModel = model.SelectedModelName is null + ? null + : ClientManager.Models.FirstOrDefault(x => x.RelativePath == model.SelectedModelName); + + SelectedVae = model.SelectedVaeName is null + ? HybridModelFile.Default + : ClientManager.VaeModels.FirstOrDefault(x => x.RelativePath == model.SelectedVaeName); + + SelectedClip1 = model.SelectedClip1Name is null + ? HybridModelFile.None + : ClientManager.Models.FirstOrDefault(x => x.RelativePath == model.SelectedClip1Name); + + SelectedClip2 = model.SelectedClip2Name is null + ? HybridModelFile.None + : ClientManager.Models.FirstOrDefault(x => x.RelativePath == model.SelectedClip2Name); + } + + internal class UnetModelCardModel + { + public string? SelectedModelName { get; set; } + public string? SelectedVaeName { get; set; } + public string? SelectedClip1Name { get; set; } + public string? SelectedClip2Name { get; set; } + } + + /// + public void LoadStateFromParameters(GenerationParameters parameters) + { + if (parameters.ModelName is not { } paramsModelName) + return; + + var currentModels = ClientManager.Models; + + HybridModelFile? model; + + // First try hash match + if (parameters.ModelHash is not null) + { + model = currentModels.FirstOrDefault( + m => + m.Local?.ConnectedModelInfo?.Hashes.SHA256 is { } sha256 + && sha256.StartsWith(parameters.ModelHash, StringComparison.InvariantCultureIgnoreCase) + ); + } + else + { + // Name matches + model = currentModels.FirstOrDefault(m => m.RelativePath.EndsWith(paramsModelName)); + model ??= currentModels.FirstOrDefault(m => m.ShortDisplayName.StartsWith(paramsModelName)); + } + + if (model is not null) + { + SelectedModel = model; + } + } + + /// + public GenerationParameters SaveStateToParameters(GenerationParameters parameters) + { + return parameters with + { + ModelName = SelectedModel?.FileName, + ModelHash = SelectedModel?.Local?.ConnectedModelInfo?.Hashes.SHA256 + }; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs index 199ee1acb..2d20872e0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs @@ -658,6 +658,7 @@ private async Task AddTabFromFileAsync(LocalImageFile imageFile, InferenceProjec InferenceProjectType.ImageToImage => vmFactory.Get(), InferenceProjectType.ImageToVideo => vmFactory.Get(), InferenceProjectType.Upscale => vmFactory.Get(), + InferenceProjectType.FluxTextToImage => vmFactory.Get(), }; switch (vm) @@ -676,6 +677,9 @@ private async Task AddTabFromFileAsync(LocalImageFile imageFile, InferenceProjec case InferenceImageToVideoViewModel imgToVidVm: imgToVidVm.SelectImageCardViewModel.ImageSource = new ImageSource(imageFile.AbsolutePath); break; + case InferenceFluxTextToImageViewModel _: + vm.LoadImageMetadata(imageFile.AbsolutePath); + break; } Tabs.Add(vm); diff --git a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml index a248c043a..ba24ba1fe 100644 --- a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml +++ b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml @@ -75,13 +75,14 @@ Opacity="1" x:CompileBindings="False" DataContext="{Binding ElementName=Dock, Path=DataContext}" - RowDefinitions="*,Auto,Auto"> + RowDefinitions="*,Auto"> - + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/InferencePage.axaml.cs b/StabilityMatrix.Avalonia/Views/InferencePage.axaml.cs index c43c4e2a6..399a287b4 100644 --- a/StabilityMatrix.Avalonia/Views/InferencePage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/InferencePage.axaml.cs @@ -61,4 +61,9 @@ private void AddTabMenu_ImgToVideo_OnClick(object? sender, RoutedEventArgs e) { (DataContext as InferenceViewModel)!.AddTabCommand.Execute(InferenceProjectType.ImageToVideo); } + + private void AddTabMenu_FluxTextToImg_OnClick(object? sender, RoutedEventArgs e) + { + (DataContext as InferenceViewModel)!.AddTabCommand.Execute(InferenceProjectType.FluxTextToImage); + } } diff --git a/StabilityMatrix.Core/Models/Api/Comfy/ComfyScheduler.cs b/StabilityMatrix.Core/Models/Api/Comfy/ComfyScheduler.cs index b08cd13d9..2ee6d7b2a 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/ComfyScheduler.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/ComfyScheduler.cs @@ -8,6 +8,7 @@ public readonly record struct ComfyScheduler(string Name) public static ComfyScheduler Karras { get; } = new("karras"); public static ComfyScheduler Exponential { get; } = new("exponential"); public static ComfyScheduler SDTurbo { get; } = new("sd_turbo"); + public static ComfyScheduler Simple { get; } = new("simple"); private static Dictionary ConvertDict { get; } = new() @@ -16,7 +17,7 @@ public readonly record struct ComfyScheduler(string Name) [Karras.Name] = "Karras", [Exponential.Name] = "Exponential", ["sgm_uniform"] = "SGM Uniform", - ["simple"] = "Simple", + [Simple.Name] = "Simple", ["ddim_uniform"] = "DDIM Uniform", [SDTurbo.Name] = "SD Turbo" }; diff --git a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs index 5f04a3651..68310d5c7 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/NodeConnections.cs @@ -31,3 +31,7 @@ public class BboxDetectorNodeConnection : NodeConnectionBase; public class SegmDetectorNodeConnection : NodeConnectionBase; public class SamModelNodeConnection : NodeConnectionBase; + +public class GuiderNodeConnection : NodeConnectionBase; + +public class NoiseNodeConnection : NodeConnectionBase; diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index 208a6337b..465a6c6ad 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -22,6 +22,8 @@ public class ComfyNodeBuilder private static string GetRandomPrefix() => Guid.NewGuid().ToString()[..8]; + private const int MaxResolution = 16384; + private string GetUniqueName(string nameBase) { var name = $"{nameBase}_1"; @@ -375,6 +377,80 @@ public record SaveAnimatedWEBP : ComfyTypedNodeBase public required string Method { get; init; } } + public record UNETLoader : ComfyTypedNodeBase + { + public required string UnetName { get; init; } + + /// + /// possible values: "default", "fp8_e4m3fn", "fp8_e5m2" + /// + public required string WeightDtype { get; init; } + } + + public record DualCLIPLoader : ComfyTypedNodeBase + { + public required string ClipName1 { get; init; } + public required string ClipName2 { get; init; } + + /// + /// possible values: "sdxl", "sd3", "flux" + /// + public required string Type { get; init; } + } + + public record FluxGuidance : ComfyTypedNodeBase + { + public required ConditioningNodeConnection Conditioning { get; init; } + + [Range(0.0d, 100.0d)] + public required double Guidance { get; init; } + } + + public record BasicGuider : ComfyTypedNodeBase + { + public required ModelNodeConnection Model { get; init; } + public required ConditioningNodeConnection Conditioning { get; init; } + } + + public record EmptySD3LatentImage : ComfyTypedNodeBase + { + [Range(16, MaxResolution)] + public int Width { get; init; } = 1024; + + [Range(16, MaxResolution)] + public int Height { get; init; } = 1024; + + [Range(1, 4096)] + public int BatchSize { get; init; } = 1; + } + + public record RandomNoise : ComfyTypedNodeBase + { + [Range(0, int.MaxValue)] + public ulong NoiseSeed { get; init; } + } + + public record BasicScheduler : ComfyTypedNodeBase + { + public required ModelNodeConnection Model { get; init; } + public required string Scheduler { get; init; } + + [Range(1, 10000)] + public int Steps { get; init; } = 20; + + [Range(0.0d, 1.0d)] + public double Denoise { get; init; } = 1.0; + } + + public record SamplerCustomAdvanced : ComfyTypedNodeBase + { + public required NoiseNodeConnection Noise { get; init; } + public required GuiderNodeConnection Guider { get; init; } + public required SamplerNodeConnection Sampler { get; init; } + public required SigmasNodeConnection Sigmas { get; init; } + public required LatentNodeConnection LatentImage { get; init; } + } + [TypedNodeOptions( Name = "Inference_Core_PromptExpansion", RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes >= 0.2.0"] @@ -1062,6 +1138,11 @@ public PrimaryNodeConnection? Primary public ComfySampler? PrimarySampler { get; set; } public ComfyScheduler? PrimaryScheduler { get; set; } + public GuiderNodeConnection PrimaryGuider { get; set; } + public NoiseNodeConnection PrimaryNoise { get; set; } + public SigmasNodeConnection PrimarySigmas { get; set; } + public SamplerNodeConnection PrimarySamplerNode { get; set; } + public List OutputNodes { get; } = new(); public IEnumerable OutputNodeNames => OutputNodes.Select(n => n.Name); diff --git a/StabilityMatrix.Core/Models/Inference/InferenceProjectType.cs b/StabilityMatrix.Core/Models/Inference/InferenceProjectType.cs index 04ec33abb..45ee649eb 100644 --- a/StabilityMatrix.Core/Models/Inference/InferenceProjectType.cs +++ b/StabilityMatrix.Core/Models/Inference/InferenceProjectType.cs @@ -7,5 +7,6 @@ public enum InferenceProjectType ImageToImage, Inpainting, Upscale, - ImageToVideo + ImageToVideo, + FluxTextToImage } From 89dc5f6d653110c01d902a1e20a15ce268eae10d Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 3 Aug 2024 21:13:31 -0700 Subject: [PATCH 132/325] Added RemoteModels for downloadable encoder models --- .../Controls/Inference/UnetModelCard.axaml | 20 ++++---- .../Controls/Inference/UnetModelCard.axaml.cs | 50 ++++++++++++++++++- .../Services/InferenceClientManager.cs | 7 +++ .../Inference/UnetModelCardViewModel.cs | 19 +++++++ StabilityMatrix.Core/Helper/RemoteModels.cs | 40 +++++++++++++++ 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml index f944531dc..25dc61405 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml @@ -67,15 +67,15 @@ Text="{x:Static lang:Resources.Label_VAE}" TextAlignment="Left" /> - + SelectedItem="{Binding SelectedVae}" + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> - + SelectedItem="{Binding SelectedClip1}" + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> - + SelectedItem="{Binding SelectedClip2}" + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs index 48911a44a..f5f3ac064 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml.cs @@ -1,7 +1,53 @@ -using Avalonia.Controls.Primitives; +using AsyncAwaitBestPractices; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using StabilityMatrix.Avalonia.ViewModels.Inference; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models; namespace StabilityMatrix.Avalonia.Controls; [Transient] -public class UnetModelCard : TemplatedControl; +public class UnetModelCard : TemplatedControl +{ + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + var clip1ComboBox = e.NameScope.Find("Clip1ComboBox") as BetterComboBox; + clip1ComboBox!.SelectionChanged += UpscalerComboBox_OnSelectionChanged; + + var clip2ComboBox = e.NameScope.Find("Clip2ComboBox") as BetterComboBox; + clip2ComboBox!.SelectionChanged += UpscalerComboBox_OnSelectionChanged; + } + + private void UpscalerComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (e.AddedItems.Count == 0) + return; + + var item = e.AddedItems[0]; + if (item is HybridModelFile { IsDownloadable: true }) + { + // Reset the selection + e.Handled = true; + + if ( + e.RemovedItems.Count > 0 + && e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem + ) + { + (sender as BetterComboBox)!.SelectedItem = removedItem; + } + else + { + (sender as BetterComboBox)!.SelectedItem = null; + } + + // Show dialog to download the model + (DataContext as UnetModelCardViewModel)! + .RemoteDownloadCommand.ExecuteAsync(item) + .SafeFireAndForget(); + } + } +} diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index 0caeed753..d36c78f17 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -136,6 +136,7 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient new ObservableCollectionExtended(); private readonly SourceCache clipModelsSource = new(p => p.GetId()); + private readonly SourceCache downloadableClipModelsSource = new(p => p.GetId()); public IObservableCollection ClipModels { get; } = new ObservableCollectionExtended(); @@ -237,6 +238,7 @@ ICompletionProvider completionProvider clipModelsSource .Connect() + .Or(downloadableClipModelsSource.Connect()) .SortBy( f => f.ShortDisplayName, SortDirection.Ascending, @@ -526,6 +528,11 @@ private void ResetSharedProperties() HybridModelFile.Comparer ); + var downloadableClipModels = RemoteModels.ClipModelFiles.Where( + u => !clipModelsSource.Lookup(u.GetId()).HasValue + ); + downloadableClipModelsSource.EditDiff(downloadableClipModels, HybridModelFile.Comparer); + samplersSource.EditDiff(ComfySampler.Defaults, ComfySampler.Comparer); latentUpscalersSource.EditDiff(ComfyUpscaler.Defaults, ComfyUpscaler.Comparer); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs index d95bf6608..b54025494 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs @@ -5,11 +5,14 @@ using System.Text.Json.Nodes; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; @@ -44,6 +47,22 @@ ServiceManager vmFactory public IInferenceClientManager ClientManager { get; } = clientManager; + [RelayCommand] + private async Task RemoteDownload(HybridModelFile? modelFile) + { + if (modelFile?.DownloadableResource is not { } resource) + return; + + var confirmDialog = vmFactory.Get(); + confirmDialog.Resource = resource; + confirmDialog.FileName = modelFile.FileName; + + if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) + { + confirmDialog.StartDownload(); + } + } + public async Task ValidateModel() { if (SelectedModel != null) diff --git a/StabilityMatrix.Core/Helper/RemoteModels.cs b/StabilityMatrix.Core/Helper/RemoteModels.cs index b5e208c7b..197249830 100644 --- a/StabilityMatrix.Core/Helper/RemoteModels.cs +++ b/StabilityMatrix.Core/Helper/RemoteModels.cs @@ -293,4 +293,44 @@ private static RemoteResource ControlNetCommon(string path, string sha256) public static IEnumerable SamModelFiles => SamModels.Select(HybridModelFile.FromDownloadable); + + private static IEnumerable ClipModels => + [ + new RemoteResource + { + Url = new Uri( + "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/clip_l.safetensors" + ), + InfoUrl = new Uri("https://huggingface.co/comfyanonymous/flux_text_encoders"), + HashSha256 = "660c6f5b1abae9dc498ac2d21e1347d2abdb0cf6c0c0c8576cd796491d9a6cdd", + Author = "OpenAI", + LicenseType = "MIT", + ContextType = SharedFolderType.CLIP, + }, + new RemoteResource + { + Url = new Uri( + "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp16.safetensors" + ), + InfoUrl = new Uri("https://huggingface.co/comfyanonymous/flux_text_encoders"), + HashSha256 = "6e480b09fae049a72d2a8c5fbccb8d3e92febeb233bbe9dfe7256958a9167635", + Author = "Google", + LicenseType = "Apache 2.0", + ContextType = SharedFolderType.CLIP, + }, + new RemoteResource + { + Url = new Uri( + "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp8_e4m3fn.safetensors" + ), + InfoUrl = new Uri("https://huggingface.co/comfyanonymous/flux_text_encoders"), + HashSha256 = "7d330da4816157540d6bb7838bf63a0f02f573fc48ca4d8de34bb0cbfd514f09", + Author = "Google", + LicenseType = "Apache 2.0", + ContextType = SharedFolderType.CLIP, + } + ]; + + public static IEnumerable ClipModelFiles => + ClipModels.Select(HybridModelFile.FromDownloadable); } From 0770186bfe62e8de19b952d8eaf73dfcc85fe2d4 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 3 Aug 2024 23:56:06 -0700 Subject: [PATCH 133/325] Add FluxGuidanceModule for using flux fp8 model with regular TextToImage inference project --- .../ViewModels/Base/LoadableViewModelBase.cs | 1 + .../ViewModels/CheckpointsPageViewModel.cs | 14 ++++------ .../InferenceTextToImageViewModel.cs | 27 ++++++++++++++----- .../Inference/Modules/FluxGuidanceModule.cs | 19 +++++++++++++ .../Inference/SamplerCardViewModel.cs | 26 +++++++++++++++--- .../Inference/StackEditableCardViewModel.cs | 7 +++++ .../Views/CheckpointsPage.axaml | 5 ++++ 7 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxGuidanceModule.cs diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs index 7235efb45..4595e87ce 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs @@ -32,6 +32,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base; [JsonDerivedType(typeof(LoraModule))] [JsonDerivedType(typeof(LayerDiffuseModule))] [JsonDerivedType(typeof(FaceDetailerModule))] +[JsonDerivedType(typeof(FluxGuidanceModule))] public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 129e01e2d..fd614f850 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -318,6 +318,9 @@ or nameof(SortConnectedModelsFirst) ) .Subscribe(); + // make filter go + OnPropertyChanged(nameof(HideEmptyRootCategories)); + settingsManager.RelayPropertyFor( this, vm => vm.IsImportAsConnectedEnabled, @@ -380,8 +383,6 @@ or nameof(SortConnectedModelsFirst) // make sure a sort happens OnPropertyChanged(nameof(SortConnectedModelsFirst)); - // gotta do this one too i guess - OnPropertyChanged(nameof(HideEmptyRootCategories)); } public void ClearSearchQuery() @@ -852,7 +853,8 @@ private void RefreshCategories() SelectedCategory = previouslySelectedCategory ?? Categories.FirstOrDefault(x => x.Path == previouslySelectedCategory?.Path) - ?? Categories.First(); + ?? Categories.FirstOrDefault() + ?? categoriesCache.Items[0]; var dirPath = new DirectoryPath(SelectedCategory.Path); @@ -868,12 +870,6 @@ private void RefreshCategories() dirPath = dirPath.Parent; } - - // one more time for good measure?? - SelectedCategory = - previouslySelectedCategory - ?? Categories.FirstOrDefault(x => x.Path == previouslySelectedCategory?.Path) - ?? Categories.First(); } private ObservableCollection GetSubfolders(string strPath) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 462bced0c..5d042da78 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -142,13 +142,26 @@ protected override void BuildPrompt(BuildPromptEventArgs args) // Load models ModelCardViewModel.ApplyStep(applyArgs); - // Setup empty latent - builder.SetupEmptyLatentSource( - SamplerCardViewModel.Width, - SamplerCardViewModel.Height, - BatchSizeCardViewModel.BatchSize, - BatchSizeCardViewModel.IsBatchIndexEnabled ? BatchSizeCardViewModel.BatchIndex : null - ); + if (SamplerCardViewModel.ModulesCardViewModel.IsModuleEnabled()) + { + // need SD3Latent + builder.SetupEmptySd3LatentSource( + SamplerCardViewModel.Width, + SamplerCardViewModel.Height, + BatchSizeCardViewModel.BatchSize, + BatchSizeCardViewModel.IsBatchIndexEnabled ? BatchSizeCardViewModel.BatchIndex : null + ); + } + else + { + // Setup empty latent + builder.SetupEmptyLatentSource( + SamplerCardViewModel.Width, + SamplerCardViewModel.Height, + BatchSizeCardViewModel.BatchSize, + BatchSizeCardViewModel.IsBatchIndexEnabled ? BatchSizeCardViewModel.BatchIndex : null + ); + } // Prompts and loras PromptCardViewModel.ApplyStep(applyArgs); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxGuidanceModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxGuidanceModule.cs new file mode 100644 index 000000000..83f5973f5 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FluxGuidanceModule.cs @@ -0,0 +1,19 @@ +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules; + +[ManagedService] +[Transient] +public class FluxGuidanceModule : ModuleBase +{ + public FluxGuidanceModule(ServiceManager vmFactory) + : base(vmFactory) + { + Title = "Use Flux Guidance"; + } + + protected override void OnApplyStep(ModuleApplyStepEventArgs e) { } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index c56542b52..858923220 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -117,7 +117,8 @@ ServiceManager vmFactory [ typeof(FreeUModule), typeof(ControlNetModule), - typeof(LayerDiffuseModule) + typeof(LayerDiffuseModule), + typeof(FluxGuidanceModule) ]; }); } @@ -286,6 +287,23 @@ private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) var conditioning = e.Temp.Base.Conditioning.Unwrap(); var refinerConditioning = e.Temp.Refiner.Conditioning; + var useFluxGuidance = ModulesCardViewModel.IsModuleEnabled(); + + if (useFluxGuidance) + { + // Flux guidance + var fluxGuidance = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.FluxGuidance + { + Name = e.Nodes.GetUniqueName("FluxGuidance"), + Conditioning = conditioning.Positive, + Guidance = CfgScale + } + ); + + conditioning = conditioning with { Positive = fluxGuidance.Output }; + } + // Use custom sampler if SDTurbo scheduler is selected if (e.Builder.Connections.PrimaryScheduler == ComfyScheduler.SDTurbo) { @@ -320,7 +338,7 @@ private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) Model = e.Builder.Connections.Base.Model, AddNoise = true, NoiseSeed = e.Builder.Connections.Seed, - Cfg = CfgScale, + Cfg = useFluxGuidance ? 1.0d : CfgScale, Positive = conditioning.Positive, Negative = conditioning.Negative, Sampler = kSamplerSelect.Output, @@ -344,7 +362,7 @@ private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) SamplerName = primarySampler.Name, Scheduler = primaryScheduler.Name, Steps = Steps, - Cfg = CfgScale, + Cfg = useFluxGuidance ? 1.0d : CfgScale, Positive = conditioning.Positive, Negative = conditioning.Negative, LatentImage = primaryLatent, @@ -365,7 +383,7 @@ private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) AddNoise = true, NoiseSeed = e.Builder.Connections.Seed, Steps = TotalSteps, - Cfg = CfgScale, + Cfg = useFluxGuidance ? 1.0d : CfgScale, SamplerName = primarySampler.Name, Scheduler = primaryScheduler.Name, Positive = conditioning.Positive, diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs index b001862f2..c053666c1 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs @@ -117,6 +117,13 @@ private void AddModule(Type type) AddCards(card!); } + public bool IsModuleEnabled(int index = 0) + where T : ModuleBase + { + var card = Cards.OfType().ElementAtOrDefault(index); + return card is { IsEnabled: true }; + } + /*/// public override void LoadStateFromJsonObject(JsonObject state) { diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index c74b733ca..5fd0a132b 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -231,6 +231,11 @@ IconSource="Filter" VerticalAlignment="Center" Label="Filter"> + + + From 375f7c83c0df175ad8f103c6214ecf48658812c3 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 4 Aug 2024 17:27:13 -0400 Subject: [PATCH 134/325] Make ProgressReport struct readonly --- StabilityMatrix.Core/Models/Progress/ProgressReport.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs index e3f532a28..e7bd40559 100644 --- a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs +++ b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs @@ -2,7 +2,7 @@ namespace StabilityMatrix.Core.Models.Progress; -public record struct ProgressReport +public readonly record struct ProgressReport { /// /// Progress value as percentage between 0 and 1. From 43e659179343109077016ccfedb7215c4c68cdd6 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 4 Aug 2024 17:27:41 -0400 Subject: [PATCH 135/325] Add ProgressReport.ForProcessOutput --- StabilityMatrix.Core/Models/Progress/ProgressReport.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs index e7bd40559..a548cabb8 100644 --- a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs +++ b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs @@ -27,6 +27,9 @@ public readonly record struct ProgressReport public bool PrintToConsole { get; init; } = true; public double SpeedInMBps { get; init; } = 0f; + public static ProgressReport ForProcessOutput(ProcessOutput output) => + new(-1f, isIndeterminate: true) { ProcessOutput = output }; + public ProgressReport( double progress, string? title = null, From 01904b7a2ae67835ac2f9e8405e89e89a2415a91 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 4 Aug 2024 18:08:39 -0400 Subject: [PATCH 136/325] Change ExecuteSteps to take IEnumerable --- .../Models/PackageModification/IPackageModificationRunner.cs | 2 +- .../Models/PackageModification/PackageModificationRunner.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs b/StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs index d3ddeb9e1..33200c089 100644 --- a/StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs +++ b/StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs @@ -5,7 +5,7 @@ namespace StabilityMatrix.Core.Models.PackageModification; public interface IPackageModificationRunner { - Task ExecuteSteps(IReadOnlyList steps); + Task ExecuteSteps(IEnumerable steps); bool IsRunning { get; } diff --git a/StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs b/StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs index b71866568..b842e1d1d 100644 --- a/StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs +++ b/StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs @@ -5,7 +5,7 @@ namespace StabilityMatrix.Core.Models.PackageModification; public class PackageModificationRunner : IPackageModificationRunner { - public async Task ExecuteSteps(IReadOnlyList steps) + public async Task ExecuteSteps(IEnumerable steps) { IProgress progress = new Progress(report => { From 2e367ceac672b77d37566c23d9c9a9529c74da11 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 4 Aug 2024 17:01:32 -0700 Subject: [PATCH 137/325] chagenlog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4d3f929..86d1e01f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,12 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.12.0-dev.3 ### Added - Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. +#### Inference +- Added new project type, "Flux Text to Image", a Flux-native workflow for text-to-image projects +- Added support for the FP8 version of Flux in the regular Text to Image and Image to Image workflows via the "Use Flux Guidance" Sampler Addon #### Model Browser - Added AuraFlow & Flux base model types to the CivitAI model browser +- Added CLIP/Text Encoders section to HuggingFace model browser #### Checkpoint Manager - Added "New Directory" and "Delete" options to the context menu of the tree view. - Added new toggle for drag & drop - when enabled, all selected models will now move together with the dragged model From ccba3a88788cfcbfb1b68e0ee1484ebfad328753 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 4 Aug 2024 17:44:41 -0700 Subject: [PATCH 138/325] Moved generate button to its own tool --- CHANGELOG.md | 1 + .../Inference/InferenceTextToImageView.axaml | 199 ++++++++++-------- 2 files changed, 110 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86d1e01f2..57ecec618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "unet" shared model folder for ComfyUI ### Changed - The "Download Failed" message for model downloads is now persistent until dismissed +- Separated the Generate button from the prompt control in Inference so it can be moved like other controls ### Fixed - Fixed "The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp." error for Linux users - Fixed download links for IPAdapters in the HuggingFace model browser diff --git a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml index ba24ba1fe..2a53c1a7b 100644 --- a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml +++ b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml @@ -57,100 +57,119 @@ - - - - - - - - - - - - - - - - - - - + + Task ClearAllCacheCollectionsAsync(); + + /// + /// Executes a query with exception logging and collection clearing. + /// This will handle unique exceptions once keyed by string representation for each collection, + /// and throws if repeated. + /// + /// The type of collection to query. + /// The type of result to return. + /// The collection to query. + /// The task representing the query to execute. + /// The result of the query, or default value on handled exception. + Task TryQueryWithClearOnExceptionAsync( + ILiteCollectionAsync collection, + Task task + ); } diff --git a/StabilityMatrix.Core/Database/LiteDbContext.cs b/StabilityMatrix.Core/Database/LiteDbContext.cs index 4e2f07935..77af36cfe 100644 --- a/StabilityMatrix.Core/Database/LiteDbContext.cs +++ b/StabilityMatrix.Core/Database/LiteDbContext.cs @@ -1,4 +1,5 @@ -using LiteDB; +using System.Collections.Immutable; +using LiteDB; using LiteDB.Async; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -16,6 +17,9 @@ public class LiteDbContext : ILiteDbContext private readonly ISettingsManager settingsManager; private readonly DebugOptions debugOptions; + // Tracks handled exceptions + private readonly HashSet handledExceptions = []; + private readonly Lazy lazyDatabase; public LiteDatabaseAsync Database => lazyDatabase.Value; @@ -163,33 +167,8 @@ public async Task UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCach if (string.IsNullOrEmpty(cacheKey)) return null; - try - { - if (await GithubCache.FindByIdAsync(cacheKey).ConfigureAwait(false) is { } result) - { - return result; - } - } - catch (Exception e) - { - if (e is LiteException or LiteAsyncException && e.InnerException is InvalidCastException inner) - { - logger.LogWarning( - e, - "LiteDb Deserialize error while fetching GithubCacheEntry '{Inner}', cache collections will be cleared", - inner.ToString() - ); - - var githubCache = Database.GetCollection(nameof(GithubCache)); - await githubCache.DeleteAllAsync().ConfigureAwait(false); - } - else - { - throw; - } - } - - return null; + return await TryQueryWithClearOnExceptionAsync(GithubCache, GithubCache.FindByIdAsync(cacheKey)) + .ConfigureAwait(false); } public Task UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) => @@ -219,6 +198,104 @@ public async Task ClearAllCacheCollectionsAsync() } } + /// + /// Executes a query with exception logging and collection clearing. + /// This will handle unique exceptions once keyed by string representation for each collection, + /// and throws if repeated. + /// + /// The type of collection to query. + /// The type of result to return. + /// The collection to query. + /// The task representing the query to execute. + /// The result of the query, or default value on handled exception. + public async Task TryQueryWithClearOnExceptionAsync( + ILiteCollectionAsync collection, + Task task + ) + { + try + { + return await task.ConfigureAwait(false); + } + catch (Exception ex) + { + var exceptionInfo = new HandledExceptionInfo( + collection.Name, + ex.ToString(), + ex.InnerException?.ToString() + ); + + lock (handledExceptions) + { + var exceptionString = ex.InnerException is null + ? $"{ex.GetType()}" + : $"{ex.GetType()} ({ex.InnerException.GetType()})"; + + // Throw if exception was already handled previously this session + // then it's probably not a migration issue + if (handledExceptions.Contains(exceptionInfo)) + { + throw new AggregateException( + $"Repeated LiteDb error '{exceptionString}' while fetching from '{exceptionInfo.CollectionName}', previously handled", + ex + ); + } + + // Log warning for known exception types, otherwise log error + if ( + ex is LiteException or LiteAsyncException + && ex.InnerException + is InvalidCastException // GitHub cache int type changes + or ArgumentException // Unknown enum values + ) + { + logger.LogWarning( + ex, + "LiteDb error while fetching from {Name}, collection will be cleared: {Exception}", + collection.Name, + exceptionString + ); + } + else + { +#if DEBUG + throw; +#else + logger.LogError( + ex, + "LiteDb unknown error while fetching from {Name}, collection will be cleared: {Exception}", + collection.Name, + exceptionString + ); +#endif + } + + // Add to handled exceptions + handledExceptions.Add(exceptionInfo); + } + + // Clear collection + await collection.DeleteAllAsync().ConfigureAwait(false); + + // Get referenced collections + var referencedCollections = FindReferencedCollections(collection).ToArray(); + if (referencedCollections.Length > 0) + { + logger.LogWarning( + "Clearing referenced collections: [{@Names}]", + referencedCollections.Select(c => c.Name) + ); + + foreach (var referencedCollection in referencedCollections) + { + await referencedCollection.DeleteAllAsync().ConfigureAwait(false); + } + } + } + + return default; + } + public void Dispose() { if (lazyDatabase.IsValueCreated) @@ -237,4 +314,66 @@ public void Dispose() GC.SuppressFinalize(this); } + + /// + /// Recursively find all referenced collections in the entity mapper of a collection. + /// + private IEnumerable> FindReferencedCollections( + ILiteCollectionAsync collection + ) + { + var collectionNames = Database.UnderlyingDatabase.GetCollectionNames().ToArray(); + + foreach ( + var referencedCollectionName in FindReferencedCollectionNamesRecursive( + collection.EntityMapper, + [collection.Name] + ) + ) + { + yield return Database.GetCollection(referencedCollectionName); + } + + yield break; + + IEnumerable FindReferencedCollectionNamesRecursive( + EntityMapper entityMapper, + ImmutableHashSet seenCollectionNames + ) + { + foreach (var member in entityMapper.Members) + { + // Only look for members that are DBRef + if (!member.IsDbRef || member.UnderlyingType is not { } dbRefType) + continue; + + // Skip if not a collection or already seen + if (!collectionNames.Contains(dbRefType.Name) || seenCollectionNames.Contains(dbRefType.Name)) + continue; + + var memberCollection = Database.GetCollection(dbRefType.Name); + + seenCollectionNames = seenCollectionNames.Add(memberCollection.Name); + yield return memberCollection.Name; + + // Also recursively find references in the referenced collection + foreach ( + var subCollectionName in FindReferencedCollectionNamesRecursive( + memberCollection.EntityMapper, + seenCollectionNames + ) + ) + { + seenCollectionNames = seenCollectionNames.Add(subCollectionName); + yield return subCollectionName; + } + } + } + } + + private readonly record struct HandledExceptionInfo( + string CollectionName, + string Exception, + string? InnerException + ); } diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index 0efea7fc3..75d4672d3 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -105,44 +105,30 @@ private async Task LoadFromDbAsync() logger.LogInformation("Loading models from database..."); - ImmutableArray allModels = []; - try + // Handle enum deserialize exceptions from changes + var allModels = await liteDbContext + .TryQueryWithClearOnExceptionAsync( + liteDbContext.LocalModelFiles, + liteDbContext.LocalModelFiles.IncludeAll().FindAllAsync() + ) + .ConfigureAwait(false); + + if (allModels is not null) { - allModels = - [ - ..( - await liteDbContext.LocalModelFiles.IncludeAll().FindAllAsync().ConfigureAwait(false) - ) - ]; + ModelIndex = allModels.GroupBy(m => m.SharedFolderType).ToDictionary(g => g.Key, g => g.ToList()); } - catch (Exception e) + else { - // Handle enum deserialize exceptions from changes - if (e is LiteException or LiteAsyncException && e.InnerException is ArgumentException inner) - { - logger.LogWarning( - e, - "LiteDb Deserialize error while fetching LocalModelFiles '{Inner}', cache collections will be cleared", - inner.ToString() - ); - - await liteDbContext.ClearAllCacheCollectionsAsync().ConfigureAwait(false); - } - else - { - throw; - } + ModelIndex.Clear(); } - ModelIndex = allModels.GroupBy(m => m.SharedFolderType).ToDictionary(g => g.Key, g => g.ToList()); - IsDbLoaded = true; EventManager.Instance.OnModelIndexChanged(); timer.Stop(); logger.LogInformation( "Loaded {Count} models from database in {Time:F2}ms", - allModels.Length, + ModelIndex.Count, timer.Elapsed.TotalMilliseconds ); } @@ -506,33 +492,20 @@ private async Task RefreshIndexParallelCore() if (model.LatestModelInfo == null && model.HasConnectedModel) { - try - { - model.LatestModelInfo = await liteDbContext - .CivitModels.Include(m => m.ModelVersions) - .FindByIdAsync(model.ConnectedModelInfo.ModelId) - .ConfigureAwait(false); - } - catch (Exception e) + // Handle enum deserialize exceptions from changes + if ( + await liteDbContext + .TryQueryWithClearOnExceptionAsync( + liteDbContext.CivitModels, + liteDbContext + .CivitModels.Include(m => m.ModelVersions) + .FindByIdAsync(model.ConnectedModelInfo.ModelId) + ) + .ConfigureAwait(false) is + { } latestModel + ) { - // Handle enum deserialize exceptions from changes - if ( - e is LiteException or LiteAsyncException - && e.InnerException is ArgumentException inner - ) - { - logger.LogWarning( - e, - "LiteDb Deserialize error while fetching CivitModels '{Inner}', cache collections will be cleared", - inner.ToString() - ); - - await liteDbContext.ClearAllCacheCollectionsAsync().ConfigureAwait(false); - } - else - { - throw; - } + model.LatestModelInfo = latestModel; } } var list = newIndex.GetOrAdd(model.SharedFolderType); From 36f39a4d0ca70c9fa7f6544dc7a624662f7bb6e3 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 5 Aug 2024 19:13:46 -0400 Subject: [PATCH 144/325] Add LoadExternal methods for FallbackRamCachedWebImageLoader --- .../FallbackRamCachedWebImageLoader.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs b/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs index 93951249a..695db508e 100644 --- a/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs +++ b/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs @@ -80,6 +80,44 @@ await LoadFromInternalAsync(url).ConfigureAwait(false) } } + public async Task LoadExternalNoCacheAsync(string url) + { + if (await LoadDataFromExternalAsync(url).ConfigureAwait(false) is not { } externalBytes) + { + return null; + } + + using var memoryStream = new MemoryStream(externalBytes); + var bitmap = new Bitmap(memoryStream); + return bitmap; + } + + public async Task LoadExternalAsync(string url) + { + var internalOrCachedBitmap = + await LoadFromInternalAsync(url).ConfigureAwait(false) + ?? await LoadFromGlobalCache(url).ConfigureAwait(false); + + if (internalOrCachedBitmap != null) + return internalOrCachedBitmap; + + try + { + var externalBytes = await LoadDataFromExternalAsync(url).ConfigureAwait(false); + if (externalBytes == null) + return null; + + using var memoryStream = new MemoryStream(externalBytes); + var bitmap = new Bitmap(memoryStream); + await SaveToGlobalCache(url, externalBytes).ConfigureAwait(false); + return bitmap; + } + catch (Exception) + { + return null; + } + } + public void RemovePathFromCache(string filePath) { var cache = From 806b3ef87d32ed7cf9295e293a433dcab55e8eea Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 5 Aug 2024 19:17:41 -0400 Subject: [PATCH 145/325] Improved BetterAsyncImage loading and animation behavior --- CHANGELOG.md | 1 + .../VendorLabs/AsyncImage/BetterAsyncImage.cs | 208 +++++++++--------- 2 files changed, 107 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 528a45d44..ea27ee9b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Select All" button to the InfoBar (shown when at least one model is selected) - Added "unet" shared model folder for ComfyUI ### Changed +- Improved memory efficiency and speed of image rendering and animation fluidity (e.g. in Model and Output browsers) - The "Download Failed" message for model downloads is now persistent until dismissed - Separated the Generate button from the prompt control in Inference so it can be moved like other controls ### Fixed diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs index ec0cfa54f..c0eb4f707 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using AsyncImageLoader; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -28,7 +29,8 @@ public partial class BetterAsyncImage : TemplatedControl protected Image? PlaceholderPart { get; private set; } private bool _isInitialized; - private CancellationTokenSource? _tokenSource; + private CancellationTokenSource? _setSourceCts; + private CancellationTokenSource? _attachSourceAnimationCts; private AsyncImageState _state; protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -38,16 +40,40 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) ImagePart = e.NameScope.Get("PART_Image"); PlaceholderPart = e.NameScope.Get("PART_PlaceholderImage"); - _tokenSource = new CancellationTokenSource(); + // _setSourceCts = new CancellationTokenSource(); _isInitialized = true; - if (Source != null) + // In case property change didn't trigger the initial load, do it now + if (State == AsyncImageState.Unloaded && Source is not null) { SetSource(Source); } } + /// + /// Cancels the current and sets and returns a new . + /// + private CancellationTokenSource CancelAndSetNewTokenSource( + ref CancellationTokenSource? cancellationTokenSource + ) + { + var newTokenSource = new CancellationTokenSource(); + + var oldTokenSource = Interlocked.Exchange(ref cancellationTokenSource, newTokenSource); + + if (oldTokenSource is not null) + { + try + { + oldTokenSource.Cancel(); + } + catch (ObjectDisposedException) { } + } + + return newTokenSource; + } + private async void SetSource(object? source) { if (!_isInitialized) @@ -55,11 +81,9 @@ private async void SetSource(object? source) return; } - _tokenSource?.Cancel(); + var newTokenSource = CancelAndSetNewTokenSource(ref _setSourceCts); - _tokenSource = new CancellationTokenSource(); - - AttachSource(null); + // AttachSource(null, newTokenSource.Token); if (source == null) { @@ -70,7 +94,7 @@ private async void SetSource(object? source) if (Source is IImage image) { - AttachSource(image); + AttachSource(image, newTokenSource.Token); return; } @@ -82,147 +106,127 @@ private async void SetSource(object? source) var uri = Source; - if (uri != null && uri.IsAbsoluteUri) + if (!uri.IsAbsoluteUri) { - if (uri.Scheme == "http" || uri.Scheme == "https") - { - Bitmap? bitmap = null; - // Android doesn't allow network requests on the main thread, even though we are using async apis. -#if NET6_0_OR_GREATER - if (OperatingSystem.IsAndroid()) - { - await Task.Run(async () => - { - try - { - bitmap = await LoadImageAsync(uri, _tokenSource.Token); - } - catch (Exception ex) - { - await Dispatcher.UIThread.InvokeAsync(() => - { - State = AsyncImageState.Failed; - - RaiseEvent(new AsyncImageFailedEventArgs(ex)); - }); - } - }); - } - else -#endif + State = AsyncImageState.Failed; + + RaiseEvent( + new AsyncImageFailedEventArgs( + new UriFormatException($"Relative paths aren't supported. Uri:{source}") + ) + ); + + return; + } + + try + { + var bitmap = await Task.Run( + async () => { - try + // A small delay allows to cancel early if the image goes out of screen too fast (e.g. scrolling) + // The Bitmap constructor is expensive and cannot be cancelled + await Task.Delay(10, newTokenSource.Token); + + if (uri.Scheme is "http" or "https") { - bitmap = await LoadImageAsync(uri, _tokenSource.Token); + return await LoadImageAsync(uri, newTokenSource.Token); } - catch (Exception ex) - { - await Dispatcher.UIThread.InvokeAsync(() => - { - State = AsyncImageState.Failed; - RaiseEvent(new AsyncImageFailedEventArgs(ex)); - }); + if (uri.Scheme == "avares") + { + return new Bitmap(AssetLoader.Open(uri)); } - } - AttachSource(bitmap); - } - else if (uri.Scheme == "avares") - { - try - { - AttachSource(new Bitmap(AssetLoader.Open(uri))); - } - catch (Exception ex) - { - State = AsyncImageState.Failed; + if (uri.Scheme == "file" && File.Exists(uri.LocalPath)) + { + return new Bitmap(uri.LocalPath); + } - RaiseEvent(new AsyncImageFailedEventArgs(ex)); - } - } - else if (uri.Scheme == "file" && File.Exists(uri.LocalPath)) - { - // Added error handling here for local files - try - { - AttachSource(new Bitmap(uri.LocalPath)); - } - catch (Exception ex) - { - State = AsyncImageState.Failed; + throw new UriFormatException($"Uri has unsupported scheme. Uri:{source}"); + }, + CancellationToken.None + ); - RaiseEvent(new AsyncImageFailedEventArgs(ex)); - } - } - else + if (newTokenSource.IsCancellationRequested) { - RaiseEvent( - new AsyncImageFailedEventArgs( - new UriFormatException($"Uri has unsupported scheme. Uri:{source}") - ) - ); + return; } + + AttachSource(bitmap, newTokenSource.Token); } - else + catch (TaskCanceledException) { } + catch (Exception ex) { - RaiseEvent( - new AsyncImageFailedEventArgs( - new UriFormatException($"Relative paths aren't supported. Uri:{source}") - ) - ); + State = AsyncImageState.Failed; + + RaiseEvent(new AsyncImageFailedEventArgs(ex)); + } + finally + { + newTokenSource.Dispose(); } } - private void AttachSource(IImage? image) + private void AttachSource(IImage? image, CancellationToken cancellationToken) { if (ImagePart != null) { ImagePart.Source = image; } - _tokenSource?.Cancel(); - _tokenSource = new CancellationTokenSource(); + // Get new animation token source, cancel previous ones + var newAnimationCts = CancelAndSetNewTokenSource(ref _attachSourceAnimationCts); if (image == null) { State = AsyncImageState.Unloaded; - ImageTransition?.Start(ImagePart, PlaceholderPart, true, _tokenSource.Token); + ImageTransition + ?.Start(ImagePart, PlaceholderPart, true, newAnimationCts.Token) + .ContinueWith(_ => newAnimationCts.Dispose(), CancellationToken.None); } else if (image.Size != default) { State = AsyncImageState.Loaded; - ImageTransition?.Start(PlaceholderPart, ImagePart, true, _tokenSource.Token); + ImageTransition + ?.Start(PlaceholderPart, ImagePart, true, newAnimationCts.Token) + .ContinueWith(_ => newAnimationCts.Dispose(), CancellationToken.None); RaiseEvent(new RoutedEventArgs(OpenedEvent)); } } - private async Task LoadImageAsync(Uri? url, CancellationToken token) + private async Task LoadImageAsync(Uri url, CancellationToken token) { - if (await ProvideCachedResourceAsync(url, token) is { } bitmap) + /*if (await ProvideCachedResourceAsync(url, token) is { } bitmap) { return bitmap; + }*/ + + if (ImageLoader.AsyncImageLoader is not FallbackRamCachedWebImageLoader loader) + { + throw new InvalidOperationException( + "ImageLoader must be an instance of FallbackRamCachedWebImageLoader" + ); + } + + if (IsCacheEnabled) + { + return await loader.LoadExternalAsync(url.ToString()); } -#if NET6_0_OR_GREATER - using var client = new HttpClient(); + + return await loader.LoadExternalNoCacheAsync(url.ToString()); + + /*using var client = new HttpClient(); var stream = await client.GetStreamAsync(url, token).ConfigureAwait(false); await using var memoryStream = new MemoryStream(); await stream.CopyToAsync(memoryStream, token).ConfigureAwait(false); -#elif NETSTANDARD2_0 - using var client = new HttpClient(); - var response = await client.GetAsync(url, token).ConfigureAwait(false); - var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - - using var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream).ConfigureAwait(false); -#endif memoryStream.Position = 0; - return new Bitmap(memoryStream); + return new Bitmap(memoryStream);*/ } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) From fab686dd40aeab30f6031a26aa57da377e242219 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 5 Aug 2024 19:25:31 -0400 Subject: [PATCH 146/325] Add deferred loading for disabled images --- .../VendorLabs/AsyncImage/BetterAsyncImage.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs index c0eb4f707..d61e2ba06 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs @@ -40,10 +40,12 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) ImagePart = e.NameScope.Get("PART_Image"); PlaceholderPart = e.NameScope.Get("PART_PlaceholderImage"); - // _setSourceCts = new CancellationTokenSource(); - _isInitialized = true; + // Skip loading the image if we're disabled + if (!IsEffectivelyEnabled) + return; + // In case property change didn't trigger the initial load, do it now if (State == AsyncImageState.Unloaded && Source is not null) { @@ -233,10 +235,22 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang { base.OnPropertyChanged(change); + // If we're disabled, don't load the image + if (!IsEffectivelyEnabled) + return; + if (change.Property == SourceProperty) { SetSource(Source); } + else if (change.Property == IsEffectivelyEnabledProperty) + { + // When we become enabled, reload the image since it was skipped at apply template + if (change.GetNewValue() && State == AsyncImageState.Unloaded) + { + SetSource(Source); + } + } } protected virtual async Task ProvideCachedResourceAsync(Uri? imageUri, CancellationToken token) From 6fe455f025ab7473a7dd87b4f98c2d90aadd9509 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 5 Aug 2024 19:29:03 -0400 Subject: [PATCH 147/325] Refactors for BetterAsyncImage cache usages --- .../Controls/SelectableImageCard/SelectableImageButton.axaml | 1 + StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml b/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml index 402896219..bfbc310e2 100644 --- a/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml +++ b/StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml @@ -41,6 +41,7 @@ Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}"> @@ -123,6 +124,7 @@ CornerRadius="8" Width="330" Height="400" + IsCacheEnabled="True" Source="{Binding CardImage}" Stretch="UniformToFill"/> @@ -188,7 +190,7 @@ Height="22" Effect="{StaticResource ImageDropShadowEffect}" CornerRadius="11" - RenderOptions.BitmapInterpolationMode="HighQuality" + IsCacheEnabled="True" IsVisible="{Binding CivitModel.Creator.Image, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Source="{Binding CivitModel.Creator.Image}"/> Date: Mon, 5 Aug 2024 22:38:20 -0700 Subject: [PATCH 148/325] Add ModelMetadataEditorDialog for editing model metadata --- CHANGELOG.md | 1 + .../Controls/BetterContentDialog.cs | 6 + .../DesignData/DesignData.cs | 13 ++ .../Helpers/EnumHelpers.cs | 26 ++++ .../ModelMetadataEditorDialogViewModel.cs | 132 ++++++++++++++++++ .../InferenceFluxTextToImageViewModel.cs | 9 +- .../InferenceImageToVideoViewModel.cs | 14 +- .../Settings/MainSettingsViewModel.cs | 26 ++++ .../Dialogs/ModelMetadataEditorDialog.axaml | 94 +++++++++++++ .../ModelMetadataEditorDialog.axaml.cs | 14 ++ 10 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs create mode 100644 StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml create mode 100644 StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 528a45d44..45fe49a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed "The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp." error for Linux users - Fixed download links for IPAdapters in the HuggingFace model browser - Fixed potential memory leak of transient controls (Inference Prompt and Output Image Viewer) not being garbage collected due to event subscriptions +- Fixed Batch Count seeds not being recorded properly in Inference projects and image metadata ## v2.12.0-dev.2 ### Added diff --git a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs index a0c279882..b5b992d25 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs @@ -338,6 +338,12 @@ private void OnLoaded(object? sender, RoutedEventArgs? e) { faBorder!.MinWidth = MinDialogWidth; } + + if (MinDialogHeight > 0) + { + faBorder!.MinHeight = MinDialogHeight; + } + if (MaxDialogHeight > 0) { faBorder!.MaxHeight = MaxDialogHeight; diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index d2cbce9c1..dc503e0df 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -1098,6 +1098,19 @@ public static CompletionList SampleCompletionList } }; + public static ModelMetadataEditorDialogViewModel MetadataEditorDialogViewModel => + DialogFactory.Get(vm => + { + vm.ThumbnailFilePath = Assets.NoImage.ToString(); + vm.Tags = "tag1, tag2, tag3"; + vm.ModelDescription = "This is a description"; + vm.ModelName = "Model Name"; + vm.VersionName = "1.0.0"; + vm.TrainedWords = "word1, word2, word3"; + vm.ModelType = CivitModelType.Checkpoint; + vm.BaseModelType = CivitBaseModelType.Pony; + }); + public static string CurrentDirectory => Directory.GetCurrentDirectory(); public static Indexer Types { get; } = new(); diff --git a/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs b/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs new file mode 100644 index 000000000..b0d6a1bdc --- /dev/null +++ b/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api; + +namespace StabilityMatrix.Avalonia.Helpers; + +public static class EnumHelpers +{ + public static IEnumerable AllCivitPeriods { get; } = + Enum.GetValues(typeof(CivitPeriod)).Cast(); + + public static IEnumerable AllSortModes { get; } = + Enum.GetValues(typeof(CivitSortMode)).Cast(); + + public static IEnumerable AllCivitModelTypes { get; } = + Enum.GetValues(typeof(CivitModelType)) + .Cast() + .Where(t => t == CivitModelType.All || t.ConvertTo() > 0) + .OrderBy(t => t.ToString()); + + public static IEnumerable AllCivitBaseModelTypes { get; } = + Enum.GetValues(typeof(CivitBaseModelType)).Cast(); +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs new file mode 100644 index 000000000..dda8c3086 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Avalonia.Input; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using StabilityMatrix.Avalonia.Extensions; +using StabilityMatrix.Avalonia.Models; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; +using StabilityMatrix.Avalonia.Views.Dialogs; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models.Api; +using StabilityMatrix.Core.Models.Database; +using StabilityMatrix.Core.Models.FileInterfaces; + +namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; + +[View(typeof(ModelMetadataEditorDialog))] +[ManagedService] +[Transient] +public partial class ModelMetadataEditorDialogViewModel : ContentDialogViewModelBase, IDropTarget +{ + [ObservableProperty] + private List checkpointFiles = []; + + [ObservableProperty] + private string modelName = string.Empty; + + [ObservableProperty] + private string modelDescription = string.Empty; + + [ObservableProperty] + private bool isNsfw; + + [ObservableProperty] + private string tags = string.Empty; + + [ObservableProperty] + private CivitModelType modelType; + + [ObservableProperty] + private string versionName = string.Empty; + + [ObservableProperty] + private CivitBaseModelType baseModelType; + + [ObservableProperty] + private string trainedWords = string.Empty; + + [ObservableProperty] + private string thumbnailFilePath = string.Empty; + + public bool IsEditingMultipleCheckpoints => CheckpointFiles.Count > 1; + + public ModelMetadataEditorDialogViewModel() + { + if (IsEditingMultipleCheckpoints) + return; + + var firstCheckpoint = CheckpointFiles.FirstOrDefault(); + if (firstCheckpoint == null || firstCheckpoint.CheckpointFile.HasConnectedModel is false) + return; + + if ( + Enum.TryParse( + firstCheckpoint.CheckpointFile.ConnectedModelInfo.BaseModel, + out CivitBaseModelType baseModel + ) + ) + BaseModelType = baseModel; + + ModelName = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelName; + ModelDescription = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelDescription; + IsNsfw = firstCheckpoint.CheckpointFile.ConnectedModelInfo.Nsfw; + Tags = string.Join(", ", firstCheckpoint.CheckpointFile.ConnectedModelInfo.Tags); + ModelType = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelType; + VersionName = firstCheckpoint.CheckpointFile.ConnectedModelInfo.VersionName; + TrainedWords = string.Join(", ", firstCheckpoint.CheckpointFile.ConnectedModelInfo.TrainedWords); + ThumbnailFilePath = + firstCheckpoint.CheckpointFile.ConnectedModelInfo.ThumbnailImageUrl ?? Assets.NoImage.ToString(); + } + + [RelayCommand] + private async Task OpenFilePickerDialog() + { + var files = await App.StorageProvider.OpenFilePickerAsync( + new FilePickerOpenOptions + { + Title = "Select an image", + FileTypeFilter = [FilePickerFileTypes.ImageAll] + } + ); + + if (files.Count == 0) + return; + + var sourceFile = new FilePath(files[0].TryGetLocalPath()!); + + ThumbnailFilePath = sourceFile.FullPath; + } + + public void DragOver(object? sender, DragEventArgs e) + { + if ( + e.Data.GetDataFormats().Contains(DataFormats.Files) + || e.Data.GetContext() is not null + ) + { + e.Handled = true; + return; + } + + e.DragEffects = DragDropEffects.None; + } + + public void Drop(object? sender, DragEventArgs e) + { + if ( + e.Data.GetFiles() is not { } files + || files.Select(f => f.TryGetLocalPath()).FirstOrDefault() is not { } path + ) + { + return; + } + + e.Handled = true; + ThumbnailFilePath = path; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs index d2e96ab44..412101d1d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceFluxTextToImageViewModel.cs @@ -198,13 +198,20 @@ CancellationToken cancellationToken var buildPromptArgs = new BuildPromptEventArgs { Overrides = overrides, SeedOverride = seed }; BuildPrompt(buildPromptArgs); + // update seed in project for batches + var inferenceProject = InferenceProjectDocument.FromLoadable(this); + if (inferenceProject.State?["Seed"]?["Seed"] is not null) + { + inferenceProject = inferenceProject.WithState(x => x["Seed"]["Seed"] = seed); + } + var generationArgs = new ImageGenerationEventArgs { Client = ClientManager.Client, Nodes = buildPromptArgs.Builder.ToNodeDictionary(), OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(), Parameters = SaveStateToParameters(new GenerationParameters()), - Project = InferenceProjectDocument.FromLoadable(this), + Project = inferenceProject, FilesToTransfer = buildPromptArgs.FilesToTransfer, BatchIndex = i, // Only clear output images on the first batch diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs index 25cc1df7a..5981093f6 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs @@ -190,13 +190,23 @@ CancellationToken cancellationToken var buildPromptArgs = new BuildPromptEventArgs { Overrides = overrides, SeedOverride = seed }; BuildPrompt(buildPromptArgs); + // update seed in project for batches + var inferenceProject = InferenceProjectDocument.FromLoadable(this); + if (inferenceProject.State?["Seed"]?["Seed"] is not null) + { + inferenceProject = inferenceProject.WithState(x => x["Seed"]["Seed"] = seed); + } + var generationArgs = new ImageGenerationEventArgs { Client = ClientManager.Client, Nodes = buildPromptArgs.Builder.ToNodeDictionary(), OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(), - Parameters = SaveStateToParameters(new GenerationParameters()), - Project = InferenceProjectDocument.FromLoadable(this), + Parameters = SaveStateToParameters(new GenerationParameters()) with + { + Seed = Convert.ToUInt64(seed) + }, + Project = inferenceProject, FilesToTransfer = buildPromptArgs.FilesToTransfer, BatchIndex = i, // Only clear output images on the first batch diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs index 48916646e..ab5062ec4 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs @@ -44,6 +44,7 @@ using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.HardwareInfo; using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.PackageModification; @@ -934,8 +935,33 @@ private async Task DebugTrackedDownload() new CommandItem(DebugShowImageMaskEditorCommand), new CommandItem(DebugExtractImagePromptsToTxtCommand), new CommandItem(DebugShowConfirmDeleteDialogCommand), + new CommandItem(DebugShowModelMetadataEditorDialogCommand), ]; + [RelayCommand] + private async Task DebugShowModelMetadataEditorDialog() + { + var vm = dialogFactory.Get(); + vm.ThumbnailFilePath = Assets.NoImage.ToString(); + vm.Tags = "tag1, tag2, tag3"; + vm.ModelDescription = "This is a description"; + vm.ModelName = "Model Name"; + vm.VersionName = "1.0.0"; + vm.TrainedWords = "word1, word2, word3"; + vm.ModelType = CivitModelType.Checkpoint; + vm.BaseModelType = CivitBaseModelType.Pony; + + var dialog = vm.GetDialog(); + dialog.MinDialogHeight = 800; + dialog.IsPrimaryButtonEnabled = true; + dialog.IsFooterVisible = true; + dialog.PrimaryButtonText = "Save"; + dialog.DefaultButton = ContentDialogButton.Primary; + dialog.CloseButtonText = "Cancel"; + + await dialog.ShowAsync(); + } + [RelayCommand] private async Task DebugShowConfirmDeleteDialog() { diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml new file mode 100644 index 000000000..ae7f267db --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml.cs new file mode 100644 index 000000000..3e052a11c --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia.Controls; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Views.Dialogs; + +[Transient] +public partial class ModelMetadataEditorDialog : DropTargetUserControlBase +{ + public ModelMetadataEditorDialog() + { + InitializeComponent(); + } +} From 70ceeecad3dd36b3871cd67d1703685050bf6e59 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 6 Aug 2024 22:36:49 -0700 Subject: [PATCH 149/325] hook up the functionality for metadata editing --- .../DesignData/DesignData.cs | 2 + .../Extensions/EnumExtensions.cs | 27 ++++ .../CheckpointFileViewModel.cs | 139 ++++++++++++++++++ .../ViewModels/CheckpointsPageViewModel.cs | 11 ++ .../ModelMetadataEditorDialogViewModel.cs | 77 ++++++---- .../Views/CheckpointsPage.axaml | 22 ++- .../Dialogs/ModelMetadataEditorDialog.axaml | 45 ++++-- .../Models/Database/LocalModelFile.cs | 3 + 8 files changed, 279 insertions(+), 47 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Extensions/EnumExtensions.cs diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index dc503e0df..d55aa06e4 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -326,6 +326,7 @@ public static void Initialize() settingsManager, new MockModelIndexService(), notificationService, + downloadService, dialogFactory, null, new LocalModelFile @@ -356,6 +357,7 @@ public static void Initialize() settingsManager, new MockModelIndexService(), notificationService, + downloadService, dialogFactory, null, new LocalModelFile diff --git a/StabilityMatrix.Avalonia/Extensions/EnumExtensions.cs b/StabilityMatrix.Avalonia/Extensions/EnumExtensions.cs new file mode 100644 index 000000000..6a1246622 --- /dev/null +++ b/StabilityMatrix.Avalonia/Extensions/EnumExtensions.cs @@ -0,0 +1,27 @@ +using System; +using StabilityMatrix.Core.Extensions; + +namespace StabilityMatrix.Avalonia.Extensions; + +public static class EnumExtensions +{ + public static bool TryParseEnumStringValue(string? value, T defaultValue, out T result) + where T : Enum + { + result = defaultValue; + + if (value == null) + return false; + + foreach (T enumValue in Enum.GetValues(typeof(T))) + { + if (!enumValue.GetStringValue().Equals(value, StringComparison.OrdinalIgnoreCase)) + continue; + + result = enumValue; + return true; + } + + return false; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index 23f079df6..9a3e63160 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.ComponentModel; using System.IO; +using System.Linq; using System.Threading.Tasks; using Avalonia.Controls.Notifications; using Avalonia.Data; @@ -12,9 +13,12 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Dialogs; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Database; +using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; @@ -41,6 +45,7 @@ public partial class CheckpointFileViewModel : SelectableViewModelBase private readonly ISettingsManager settingsManager; private readonly IModelIndexService modelIndexService; private readonly INotificationService notificationService; + private readonly IDownloadService downloadService; private readonly ServiceManager vmFactory; private readonly ILogger logger; @@ -53,6 +58,7 @@ public CheckpointFileViewModel( ISettingsManager settingsManager, IModelIndexService modelIndexService, INotificationService notificationService, + IDownloadService downloadService, ServiceManager vmFactory, ILogger logger, LocalModelFile checkpointFile @@ -61,6 +67,7 @@ LocalModelFile checkpointFile this.settingsManager = settingsManager; this.modelIndexService = modelIndexService; this.notificationService = notificationService; + this.downloadService = downloadService; this.vmFactory = vmFactory; this.logger = logger; CheckpointFile = checkpointFile; @@ -268,6 +275,138 @@ private async Task RenameAsync() } } + [RelayCommand] + private async Task OpenMetadataEditor() + { + var vm = vmFactory.Get(vm => + { + vm.CheckpointFiles = [this]; + }); + + var dialog = vm.GetDialog(); + dialog.MinDialogHeight = 800; + dialog.MinDialogWidth = 700; + dialog.IsPrimaryButtonEnabled = true; + dialog.IsFooterVisible = true; + dialog.PrimaryButtonText = "Save"; + dialog.DefaultButton = ContentDialogButton.Primary; + dialog.CloseButtonText = "Cancel"; + + var result = await dialog.ShowAsync(); + + if (result != ContentDialogResult.Primary) + return; + + // not supported yet + if (vm.IsEditingMultipleCheckpoints) + return; + + try + { + var hasCmInfoAlready = CheckpointFile.HasConnectedModel; + var cmInfo = CheckpointFile.ConnectedModelInfo ?? new ConnectedModelInfo(); + var hasThumbnailChanged = + vm.ThumbnailFilePath + != CheckpointFile.GetPreviewImageFullPath(settingsManager.ModelsDirectory); + + cmInfo.ModelName = vm.ModelName; + cmInfo.ModelDescription = vm.ModelDescription; + cmInfo.Nsfw = vm.IsNsfw; + cmInfo.Tags = vm.Tags.Split(',').Select(x => x.Trim()).ToArray(); + cmInfo.BaseModel = vm.BaseModelType.GetStringValue(); + cmInfo.TrainedWords = string.IsNullOrWhiteSpace(vm.TrainedWords) + ? null + : vm.TrainedWords.Split(',').Select(x => x.Trim()).ToArray(); + cmInfo.ThumbnailImageUrl = vm.ThumbnailFilePath; + cmInfo.ModelType = vm.ModelType; + cmInfo.VersionName = vm.VersionName; + + var modelFilePath = new FilePath( + Path.Combine(settingsManager.ModelsDirectory, CheckpointFile.RelativePath) + ); + + IsLoading = true; + Progress = new ProgressReport(0f, "Saving metadata...", isIndeterminate: true); + + if (!hasCmInfoAlready) + { + cmInfo.Hashes = new CivitFileHashes + { + BLAKE3 = await FileHash.GetBlake3Async( + modelFilePath, + new Progress(report => + { + Progress = report with { Title = "Calculating hash..." }; + }) + ) + }; + cmInfo.Stats = new CivitModelStats(); + cmInfo.FileMetadata = new CivitFileMetadata(); + cmInfo.ImportedAt = DateTimeOffset.Now; + cmInfo.ModelId = -1; + cmInfo.VersionDescription = string.Empty; + cmInfo.VersionId = -1; + } + + var modelFileName = modelFilePath.NameWithoutExtension; + var modelFolder = + modelFilePath.Directory + ?? Path.Combine(settingsManager.ModelsDirectory, CheckpointFile.SharedFolderType.ToString()); + + await cmInfo.SaveJsonToDirectory(modelFolder, modelFileName); + + if (string.IsNullOrWhiteSpace(cmInfo.ThumbnailImageUrl)) + return; + + if (File.Exists(cmInfo.ThumbnailImageUrl) && hasThumbnailChanged) + { + var filePath = new FilePath(cmInfo.ThumbnailImageUrl); + var previewPath = new FilePath( + modelFolder, + @$"{modelFileName}.preview{Path.GetExtension(cmInfo.ThumbnailImageUrl)}" + ); + await filePath.CopyToAsync(previewPath); + } + else if (cmInfo.ThumbnailImageUrl.StartsWith("http")) + { + var imageExtension = Path.GetExtension(cmInfo.ThumbnailImageUrl).TrimStart('.'); + if (imageExtension is "jpg" or "jpeg" or "png" or "webp") + { + var imageDownloadPath = modelFilePath.Directory!.JoinFile( + $"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" + ); + + var imageTask = downloadService.DownloadToFileAsync( + cmInfo.ThumbnailImageUrl, + imageDownloadPath, + new Progress(report => + { + Progress = report with { Title = "Downloading image" }; + }) + ); + + await notificationService.TryAsync(imageTask, "Could not download preview image"); + } + } + + await modelIndexService.RefreshIndex(); + notificationService.Show( + "Metadata saved", + "Metadata has been saved successfully", + NotificationType.Success + ); + } + catch (Exception e) + { + logger.LogError(e, "Failed to save metadata"); + notificationService.Show("Failed to save metadata", e.Message, NotificationType.Error); + } + finally + { + IsLoading = false; + } + } + private long GetFileSize(string filePath) { if (!File.Exists(filePath)) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index fd614f850..834229d8e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -286,6 +286,7 @@ or nameof(SortConnectedModelsFirst) settingsManager, modelIndexService, notificationService, + downloadService, dialogFactory, logger, x @@ -510,6 +511,16 @@ private Task OnItemClick(CheckpointFileViewModel item) [RelayCommand] private async Task ShowVersionDialog(CheckpointFileViewModel item) { + if (item.CheckpointFile.HasCustomMetadata) + { + notificationService.Show( + "Cannot show version dialog", + "This model has custom metadata.", + NotificationType.Error + ); + return; + } + var model = item.CheckpointFile.LatestModelInfo; if (model is null) { diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs index dda8c3086..dcf1b22a2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Avalonia.Input; @@ -7,7 +6,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using StabilityMatrix.Avalonia.Extensions; -using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; using StabilityMatrix.Avalonia.Views.Dialogs; @@ -15,13 +13,16 @@ using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; [View(typeof(ModelMetadataEditorDialog))] [ManagedService] [Transient] -public partial class ModelMetadataEditorDialogViewModel : ContentDialogViewModelBase, IDropTarget +public partial class ModelMetadataEditorDialogViewModel(ISettingsManager settingsManager) + : ContentDialogViewModelBase, + IDropTarget { [ObservableProperty] private List checkpointFiles = []; @@ -55,22 +56,51 @@ public partial class ModelMetadataEditorDialogViewModel : ContentDialogViewModel public bool IsEditingMultipleCheckpoints => CheckpointFiles.Count > 1; - public ModelMetadataEditorDialogViewModel() + [RelayCommand] + private async Task OpenFilePickerDialog() + { + var files = await App.StorageProvider.OpenFilePickerAsync( + new FilePickerOpenOptions + { + Title = "Select an image", + FileTypeFilter = [FilePickerFileTypes.ImageAll] + } + ); + + if (files.Count == 0) + return; + + var sourceFile = new FilePath(files[0].TryGetLocalPath()!); + + ThumbnailFilePath = sourceFile.FullPath; + } + + partial void OnCheckpointFilesChanged(List value) { if (IsEditingMultipleCheckpoints) return; var firstCheckpoint = CheckpointFiles.FirstOrDefault(); - if (firstCheckpoint == null || firstCheckpoint.CheckpointFile.HasConnectedModel is false) + if (firstCheckpoint == null) return; + if (!firstCheckpoint.CheckpointFile.HasConnectedModel) + { + ModelName = firstCheckpoint.CheckpointFile.DisplayModelName; + ThumbnailFilePath = GetImagePath(firstCheckpoint.CheckpointFile); + return; + } + if ( - Enum.TryParse( + EnumExtensions.TryParseEnumStringValue( firstCheckpoint.CheckpointFile.ConnectedModelInfo.BaseModel, - out CivitBaseModelType baseModel + CivitBaseModelType.Other, + out var baseModel ) ) + { BaseModelType = baseModel; + } ModelName = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelName; ModelDescription = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelDescription; @@ -78,28 +108,21 @@ out CivitBaseModelType baseModel Tags = string.Join(", ", firstCheckpoint.CheckpointFile.ConnectedModelInfo.Tags); ModelType = firstCheckpoint.CheckpointFile.ConnectedModelInfo.ModelType; VersionName = firstCheckpoint.CheckpointFile.ConnectedModelInfo.VersionName; - TrainedWords = string.Join(", ", firstCheckpoint.CheckpointFile.ConnectedModelInfo.TrainedWords); - ThumbnailFilePath = - firstCheckpoint.CheckpointFile.ConnectedModelInfo.ThumbnailImageUrl ?? Assets.NoImage.ToString(); + TrainedWords = + firstCheckpoint.CheckpointFile.ConnectedModelInfo.TrainedWords == null + ? string.Empty + : string.Join(", ", firstCheckpoint.CheckpointFile.ConnectedModelInfo.TrainedWords); + ThumbnailFilePath = GetImagePath(firstCheckpoint.CheckpointFile); } - [RelayCommand] - private async Task OpenFilePickerDialog() + private string GetImagePath(LocalModelFile checkpointFile) { - var files = await App.StorageProvider.OpenFilePickerAsync( - new FilePickerOpenOptions - { - Title = "Select an image", - FileTypeFilter = [FilePickerFileTypes.ImageAll] - } - ); - - if (files.Count == 0) - return; - - var sourceFile = new FilePath(files[0].TryGetLocalPath()!); - - ThumbnailFilePath = sourceFile.FullPath; + return checkpointFile.HasConnectedModel + ? checkpointFile.GetPreviewImageFullPath(settingsManager.ModelsDirectory) + ?? checkpointFile.ConnectedModelInfo?.ThumbnailImageUrl + ?? Assets.NoImage.ToString() + : checkpointFile.GetPreviewImageFullPath(settingsManager.ModelsDirectory) + ?? Assets.NoImage.ToString(); } public void DragOver(object? sender, DragEventArgs e) diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 5fd0a132b..084bd1120 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -404,8 +404,19 @@ Text="{x:Static lang:Resources.Action_UpdateExistingMetadata}" IconSource="Sync" Command="{Binding FindConnectedMetadataCommand}" - CommandParameter="{StaticResource True}" - IsVisible="{Binding CheckpointFile.HasConnectedModel}" /> + CommandParameter="{StaticResource True}"> + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml index ae7f267db..34750f613 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml @@ -21,7 +21,7 @@ - + TextWrapping="Wrap" Margin="0,10,0,0" /> + + - - + - - + - - - - + - - @@ -71,12 +81,15 @@ - - + - - + + ConnectedModelInfo != null; + [BsonIgnore] + public bool HasCustomMetadata => HasConnectedModel && ConnectedModelInfo.ModelId == -1; + public string GetFullPath(string rootModelDirectory) { return Path.Combine(rootModelDirectory, RelativePath); From fa85974cfb584fb265ec949c9f23812d58b7d232 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 6 Aug 2024 22:38:42 -0700 Subject: [PATCH 150/325] chagenlog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45fe49a37..83912ab0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added AuraFlow & Flux base model types to the CivitAI model browser - Added CLIP/Text Encoders section to HuggingFace model browser #### Checkpoint Manager +- Added new Metadata Editor (accessible via the right-click menu), allowing you to create or edit metadata for models - Added "New Directory" and "Delete" options to the context menu of the tree view. - Added new toggle for drag & drop - when enabled, all selected models will now move together with the dragged model - Added "File Size" sorting option From 09bb5ad31786debfe55d4aa6a8e1cb2817444f31 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 6 Aug 2024 23:12:45 -0700 Subject: [PATCH 151/325] nullable some stuff --- .../CheckpointManager/CheckpointFileViewModel.cs | 9 +++------ StabilityMatrix.Core/Models/ConnectedModelInfo.cs | 10 +++++----- StabilityMatrix.Core/Models/Database/LocalModelFile.cs | 2 +- StabilityMatrix.Core/Services/ModelIndexService.cs | 4 ++-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index 9a3e63160..30411b042 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -99,7 +99,9 @@ private void FindOnModelBrowser() if (CheckpointFile.ConnectedModelInfo?.ModelId == null) return; - EventManager.Instance.OnNavigateAndFindCivitModelRequested(CheckpointFile.ConnectedModelInfo.ModelId); + EventManager.Instance.OnNavigateAndFindCivitModelRequested( + CheckpointFile.ConnectedModelInfo.ModelId.Value + ); } [RelayCommand] @@ -340,12 +342,7 @@ private async Task OpenMetadataEditor() }) ) }; - cmInfo.Stats = new CivitModelStats(); - cmInfo.FileMetadata = new CivitFileMetadata(); cmInfo.ImportedAt = DateTimeOffset.Now; - cmInfo.ModelId = -1; - cmInfo.VersionDescription = string.Empty; - cmInfo.VersionId = -1; } var modelFileName = modelFilePath.NameWithoutExtension; diff --git a/StabilityMatrix.Core/Models/ConnectedModelInfo.cs b/StabilityMatrix.Core/Models/ConnectedModelInfo.cs index 6d44bf236..24264d6b6 100644 --- a/StabilityMatrix.Core/Models/ConnectedModelInfo.cs +++ b/StabilityMatrix.Core/Models/ConnectedModelInfo.cs @@ -9,21 +9,21 @@ public class ConnectedModelInfo [JsonIgnore] public const string FileExtension = ".cm-info.json"; - public int ModelId { get; set; } + public int? ModelId { get; set; } public string ModelName { get; set; } public string ModelDescription { get; set; } public bool Nsfw { get; set; } public string[] Tags { get; set; } public CivitModelType ModelType { get; set; } - public int VersionId { get; set; } + public int? VersionId { get; set; } public string VersionName { get; set; } - public string VersionDescription { get; set; } + public string? VersionDescription { get; set; } public string? BaseModel { get; set; } - public CivitFileMetadata FileMetadata { get; set; } + public CivitFileMetadata? FileMetadata { get; set; } public DateTimeOffset ImportedAt { get; set; } public CivitFileHashes Hashes { get; set; } public string[]? TrainedWords { get; set; } - public CivitModelStats Stats { get; set; } + public CivitModelStats? Stats { get; set; } // User settings public string? UserTitle { get; set; } diff --git a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs index d083d7ff0..f70413892 100644 --- a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs +++ b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs @@ -151,7 +151,7 @@ public override int GetHashCode() public bool HasConnectedModel => ConnectedModelInfo != null; [BsonIgnore] - public bool HasCustomMetadata => HasConnectedModel && ConnectedModelInfo.ModelId == -1; + public bool HasCustomMetadata => HasConnectedModel && ConnectedModelInfo.ModelId == null; public string GetFullPath(string rootModelDirectory) { diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index 75d4672d3..1de0d5dbe 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -612,8 +612,8 @@ await liteDbContext.LocalModelFiles.FindAllAsync().ConfigureAwait(false) ?? [] ).ToList(); var ids = dbModels - .Where(x => x.ConnectedModelInfo != null) - .Select(x => x.ConnectedModelInfo!.ModelId) + .Where(x => x.ConnectedModelInfo?.ModelId != null) + .Select(x => x.ConnectedModelInfo!.ModelId.Value) .Distinct(); var remoteModels = (await modelFinder.FindRemoteModelsById(ids).ConfigureAwait(false)).ToList(); From b5f67bb643b037d53c14c54cb53cb0432b318283 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 6 Aug 2024 23:22:44 -0700 Subject: [PATCH 152/325] rename & stuff --- .../ViewModels/CheckpointsPageViewModel.cs | 2 +- StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml | 12 +++++++++--- .../Models/Database/LocalModelFile.cs | 3 ++- StabilityMatrix.Core/Services/ModelIndexService.cs | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 834229d8e..9cbee1308 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -511,7 +511,7 @@ private Task OnItemClick(CheckpointFileViewModel item) [RelayCommand] private async Task ShowVersionDialog(CheckpointFileViewModel item) { - if (item.CheckpointFile.HasCustomMetadata) + if (!item.CheckpointFile.HasCivitMetadata) { notificationService.Show( "Cannot show version dialog", diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 084bd1120..83d90c8c0 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -382,9 +382,15 @@ Text="{x:Static lang:Resources.Action_CopyTriggerWords}" IconSource="Copy" /> + IconSource="Find"> + + + + + + + - + diff --git a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs index f70413892..dd107fa3c 100644 --- a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs +++ b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs @@ -151,7 +151,8 @@ public override int GetHashCode() public bool HasConnectedModel => ConnectedModelInfo != null; [BsonIgnore] - public bool HasCustomMetadata => HasConnectedModel && ConnectedModelInfo.ModelId == null; + [MemberNotNullWhen(true, nameof(ConnectedModelInfo))] + public bool HasCivitMetadata => HasConnectedModel && ConnectedModelInfo.ModelId != null; public string GetFullPath(string rootModelDirectory) { diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index 1de0d5dbe..9797af906 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -490,7 +490,7 @@ private async Task RefreshIndexParallelCore() model.LatestModelInfo = dbModel.LatestModelInfo; } - if (model.LatestModelInfo == null && model.HasConnectedModel) + if (model.LatestModelInfo == null && model.HasCivitMetadata) { // Handle enum deserialize exceptions from changes if ( From 1c5ff5ce8e3cf090469dcca14fff1d0835c8bd4e Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 7 Aug 2024 21:27:10 -0400 Subject: [PATCH 153/325] Fix SkiaExtensions rendering bounds calculations --- .../Extensions/SkiaExtensions.cs | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/StabilityMatrix.Avalonia/Extensions/SkiaExtensions.cs b/StabilityMatrix.Avalonia/Extensions/SkiaExtensions.cs index 1ddcc3061..287cdce06 100644 --- a/StabilityMatrix.Avalonia/Extensions/SkiaExtensions.cs +++ b/StabilityMatrix.Avalonia/Extensions/SkiaExtensions.cs @@ -15,6 +15,8 @@ private record class SKBitmapDrawOperation : ICustomDrawOperation { public Rect Bounds { get; set; } + public Rect SourceBounds { get; set; } + public SKBitmap? Bitmap { get; init; } public void Dispose() @@ -29,23 +31,22 @@ public void Dispose() public void Render(ImmediateDrawingContext context) { if ( - Bitmap is { } bitmap + Bitmap != null && context.PlatformImpl.GetFeature() is { } leaseFeature ) { - var lease = leaseFeature.Lease(); - using (lease) - { - lease.SkCanvas.DrawBitmap( - bitmap, - SKRect.Create( - (float)Bounds.X, - (float)Bounds.Y, - (float)Bounds.Width, - (float)Bounds.Height - ) - ); - } + using var apiLease = leaseFeature.Lease(); + + apiLease.SkCanvas.DrawBitmap( + Bitmap, + SKRect.Create( + (float)SourceBounds.X, + (float)SourceBounds.Y, + (float)SourceBounds.Width, + (float)SourceBounds.Height + ), + SKRect.Create((float)Bounds.X, (float)Bounds.Y, (float)Bounds.Width, (float)Bounds.Height) + ); } } } @@ -72,10 +73,11 @@ public void Draw(DrawingContext context, Rect sourceRect, Rect destRect) { if (_drawImageOperation is null) { - _drawImageOperation = new SKBitmapDrawOperation { Bitmap = _source, }; + _drawImageOperation = new SKBitmapDrawOperation { Bitmap = _source }; } - _drawImageOperation.Bounds = sourceRect; + _drawImageOperation.SourceBounds = sourceRect; + _drawImageOperation.Bounds = destRect; context.Custom(_drawImageOperation); } } From 9275e3ebea7762ec4a4e6aa5d5bd475d791e57bd Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 7 Aug 2024 21:27:28 -0400 Subject: [PATCH 154/325] Add System.Runtime annotations for localize --- .../ExternalAnnotations/System.Runtime.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 StabilityMatrix.Avalonia/ExternalAnnotations/System.Runtime.xml diff --git a/StabilityMatrix.Avalonia/ExternalAnnotations/System.Runtime.xml b/StabilityMatrix.Avalonia/ExternalAnnotations/System.Runtime.xml new file mode 100644 index 000000000..fa6d99fb8 --- /dev/null +++ b/StabilityMatrix.Avalonia/ExternalAnnotations/System.Runtime.xml @@ -0,0 +1,12 @@ + + + + + + false + + + false + + + From c2d07a0830cb1da61c6d8b35ac9385a66e4a2f84 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 7 Aug 2024 21:28:33 -0400 Subject: [PATCH 155/325] Improved image loading and caching --- .../Controls/ImageLoaders.cs | 16 + .../AsyncImage/BetterAsyncImage.Properties.cs | 21 + .../VendorLabs/AsyncImage/BetterAsyncImage.cs | 83 ++-- .../BetterAsyncImageCacheProvider.cs | 36 ++ .../Controls/VendorLabs/Cache/CacheBase.cs | 218 +++++++---- .../Controls/VendorLabs/Cache/CacheOptions.cs | 1 + .../Controls/VendorLabs/Cache/IImageCache.cs | 38 ++ .../Controls/VendorLabs/Cache/ImageCache.cs | 56 ++- .../VendorLabs/Cache/InMemoryStorage.cs | 119 +++++- .../VendorLabs/Cache/MemoryImageCache.cs | 363 ++++++++++++++++++ .../Models/ImageCacheProviders.cs | 22 ++ StabilityMatrix.Avalonia/Program.cs | 13 + 12 files changed, 827 insertions(+), 159 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Controls/ImageLoaders.cs create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImageCacheProvider.cs create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/IImageCache.cs create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/MemoryImageCache.cs create mode 100644 StabilityMatrix.Avalonia/Models/ImageCacheProviders.cs diff --git a/StabilityMatrix.Avalonia/Controls/ImageLoaders.cs b/StabilityMatrix.Avalonia/Controls/ImageLoaders.cs new file mode 100644 index 000000000..4e83af8bd --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/ImageLoaders.cs @@ -0,0 +1,16 @@ +using System; +using System.Threading; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; + +namespace StabilityMatrix.Avalonia.Controls; + +internal static class ImageLoaders +{ + private static readonly Lazy OutputsPageImageCacheLazy = + new( + () => new MemoryImageCache { MaxMemoryCacheCount = 64 }, + LazyThreadSafetyMode.ExecutionAndPublication + ); + + public static IImageCache OutputsPageImageCache => OutputsPageImageCacheLazy.Value; +} diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs index c31f00aa5..015ff8fd6 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs @@ -1,8 +1,10 @@ using System; using Avalonia; using Avalonia.Animation; +using Avalonia.Controls; using Avalonia.Labs.Controls; using Avalonia.Media; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; namespace StabilityMatrix.Avalonia.Controls.VendorLabs; @@ -132,4 +134,23 @@ public bool IsCacheEnabled get => _isCacheEnabled; set => SetAndRaise(IsCacheEnabledProperty, ref _isCacheEnabled, value); } + + public static readonly AttachedProperty ImageCacheProperty = + AvaloniaProperty.RegisterAttached("ImageCache", null, true); + + public IImageCache? ImageCache + { + get => GetValue(ImageCacheProperty); + set => SetValue(ImageCacheProperty, value); + } + + public static void SetImageCache(Control control, IImageCache? value) + { + control.SetValue(ImageCacheProperty, value); + } + + public static IImageCache? GetImageCache(Control control) + { + return control.GetValue(ImageCacheProperty); + } } diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs index d61e2ba06..924a71644 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs @@ -1,9 +1,7 @@ using System; using System.IO; -using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using AsyncImageLoader; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -25,6 +23,8 @@ namespace StabilityMatrix.Avalonia.Controls.VendorLabs; [TemplatePart("PART_PlaceholderImage", typeof(Image))] public partial class BetterAsyncImage : TemplatedControl { + private static NLog.Logger Logger { get; } = NLog.LogManager.GetCurrentClassLogger(); + protected Image? ImagePart { get; private set; } protected Image? PlaceholderPart { get; private set; } @@ -33,6 +33,17 @@ public partial class BetterAsyncImage : TemplatedControl private CancellationTokenSource? _attachSourceAnimationCts; private AsyncImageState _state; + private readonly Lazy _instanceImageCache; + public IImageCache? InstanceImageCache => _instanceImageCache.Value; + + public BetterAsyncImage() + { + // Need to run on UI thread to get our attached property, so we cache the result + _instanceImageCache = new Lazy( + () => Dispatcher.UIThread.Invoke(() => GetImageCache(this)) + ); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); @@ -135,14 +146,19 @@ private async void SetSource(object? source) return await LoadImageAsync(uri, newTokenSource.Token); } - if (uri.Scheme == "avares") + if (uri.Scheme == "file" && File.Exists(uri.LocalPath)) { - return new Bitmap(AssetLoader.Open(uri)); + if (!IsCacheEnabled) + { + return new Bitmap(uri.LocalPath); + } + + return await LoadImageAsync(uri, newTokenSource.Token); } - if (uri.Scheme == "file" && File.Exists(uri.LocalPath)) + if (uri.Scheme == "avares") { - return new Bitmap(uri.LocalPath); + return new Bitmap(AssetLoader.Open(uri)); } throw new UriFormatException($"Uri has unsupported scheme. Uri:{source}"); @@ -150,18 +166,22 @@ private async void SetSource(object? source) CancellationToken.None ); - if (newTokenSource.IsCancellationRequested) - { - return; - } + newTokenSource.Token.ThrowIfCancellationRequested(); AttachSource(bitmap, newTokenSource.Token); } - catch (TaskCanceledException) { } + catch (OperationCanceledException ex) + { + State = AsyncImageState.Unloaded; + + // Logger.Info(ex, "Canceled loading image from {Uri}", uri); + } catch (Exception ex) { State = AsyncImageState.Failed; + // Logger.Warn(ex, "Failed to load image from {Uri} ({Ex})", uri, ex.ToString()); + RaiseEvent(new AsyncImageFailedEventArgs(ex)); } finally @@ -200,35 +220,21 @@ private void AttachSource(IImage? image, CancellationToken cancellationToken) } } - private async Task LoadImageAsync(Uri url, CancellationToken token) + private async Task LoadImageAsync(Uri url, CancellationToken cancellationToken) { - /*if (await ProvideCachedResourceAsync(url, token) is { } bitmap) - { - return bitmap; - }*/ + // Get specific cache for this control or use the default one + var cache = InstanceImageCache; - if (ImageLoader.AsyncImageLoader is not FallbackRamCachedWebImageLoader loader) - { - throw new InvalidOperationException( - "ImageLoader must be an instance of FallbackRamCachedWebImageLoader" - ); - } + cache ??= BetterAsyncImageCacheProvider.DefaultCache; + + // Logger.Trace("Using ImageCache: <{Type}:{Id}>", cache.GetType().Name, cache.GetHashCode()); if (IsCacheEnabled) { - return await loader.LoadExternalAsync(url.ToString()); + return await cache.GetWithCacheAsync(url, cancellationToken); } - return await loader.LoadExternalNoCacheAsync(url.ToString()); - - /*using var client = new HttpClient(); - var stream = await client.GetStreamAsync(url, token).ConfigureAwait(false); - - await using var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream, token).ConfigureAwait(false); - - memoryStream.Position = 0; - return new Bitmap(memoryStream);*/ + return await cache.GetAsync(url, cancellationToken); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) @@ -252,15 +258,4 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang } } } - - protected virtual async Task ProvideCachedResourceAsync(Uri? imageUri, CancellationToken token) - { - if (IsCacheEnabled && imageUri != null) - { - return await ImageCache - .Instance.GetFromCacheAsync(imageUri, cancellationToken: token) - .ConfigureAwait(false); - } - return null; - } } diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImageCacheProvider.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImageCacheProvider.cs new file mode 100644 index 000000000..2bf7ffe4d --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImageCacheProvider.cs @@ -0,0 +1,36 @@ +using System; +using System.IO; +using System.Reflection; +using System.Threading; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; + +namespace StabilityMatrix.Avalonia.Controls.VendorLabs; + +public static class BetterAsyncImageCacheProvider +{ + private static readonly Lazy DefaultCacheLazy = + new( + () => + new ImageCache( + new CacheOptions + { + // ReSharper disable twice LocalizableElement + BaseCachePath = + Assembly.GetExecutingAssembly().FullName is { } assemblyName + && !string.IsNullOrEmpty(assemblyName) + ? Path.Combine(Path.GetTempPath(), assemblyName, "Cache") + : Path.Combine(Path.GetTempPath(), "Cache"), + CacheDuration = TimeSpan.FromDays(1) + } + ), + LazyThreadSafetyMode.ExecutionAndPublication + ); + + private static IImageCache? _defaultCache; + + public static IImageCache DefaultCache + { + get => _defaultCache ?? DefaultCacheLazy.Value; + set => _defaultCache = value; + } +} diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs index a4604082c..e0ff5354a 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs @@ -30,7 +30,7 @@ private class ConcurrentRequest private string? _cacheFolderName = null; private string? _cacheFolder = null; - private InMemoryStorage? _inMemoryFileStorage = null; + protected InMemoryStorage? InMemoryFileStorage = new(); private ConcurrentDictionary _concurrentTasks = new ConcurrentDictionary(); @@ -40,12 +40,13 @@ private class ConcurrentRequest /// /// Initializes a new instance of the class. /// - protected CacheBase() + protected CacheBase(CacheOptions? options = null) { - var options = CacheOptions.Default; - CacheDuration = options?.CacheDuration ?? TimeSpan.FromDays(1); - _baseFolder = options?.BaseCachePath ?? null; - _inMemoryFileStorage = new InMemoryStorage(); + options ??= CacheOptions.Default; + _baseFolder = options.BaseCachePath ?? null; + + CacheDuration = options.CacheDuration ?? TimeSpan.FromDays(1); + MaxMemoryCacheCount = options.MaxMemoryCacheCount ?? 0; RetryCount = 1; } @@ -64,11 +65,11 @@ protected CacheBase() /// public int MaxMemoryCacheCount { - get { return _inMemoryFileStorage?.MaxItemCount ?? 0; } + get { return InMemoryFileStorage?.MaxItemCount ?? 0; } set { - if (_inMemoryFileStorage != null) - _inMemoryFileStorage.MaxItemCount = value; + if (InMemoryFileStorage != null) + InMemoryFileStorage.MaxItemCount = value; } } @@ -125,7 +126,7 @@ public async Task ClearAsync() await InternalClearAsync(files.Select(x => x as string)).ConfigureAwait(false); - _inMemoryFileStorage?.Clear(); + InMemoryFileStorage?.Clear(); } /// @@ -145,7 +146,7 @@ public Task ClearAsync(TimeSpan duration) /// awaitable task public async Task RemoveExpiredAsync(TimeSpan? duration = null) { - TimeSpan expiryDuration = duration ?? CacheDuration; + var expiryDuration = duration ?? CacheDuration; var folder = await GetCacheFolderAsync().ConfigureAwait(false); var files = Directory.EnumerateFiles(folder!); @@ -167,7 +168,7 @@ public async Task RemoveExpiredAsync(TimeSpan? duration = null) await InternalClearAsync(filesToDelete).ConfigureAwait(false); - _inMemoryFileStorage?.Clear(expiryDuration); + InMemoryFileStorage?.Clear(expiryDuration); } /// @@ -187,7 +188,7 @@ public async Task RemoveAsync(IEnumerable uriForCachedItems) var filesToDelete = new List(); var keys = new List(); - Dictionary hashDictionary = new Dictionary(); + var hashDictionary = new Dictionary(); foreach (var file in files) { @@ -196,7 +197,7 @@ public async Task RemoveAsync(IEnumerable uriForCachedItems) foreach (var uri in uriForCachedItems) { - string fileName = GetCacheFileName(uri); + var fileName = GetCacheFileName(uri); if (hashDictionary.TryGetValue(fileName, out var file)) { filesToDelete.Add(file); @@ -206,7 +207,7 @@ public async Task RemoveAsync(IEnumerable uriForCachedItems) await InternalClearAsync(filesToDelete).ConfigureAwait(false); - _inMemoryFileStorage?.Remove(keys); + InMemoryFileStorage?.Remove(keys); } /// @@ -221,7 +222,7 @@ public Task PreCacheAsync( Uri uri, bool throwOnError = false, bool storeToMemoryCache = false, - CancellationToken cancellationToken = default(CancellationToken) + CancellationToken cancellationToken = default ) { return GetItemAsync(uri, throwOnError, !storeToMemoryCache, cancellationToken); @@ -237,7 +238,7 @@ public Task PreCacheAsync( public Task GetFromCacheAsync( Uri uri, bool throwOnError = false, - CancellationToken cancellationToken = default(CancellationToken) + CancellationToken cancellationToken = default ) { return GetItemAsync(uri, throwOnError, false, cancellationToken); @@ -262,13 +263,13 @@ public async Task GetFileFromCacheAsync(Uri uri) /// an instance of Generic type public T? GetFromMemoryCache(Uri uri) { - T? instance = default(T); + var instance = default(T); - string fileName = GetCacheFileName(uri); + var fileName = GetCacheFileName(uri); - if (_inMemoryFileStorage?.MaxItemCount > 0) + if (InMemoryFileStorage?.MaxItemCount > 0) { - var msi = _inMemoryFileStorage?.GetItem(fileName, CacheDuration); + var msi = InMemoryFileStorage?.GetItem(fileName, CacheDuration); if (msi != null) { instance = msi.Item; @@ -322,10 +323,10 @@ private static string GetCacheFileName(Uri uri) private static ulong CreateHash64(string str) { - byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(str); + var utf8 = System.Text.Encoding.UTF8.GetBytes(str); - ulong value = (ulong)utf8.Length; - for (int n = 0; n < utf8.Length; n++) + var value = (ulong)utf8.Length; + for (var n = 0; n < utf8.Length; n++) { value += (ulong)utf8[n] << ((n * 5) % 56); } @@ -340,9 +341,9 @@ private static ulong CreateHash64(string str) CancellationToken cancellationToken ) { - T? instance = default(T); + var instance = default(T); - string fileName = GetCacheFileName(uri); + var fileName = GetCacheFileName(uri); _concurrentTasks.TryGetValue(fileName, out var request); // if similar request exists check if it was preCacheOnly and validate that current request isn't preCacheOnly @@ -392,11 +393,11 @@ CancellationToken cancellationToken CancellationToken cancellationToken ) { - T? instance = default(T); + var instance = default(T); - if (_inMemoryFileStorage?.MaxItemCount > 0) + if (InMemoryFileStorage?.MaxItemCount > 0) { - var msi = _inMemoryFileStorage?.GetItem(fileName, CacheDuration); + var msi = InMemoryFileStorage?.GetItem(fileName, CacheDuration); if (msi != null) { instance = msi.Item; @@ -408,59 +409,97 @@ CancellationToken cancellationToken return instance; } - var folder = await GetCacheFolderAsync().ConfigureAwait(false); - var baseFile = Path.Combine(folder!, fileName); - - bool downloadDataFile = - !File.Exists(baseFile) - || await IsFileOutOfDateAsync(baseFile, CacheDuration).ConfigureAwait(false); + var isLocal = File.Exists(uri.LocalPath); + var isRemote = uri.Scheme is "http" or "https"; - if (!File.Exists(baseFile)) + // Only cache to file for remote + if (isRemote) { - File.Create(baseFile).Dispose(); - } + var folder = await GetCacheFolderAsync().ConfigureAwait(false); + var baseFile = Path.Combine(folder!, fileName); - if (downloadDataFile) - { - uint retries = 0; - try + var downloadDataFile = + !File.Exists(baseFile) + || await IsFileOutOfDateAsync(baseFile, CacheDuration).ConfigureAwait(false); + + if (!File.Exists(baseFile)) { - while (retries < RetryCount) + File.Create(baseFile).Dispose(); + } + + if (downloadDataFile) + { + uint retries = 0; + try { - try + while (retries < RetryCount) { - instance = await DownloadFileAsync(uri, baseFile, preCacheOnly, cancellationToken) - .ConfigureAwait(false); - - if (instance != null) + try { - break; + instance = await DownloadFileAsync(uri, baseFile, preCacheOnly, cancellationToken) + .ConfigureAwait(false); + + if (instance != null) + { + break; + } } - } - catch (FileNotFoundException) { } + catch (FileNotFoundException) { } - retries++; + retries++; + } + } + catch (Exception) + { + File.Delete(baseFile); + throw; // re-throwing the exception changes the stack trace. just throw } } - catch (Exception ex) + + // Cache + if (EqualityComparer.Default.Equals(instance, default) && !preCacheOnly) { - File.Delete(baseFile); - throw; // re-throwing the exception changes the stack trace. just throw + instance = await ConvertFromAsync(baseFile).ConfigureAwait(false); + + if (InMemoryFileStorage?.MaxItemCount > 0) + { + var properties = new FileInfo(baseFile); + + var msi = new InMemoryStorageItem(fileName, properties.LastWriteTime, instance); + InMemoryFileStorage?.SetItem(msi); + } } } - - if (EqualityComparer.Default.Equals(instance, default(T)) && !preCacheOnly) + else if (isLocal) { - instance = await ConvertFromAsync(baseFile).ConfigureAwait(false); - - if (_inMemoryFileStorage?.MaxItemCount > 0) + for (var i = 0; i < RetryCount; i++) { - var properties = new FileInfo(baseFile); + cancellationToken.ThrowIfCancellationRequested(); + + try + { + instance = await LoadLocalFileAsync(uri, cancellationToken).ConfigureAwait(false); - var msi = new InMemoryStorageItem(fileName, properties.LastWriteTime, instance); - _inMemoryFileStorage?.SetItem(msi); + if (instance != null) + { + break; + } + } + catch (FileNotFoundException) { } + } + + // Cache + if (instance != null && InMemoryFileStorage?.MaxItemCount > 0) + { + var msi = new InMemoryStorageItem(fileName, DateTime.Now, instance); + InMemoryFileStorage?.SetItem(msi); } } + else + { + throw new ArgumentException("Uri scheme is not supported", nameof(uri)); + } + return instance; } @@ -471,37 +510,50 @@ CancellationToken cancellationToken CancellationToken cancellationToken ) { - T? instance = default(T); + var instance = default(T); - using (MemoryStream ms = new MemoryStream()) + using var ms = new MemoryStream(); + await using (var stream = await HttpClient.GetStreamAsync(uri, cancellationToken)) { - using (var stream = await HttpClient.GetStreamAsync(uri)) - { - stream.CopyTo(ms); - ms.Flush(); + await stream.CopyToAsync(ms, cancellationToken); + await ms.FlushAsync(cancellationToken); - ms.Position = 0; + ms.Position = 0; - using (var fs = File.Open(baseFile, FileMode.OpenOrCreate, FileAccess.Write)) - { - ms.CopyTo(fs); + await using (var fs = File.Open(baseFile, FileMode.OpenOrCreate, FileAccess.Write)) + { + await ms.CopyToAsync(fs, cancellationToken); - fs.Flush(); + await fs.FlushAsync(cancellationToken); - ms.Position = 0; - } + ms.Position = 0; } + } - // if its pre-cache we aren't looking to load items in memory - if (!preCacheOnly) - { - instance = await ConvertFromAsync(ms).ConfigureAwait(false); - } + // if its pre-cache we aren't looking to load items in memory + if (!preCacheOnly) + { + instance = await ConvertFromAsync(ms).ConfigureAwait(false); } return instance; } + private async Task LoadLocalFileAsync(Uri uri, CancellationToken cancellationToken) + { + using var ms = new MemoryStream(); + + await using (var stream = File.Open(uri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + await stream.CopyToAsync(ms, cancellationToken); + await ms.FlushAsync(cancellationToken); + } + + ms.Position = 0; + + return await ConvertFromAsync(ms).ConfigureAwait(false); + } + private async Task InternalClearAsync(IEnumerable files) { foreach (var file in files) @@ -530,7 +582,9 @@ private async Task ForceInitialiseAsync() await _cacheFolderSemaphore.WaitAsync().ConfigureAwait(false); - _inMemoryFileStorage = new InMemoryStorage(); + var currentMaxItemCount = InMemoryFileStorage?.MaxItemCount ?? 0; + + InMemoryFileStorage = new InMemoryStorage { MaxItemCount = currentMaxItemCount }; if (_baseFolder == null) { diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs index a07ca33c1..243f65399 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs @@ -15,4 +15,5 @@ public static void SetDefault(CacheOptions defaultCacheOptions) public string? BaseCachePath { get; set; } public TimeSpan? CacheDuration { get; set; } + public int? MaxMemoryCacheCount { get; set; } } diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/IImageCache.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/IImageCache.cs new file mode 100644 index 000000000..ed727a570 --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/IImageCache.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media; + +namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; + +public interface IImageCache +{ + /// + /// Assures that item represented by Uri is cached. + /// + /// Uri of the item + /// instance of + /// Awaitable Task + Task PreCacheAsync(Uri uri, CancellationToken cancellationToken = default); + + /// + /// Retrieves item represented by Uri locally or by downloading, does not cache the item. + /// + /// Uri of the item. + /// instance of + /// an instance of Generic type + Task GetAsync(Uri uri, CancellationToken cancellationToken = default); + + /// + /// Retrieves item represented by Uri from the cache. + /// If the item is not found in the cache, it downloads and saves before returning it to the caller. + /// + /// Uri of the item. + /// instance of + /// an instance of Generic type + Task GetWithCacheAsync(Uri uri, CancellationToken cancellationToken = default); + + int ClearMemoryCache(); + + int ClearMemoryCache(DateTime olderThan); +} diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs index 5582b071f..f60dddb0c 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs @@ -1,6 +1,8 @@ using System; using System.IO; +using System.Threading; using System.Threading.Tasks; +using Avalonia.Media; using Avalonia.Media.Imaging; namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; @@ -8,19 +10,8 @@ namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; /// /// Provides methods and tools to cache images in a folder /// -internal class ImageCache : CacheBase +internal class ImageCache(CacheOptions? options = null) : CacheBase(options), IImageCache { - /// - /// Private singleton field. - /// - [ThreadStatic] - private static ImageCache? _instance; - - /// - /// Gets public singleton property. - /// - public static ImageCache Instance => _instance ?? (_instance = new ImageCache()); - /// /// Creates a bitmap from a stream /// @@ -57,7 +48,7 @@ protected override async Task ConvertFromAsync(string baseFile) /// option to mark uninitialized file as expired /// bool indicate whether file has expired or not protected override async Task IsFileOutOfDateAsync( - string file, + string? file, TimeSpan duration, bool treatNullFileAsOutOfDate = true ) @@ -73,4 +64,43 @@ protected override async Task IsFileOutOfDateAsync( || DateTime.Now.Subtract(File.GetLastAccessTime(file)) > duration || DateTime.Now.Subtract(File.GetLastWriteTime(file)) > duration; } + + public Task PreCacheAsync(Uri uri, CancellationToken cancellationToken = default) + { + return PreCacheAsync(uri, true, true, cancellationToken); + } + + public async Task GetAsync(Uri uri, CancellationToken cancellationToken = default) + { + return await GetFromCacheAsync(uri, false, cancellationToken).ConfigureAwait(false); + } + + public async Task GetWithCacheAsync(Uri uri, CancellationToken cancellationToken = default) + { + return await GetFromCacheAsync(uri, true, cancellationToken).ConfigureAwait(false); + } + + public int ClearMemoryCache() + { + var count = InMemoryFileStorage?.Count ?? 0; + + if (count > 0) + { + InMemoryFileStorage!.Clear(); + } + + return count; + } + + public int ClearMemoryCache(DateTime olderThan) + { + var count = InMemoryFileStorage?.Count ?? 0; + + if (count > 0) + { + InMemoryFileStorage!.Clear(olderThan); + } + + return count; + } } diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs index 597f0dc06..a4fddd6c8 100644 --- a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs @@ -5,7 +5,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; +using KGySoft.CoreLibraries; +using StabilityMatrix.Core.Helper.Cache; namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; @@ -15,17 +19,18 @@ namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; /// T defines the type of item stored public class InMemoryStorage { + private readonly Dictionary>> _inMemoryStorage = new(); + private readonly LinkedList> _lruList = []; + private int _maxItemCount; - private ConcurrentDictionary> _inMemoryStorage = - new ConcurrentDictionary>(); - private object _settingMaxItemCountLocker = new object(); + private object _settingMaxItemCountLocker = new(); /// /// Gets or sets the maximum count of Items that can be stored in this InMemoryStorage instance. /// public int MaxItemCount { - get { return _maxItemCount; } + get => _maxItemCount; set { if (_maxItemCount == value) @@ -42,29 +47,48 @@ public int MaxItemCount } } + public int Count => _inMemoryStorage.Count; + /// /// Clears all items stored in memory /// + [MethodImpl(MethodImplOptions.Synchronized)] public void Clear() { _inMemoryStorage.Clear(); + _lruList.Clear(); } /// /// Clears items stored in memory based on duration passed /// /// TimeSpan to identify expired items + [MethodImpl(MethodImplOptions.Synchronized)] public void Clear(TimeSpan duration) { - var expirationDate = DateTime.Now.Subtract(duration); - - var itemsToRemove = _inMemoryStorage - .Where(kvp => kvp.Value.LastUpdated <= expirationDate) - .Select(kvp => kvp.Key); + Clear(DateTime.Now.Subtract(duration)); + } - if (itemsToRemove.Any()) + /// + /// Clears items stored in memory based on duration passed + /// + [MethodImpl(MethodImplOptions.Synchronized)] + public void Clear(DateTime expirationDate) + { + foreach (var (key, node) in _inMemoryStorage) { - Remove(itemsToRemove); + if (string.IsNullOrWhiteSpace(key)) + { + continue; + } + + var item = node.Value; + if (item.LastUpdated > expirationDate) + { + continue; + } + + Remove(key); } } @@ -72,6 +96,7 @@ public void Clear(TimeSpan duration) /// Remove items based on provided keys /// /// identified of the in-memory storage item + [MethodImpl(MethodImplOptions.Synchronized)] public void Remove(IEnumerable keys) { foreach (var key in keys) @@ -81,14 +106,25 @@ public void Remove(IEnumerable keys) continue; } - _inMemoryStorage.TryRemove(key, out _); + Remove(key); } } + [MethodImpl(MethodImplOptions.Synchronized)] + public void Remove(string key) + { + if (!_inMemoryStorage.TryGetValue(key, out var node)) + return; + + _lruList.Remove(node); + _inMemoryStorage.Remove(key); + } + /// /// Add new item to in-memory storage /// /// item to be stored + [MethodImpl(MethodImplOptions.Synchronized)] public void SetItem(InMemoryStorageItem item) { if (MaxItemCount == 0) @@ -96,9 +132,20 @@ public void SetItem(InMemoryStorageItem item) return; } - _inMemoryStorage[item.Id] = item; + if (_inMemoryStorage.TryGetValue(item.Id, out var node)) + { + _lruList.Remove(node); + } + else if (_inMemoryStorage.Count >= MaxItemCount) + { + RemoveFirst(); + } + + var newNode = new LinkedListNode>(item); + _lruList.AddLast(newNode); + _inMemoryStorage[item.Id] = newNode; - // ensure max limit is maintained. trim older entries first + /*// ensure max limit is maintained. trim older entries first if (_inMemoryStorage.Count > MaxItemCount) { var itemsToRemove = _inMemoryStorage @@ -106,7 +153,7 @@ public void SetItem(InMemoryStorageItem item) .Take(_inMemoryStorage.Count - MaxItemCount) .Select(kvp => kvp.Key); Remove(itemsToRemove); - } + }*/ } /// @@ -115,23 +162,55 @@ public void SetItem(InMemoryStorageItem item) /// id of the in-memory storage item /// timespan denoting expiration /// Valid item if not out of date or return null if out of date or item does not exist + [MethodImpl(MethodImplOptions.Synchronized)] public InMemoryStorageItem? GetItem(string id, TimeSpan duration) { - if (!_inMemoryStorage.TryGetValue(id, out var tempItem)) + if (!_inMemoryStorage.TryGetValue(id, out var node)) { return null; } var expirationDate = DateTime.Now.Subtract(duration); - if (tempItem.LastUpdated > expirationDate) + if (node.Value.LastUpdated <= expirationDate) { - return tempItem; + Remove(id); + return null; } - _inMemoryStorage.TryRemove(id, out _); + _lruList.Remove(node); + _lruList.AddLast(node); + + return node.Value; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public InMemoryStorageItem? GetItem(string id) + { + if (!_inMemoryStorage.TryGetValue(id, out var node)) + { + return null; + } + + var value = node.Value; + + _lruList.Remove(node); + _lruList.AddLast(node); + + return value; + } + + private void RemoveFirst() + { + // Remove from LRUPriority + var node = _lruList.First; + _lruList.RemoveFirst(); + + if (node == null) + return; - return null; + // Remove from cache + _inMemoryStorage.Remove(node.Value.Id); } private void EnsureStorageBounds(int maxCount) diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/MemoryImageCache.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/MemoryImageCache.cs new file mode 100644 index 000000000..be3f17530 --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/MemoryImageCache.cs @@ -0,0 +1,363 @@ +// Parts of this file was taken from Windows Community Toolkit CacheBase implementation +// https://github.com/CommunityToolkit/WindowsCommunityToolkit/blob/main/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using SkiaSharp; +using StabilityMatrix.Avalonia.Extensions; + +namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; + +internal class MemoryImageCache : IImageCache +{ + private class ConcurrentRequest + { + public Task? Task { get; init; } + } + + private readonly InMemoryStorage? _inMemoryFileStorage = new(); + + private readonly ConcurrentDictionary _concurrentTasks = new(); + + private HttpClient? _httpClient; + + /// + /// Gets or sets the life duration of every cache entry. + /// + public TimeSpan CacheDuration { get; set; } = TimeSpan.FromMinutes(10); + + /// + /// Gets or sets the number of retries trying to ensure the file is cached. + /// + public uint RetryCount { get; set; } = 1; + + /// + /// Gets or sets max in-memory item storage count + /// + public int MaxMemoryCacheCount + { + get => _inMemoryFileStorage?.MaxItemCount ?? 0; + set + { + if (_inMemoryFileStorage != null) + _inMemoryFileStorage.MaxItemCount = value; + } + } + + /// + /// Gets instance of + /// + protected HttpClient HttpClient + { + get + { + if (_httpClient == null) + { + var messageHandler = new HttpClientHandler(); + + _httpClient = new HttpClient(messageHandler); + } + + return _httpClient; + } + } + + /// + /// Initializes FileCache and provides root folder and cache folder name + /// + /// Folder that is used as root for cache + /// Cache folder name + /// instance of + /// awaitable task + public virtual async Task InitializeAsync( + string? folder = null, + string? folderName = null, + HttpMessageHandler? httpMessageHandler = null + ) + { + if (httpMessageHandler != null) + { + _httpClient = new HttpClient(httpMessageHandler); + } + } + + /// + /// Clears all files in the cache + /// + public void Clear() + { + _inMemoryFileStorage?.Clear(); + } + + /// + /// Removes cached images that have expired + /// + /// Optional timespan to compute whether file has expired or not. If no value is supplied, is used. + public void ClearExpired(TimeSpan? duration = null) + { + var expiryDuration = duration ?? CacheDuration; + + _inMemoryFileStorage?.Clear(expiryDuration); + } + + /// + /// Removed items based on uri list passed + /// + /// Enumerable uri list + /// awaitable Task + public void Remove(IEnumerable uriForCachedItems) + { + _inMemoryFileStorage?.Remove(uriForCachedItems.Select(GetCacheFileName)); + } + + /// + /// Assures that item represented by Uri is cached. + /// + /// Uri of the item + /// Indicates whether or not exception should be thrown if item cannot be cached + /// Indicates if item should be loaded into the in-memory storage + /// instance of + /// Awaitable Task + public Task PreCacheAsync(Uri uri, CancellationToken cancellationToken = default) + { + return GetWithCacheAsync(uri, cancellationToken); + } + + /// + /// Retrieves item represented by Uri from the in-memory cache if it exists and is not out of date. If item is not found or is out of date, default instance of the generic type is returned. + /// + /// Uri of the item. + /// an instance of Generic type + public IImage? GetFromMemoryCache(Uri uri) + { + var fileName = GetCacheFileName(uri); + + if (_inMemoryFileStorage?.MaxItemCount > 0) + { + var msi = _inMemoryFileStorage?.GetItem(fileName, CacheDuration); + if (msi != null) + { + return msi.Item; + } + } + + return null; + } + + private static string GetCacheFileName(Uri uri) + { + return CreateHash64(uri.ToString()).ToString(); + } + + private static ulong CreateHash64(string str) + { + var utf8 = System.Text.Encoding.UTF8.GetBytes(str); + + var value = (ulong)utf8.Length; + for (var n = 0; n < utf8.Length; n++) + { + value += (ulong)utf8[n] << ((n * 5) % 56); + } + + return value; + } + + public async Task GetAsync(Uri uri, CancellationToken cancellationToken) + { + IImage? instance = null; + + for (var i = 0; i < RetryCount; i++) + { + try + { + // Local + if (File.Exists(uri.LocalPath)) + { + instance = LoadLocalImageWithSkia(uri); + } + // Remote + else + { + instance = await DownloadImageAsync(uri, cancellationToken).ConfigureAwait(false); + } + + if (instance != null) + { + break; + } + } + catch (FileNotFoundException) { } + } + + return instance; + } + + public async Task GetWithCacheAsync(Uri uri, CancellationToken cancellationToken) + { + IImage? instance = null; + + var fileName = GetCacheFileName(uri); + _concurrentTasks.TryGetValue(fileName, out var request); + + if (request != null) + { + if (request.Task != null) + await request.Task.ConfigureAwait(false); + request = null; + } + + if (request == null) + { + request = new ConcurrentRequest + { + Task = GetItemWithCacheAsync(uri, fileName, cancellationToken), + }; + + _concurrentTasks[fileName] = request; + } + + try + { + if (request.Task != null) + { + instance = await request.Task.ConfigureAwait(false); + } + } + finally + { + _concurrentTasks.TryRemove(fileName, out _); + } + + return instance; + } + + public int ClearMemoryCache() + { + var count = _inMemoryFileStorage?.Count ?? 0; + + if (count > 0) + { + _inMemoryFileStorage!.Clear(); + } + + return count; + } + + public int ClearMemoryCache(DateTime olderThan) + { + var count = _inMemoryFileStorage?.Count ?? 0; + + if (count > 0) + { + _inMemoryFileStorage!.Clear(olderThan); + } + + return count; + } + + private async Task GetItemWithCacheAsync( + Uri uri, + string cacheKey, + CancellationToken cancellationToken + ) + { + IImage? instance = null; + + if (_inMemoryFileStorage?.MaxItemCount > 0) + { + var msi = _inMemoryFileStorage?.GetItem(cacheKey, CacheDuration); + if (msi != null) + { + instance = msi.Item; + } + } + + if (instance != null) + { + return instance; + } + + var isLocal = File.Exists(uri.LocalPath); + + for (var i = 0; i < RetryCount; i++) + { + try + { + if (isLocal) + { + instance = LoadLocalImageWithSkia(uri); + } + else + { + instance = await DownloadImageAsync(uri, cancellationToken).ConfigureAwait(false); + } + + if (instance != null) + { + break; + } + } + catch (FileNotFoundException) { } + } + + // Cache the item + if (instance != null && _inMemoryFileStorage?.MaxItemCount > 0) + { + var msi = new InMemoryStorageItem(cacheKey, DateTime.Now, instance); + _inMemoryFileStorage?.SetItem(msi); + } + + return instance; + } + + private static async Task LoadLocalImageAsync(Uri uri, CancellationToken cancellationToken) + { + using var ms = new MemoryStream(); + + await using (var stream = File.Open(uri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + await stream.CopyToAsync(ms, cancellationToken); + await ms.FlushAsync(cancellationToken); + } + + ms.Position = 0; + + var image = new Bitmap(ms); + return image; + } + + private static IImage? LoadLocalImageWithSkia(Uri uri) + { + using var skFileStream = new SKFileStream(uri.LocalPath); + + return SKBitmap.Decode(skFileStream).ToAvaloniaImage(); + } + + private async Task DownloadImageAsync(Uri uri, CancellationToken cancellationToken) + { + using var ms = new MemoryStream(); + + await using (var stream = await HttpClient.GetStreamAsync(uri, cancellationToken)) + { + await stream.CopyToAsync(ms, cancellationToken); + await ms.FlushAsync(cancellationToken); + } + + ms.Position = 0; + + var image = new Bitmap(ms); + return image; + } +} diff --git a/StabilityMatrix.Avalonia/Models/ImageCacheProviders.cs b/StabilityMatrix.Avalonia/Models/ImageCacheProviders.cs new file mode 100644 index 000000000..4f1b7470f --- /dev/null +++ b/StabilityMatrix.Avalonia/Models/ImageCacheProviders.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; + +namespace StabilityMatrix.Avalonia.Models; + +public static class ImageCacheProviders +{ + private static readonly Lazy OutputsPageImageCacheLazy = + new( + () => + new MemoryImageCache + { + CacheDuration = TimeSpan.FromMinutes(10), + MaxMemoryCacheCount = 50, + RetryCount = 2 + }, + LazyThreadSafetyMode.ExecutionAndPublication + ); + + public static IImageCache OutputsPageImageCache => OutputsPageImageCacheLazy.Value; +} diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 9e24a160f..203d039e8 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -20,6 +20,8 @@ using Projektanker.Icons.Avalonia.FontAwesome; using Semver; using Sentry; +using StabilityMatrix.Avalonia.Controls.VendorLabs; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels.Dialogs; @@ -143,9 +145,20 @@ public static void Main(string[] args) internal static void SetupAvaloniaApp() { IconProvider.Current.Register(); + // Use our custom image loader for custom local load error handling ImageLoader.AsyncImageLoader.Dispose(); ImageLoader.AsyncImageLoader = new FallbackRamCachedWebImageLoader(); + + // Setup BetterAsyncImage cache provider + BetterAsyncImageCacheProvider.DefaultCache = new ImageCache( + new CacheOptions + { + BaseCachePath = Path.Combine(Path.GetTempPath(), "StabilityMatrix", "Cache"), + CacheDuration = TimeSpan.FromDays(1), + MaxMemoryCacheCount = 100 + } + ); } // Avalonia configuration, don't remove; also used by visual designer. From 1aa180177d642844f181a7899b08dd8041ca7951 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 7 Aug 2024 21:29:09 -0400 Subject: [PATCH 156/325] Add custom image cache for outputs page --- .../ViewModels/OutputsPageViewModel.cs | 14 ++++++++++++++ StabilityMatrix.Avalonia/Views/OutputsPage.axaml | 2 ++ 2 files changed, 16 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs index 84ac281d0..bb8179ef4 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs @@ -21,6 +21,8 @@ using Microsoft.Extensions.Logging; using Nito.Disposables.Internals; using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Controls.VendorLabs; +using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache; using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Languages; @@ -197,6 +199,18 @@ protected override void OnInitialLoaded() GetOutputs(path); } + public override void OnUnloaded() + { + base.OnUnloaded(); + + logger.LogTrace("OutputsPageViewModel Unloaded"); + + logger.LogTrace("Clearing memory cache"); + var items = ImageLoaders.OutputsPageImageCache.ClearMemoryCache(); + + logger.LogTrace("Cleared {Items} items from memory cache", items); + } + partial void OnSelectedCategoryChanged(TreeViewDirectory? oldValue, TreeViewDirectory? newValue) { if (oldValue == newValue || oldValue == null || newValue == null) diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml index 2311e33fb..ac87523a6 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml @@ -14,6 +14,7 @@ xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" + xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs" d:DataContext="{x:Static mocks:DesignData.OutputsPageViewModel}" d:DesignHeight="650" d:DesignWidth="800" @@ -178,6 +179,7 @@ Date: Wed, 7 Aug 2024 18:36:23 -0700 Subject: [PATCH 157/325] Fix swarm args not working properly --- StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 32ca92eb2..3f4fece3b 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -280,7 +280,7 @@ void HandleConsoleOutput(ProcessOutput s) dotnetProcess = await prerequisiteHelper .RunDotnet( - args: [Path.Combine(releaseFolder, dllName), arguments.TrimEnd()], + args: $"\"{Path.Combine(releaseFolder, dllName)}\" {arguments.TrimEnd()}", workingDirectory: installedPackagePath, envVars: aspEnvVars, onProcessOutput: HandleConsoleOutput, From 63edcfeb398352522713f9c31c12ba43fbff7f34 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 7 Aug 2024 19:19:05 -0700 Subject: [PATCH 158/325] fix model poof if save without changing anything & delete existing preview image if exist --- StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs | 6 ++++++ .../CheckpointManager/CheckpointFileViewModel.cs | 9 +++++++++ .../Dialogs/ModelMetadataEditorDialogViewModel.cs | 6 ++++-- .../Views/Dialogs/ModelMetadataEditorDialog.axaml | 4 ++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs b/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs index b0d6a1bdc..9d037ed45 100644 --- a/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs +++ b/StabilityMatrix.Avalonia/Helpers/EnumHelpers.cs @@ -21,6 +21,12 @@ public static class EnumHelpers .Where(t => t == CivitModelType.All || t.ConvertTo() > 0) .OrderBy(t => t.ToString()); + public static IEnumerable MetadataEditorCivitModelTypes { get; } = + Enum.GetValues(typeof(CivitModelType)).Cast().OrderBy(t => t.ToString()); + public static IEnumerable AllCivitBaseModelTypes { get; } = Enum.GetValues(typeof(CivitBaseModelType)).Cast(); + + public static IEnumerable MetadataEditorCivitBaseModelTypes { get; } = + AllCivitBaseModelTypes.Where(x => x != CivitBaseModelType.All); } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index 30411b042..57fec5b75 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -357,6 +357,15 @@ private async Task OpenMetadataEditor() if (File.Exists(cmInfo.ThumbnailImageUrl) && hasThumbnailChanged) { + // delete existing preview image + var existingPreviewPath = CheckpointFile.GetPreviewImageFullPath( + settingsManager.ModelsDirectory + ); + if (existingPreviewPath != null && File.Exists(existingPreviewPath)) + { + File.Delete(existingPreviewPath); + } + var filePath = new FilePath(cmInfo.ThumbnailImageUrl); var previewPath = new FilePath( modelFolder, diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs index dcf1b22a2..7cada73d2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelMetadataEditorDialogViewModel.cs @@ -40,13 +40,13 @@ public partial class ModelMetadataEditorDialogViewModel(ISettingsManager setting private string tags = string.Empty; [ObservableProperty] - private CivitModelType modelType; + private CivitModelType modelType = CivitModelType.Other; [ObservableProperty] private string versionName = string.Empty; [ObservableProperty] - private CivitBaseModelType baseModelType; + private CivitBaseModelType baseModelType = CivitBaseModelType.Other; [ObservableProperty] private string trainedWords = string.Empty; @@ -88,6 +88,8 @@ partial void OnCheckpointFilesChanged(List value) { ModelName = firstCheckpoint.CheckpointFile.DisplayModelName; ThumbnailFilePath = GetImagePath(firstCheckpoint.CheckpointFile); + BaseModelType = CivitBaseModelType.Other; + ModelType = CivitModelType.Other; return; } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml index 34750f613..3e4427ec7 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ModelMetadataEditorDialog.axaml @@ -62,7 +62,7 @@ From 1cc0bda73cf27da9e0dcb5b701b5c3663a5839a5 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 7 Aug 2024 19:27:56 -0700 Subject: [PATCH 159/325] no civit for u --- StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 83d90c8c0..113c363b7 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -394,8 +394,14 @@ + IconSource="Link"> + + + + + + + Date: Wed, 7 Aug 2024 22:50:39 -0400 Subject: [PATCH 160/325] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea27ee9b2..1c6b8f2e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Select All" button to the InfoBar (shown when at least one model is selected) - Added "unet" shared model folder for ComfyUI ### Changed -- Improved memory efficiency and speed of image rendering and animation fluidity (e.g. in Model and Output browsers) +- Optimized image loading across the app, with loading speed now up to 4x faster for local images, and up to 17x faster for remote images +- Image loading in the Outputs page now uses native memory management for ~2x less peak memory usage, and will release memory more quickly when switching away from the Outputs page or scrolling images out of view +- Improved animation fluidity of image rendering while scrolling quickly across large collections (e.g. Outputs, Model Browser) - The "Download Failed" message for model downloads is now persistent until dismissed - Separated the Generate button from the prompt control in Inference so it can be moved like other controls ### Fixed From f9ca85447103c5b7e9bd9a81fbe438a054e687e3 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 7 Aug 2024 20:45:40 -0700 Subject: [PATCH 161/325] chagenlog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83912ab0e..e6ff09d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,12 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed incorrect IPAdapter download links in the HuggingFace model browser - Fixed potential memory leak of transient controls (Inference Prompt and Output Image Viewer) not being garbage collected due to event subscriptions - Fixed Batch Count seeds not being recorded properly in Inference projects and image metadata +- Fixed [#795](https://github.com/LykosAI/StabilityMatrix/issues/795) - SwarmUI launch args not working properly +### Supporters +#### Visionaries +- Shoutout to our Visionary-tier Patreon supporter, **Scopp Mcdee**! Huge thanks for your continued support! +#### Pioneers +- Many thanks to our Pioneer-tier supporters on Patreon: **tankfox**, **tanangular**, **Mr. Unknown**, and **Szir777**! Your continued support is greatly appreciated! ## v2.11.5 ### Added From 7ab3faeb65f3800f1aebc571965830451ba16a46 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 7 Aug 2024 21:34:57 -0700 Subject: [PATCH 162/325] args are dumb --- StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 3f4fece3b..b64f4ca43 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -280,7 +280,9 @@ void HandleConsoleOutput(ProcessOutput s) dotnetProcess = await prerequisiteHelper .RunDotnet( - args: $"\"{Path.Combine(releaseFolder, dllName)}\" {arguments.TrimEnd()}", + args: new ProcessArgs(new[] { Path.Combine(releaseFolder, dllName) }).Concat( + arguments.TrimEnd() + ), workingDirectory: installedPackagePath, envVars: aspEnvVars, onProcessOutput: HandleConsoleOutput, From 80a9715860df0115c2c2aed112918b33be340e9d Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 7 Aug 2024 21:59:09 -0700 Subject: [PATCH 163/325] add shoutout to changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6ff09d87..f26a9522f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed download links for IPAdapters in the HuggingFace model browser - Fixed potential memory leak of transient controls (Inference Prompt and Output Image Viewer) not being garbage collected due to event subscriptions - Fixed Batch Count seeds not being recorded properly in Inference projects and image metadata +### Supporters +#### Visionaries +- A heartfelt thank you to our Visionary-tier Patreon supporter, **Scopp Mcdee**! We truly appreciate your continued support! ## v2.12.0-dev.2 ### Added From 4d6dd9a9cf2521d70c4969ab15fa11b127b306e2 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 8 Aug 2024 20:13:48 -0400 Subject: [PATCH 164/325] Add InstalledPackage, Options, and Cancellation support to BasePackage methods & refactors --- .../Services/RunningPackageService.cs | 19 +++-- .../Dialogs/NewOneClickInstallViewModel.cs | 40 ++++++----- .../Dialogs/OneClickInstallViewModel.cs | 40 ++++++----- .../ViewModels/LaunchPageViewModel.cs | 2 +- .../PackageManager/PackageCardViewModel.cs | 10 +-- .../PackageInstallDetailViewModel.cs | 57 +++++++-------- .../Extensions/ProgressExtensions.cs | 37 ++++++---- .../DownloadPackageVersionStep.cs | 24 +++---- .../PackageModification/InstallPackageStep.cs | 39 +++++----- .../PackageModification/UpdatePackageStep.cs | 55 +++++--------- .../Models/Packages/A3WebUI.cs | 42 ++++++----- .../Models/Packages/BaseGitPackage.cs | 38 +++++----- .../Models/Packages/BasePackage.cs | 38 +++++----- .../Models/Packages/ComfyUI.cs | 38 +++++----- .../Models/Packages/DankDiffusion.cs | 25 +++---- .../Models/Packages/Fooocus.cs | 35 +++++---- .../Models/Packages/FooocusMre.cs | 35 +++++---- .../Models/Packages/InvokeAI.cs | 28 +++++--- .../Models/Packages/KohyaSs.cs | 27 +++---- .../Models/Packages/OneTrainer.cs | 38 ++++------ .../Options/DownloadPackageOptions.cs | 6 ++ .../Packages/Options/InstallPackageOptions.cs | 10 +++ .../Packages/Options/PythonPackageOptions.cs | 9 +++ .../Packages/Options/RunPackageOptions.cs | 8 +++ .../Packages/Options/UpdatePackageOptions.cs | 13 ++++ .../Models/Packages/RuinedFooocus.cs | 18 ++--- .../Models/Packages/SDWebForge.cs | 14 ++-- StabilityMatrix.Core/Models/Packages/Sdfx.cs | 31 ++++---- .../Packages/StableDiffusionDirectMl.cs | 9 +-- .../Models/Packages/StableDiffusionUx.cs | 28 ++++---- .../Models/Packages/StableSwarm.cs | 27 ++++--- .../Models/Packages/UnknownPackage.cs | 30 ++++---- .../Models/Packages/VladAutomatic.cs | 71 +++++++++---------- .../Models/Packages/VoltaML.cs | 27 +++---- 34 files changed, 515 insertions(+), 453 deletions(-) create mode 100644 StabilityMatrix.Core/Models/Packages/Options/DownloadPackageOptions.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Options/InstallPackageOptions.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Options/PythonPackageOptions.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Options/RunPackageOptions.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Options/UpdatePackageOptions.cs diff --git a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs index 07822e917..d82911dbe 100644 --- a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs +++ b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs @@ -8,6 +8,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using KeyedSemaphores; using Microsoft.Extensions.Logging; +using Nito.Disposables.Internals; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Core.Attributes; @@ -127,17 +128,21 @@ await basePackage.UpdateModelFolders( await basePackage.SetupOutputFolderLinks(installedPackage.FullPath!); } - // Load user launch args from settings and convert to string - var userArgs = installedPackage.LaunchArgs ?? []; - var userArgsString = string.Join(" ", userArgs.Select(opt => opt.ToArgString())); + // Load user launch args from settings + var launchArgs = + installedPackage.LaunchArgs?.Select(option => option.ToArgString()).WhereNotNull().ToList() ?? []; // Join with extras, if any - userArgsString = string.Join(" ", userArgsString, basePackage.ExtraLaunchArguments); + launchArgs.AddRange(basePackage.ExtraLaunchArguments); - // Use input command if provided, otherwise use package launch command - command ??= basePackage.LaunchCommand; + await basePackage.RunPackage( + packagePath, + installedPackage, + new RunPackageOptions { Command = command, Arguments = launchArgs }, + console.Post, + cancellationToken + ); - await basePackage.RunPackage(packagePath, command, userArgsString, o => console.Post(o)); var runningPackage = new PackagePair(installedPackage, basePackage); var viewModel = new RunningPackageViewModel( diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs index 425b20e7b..9d21d3103 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs @@ -143,10 +143,23 @@ private void InstallPackage(BasePackage selectedPackage) var torchVersion = selectedPackage.GetRecommendedTorchVersion(); var recommendedSharedFolderMethod = selectedPackage.RecommendedSharedFolderMethod; + var installedPackage = new InstalledPackage + { + DisplayName = selectedPackage.DisplayName, + LibraryPath = Path.Combine("Packages", selectedPackage.Name), + Id = Guid.NewGuid(), + PackageName = selectedPackage.Name, + Version = installedVersion, + LaunchCommand = selectedPackage.LaunchCommand, + LastUpdateCheck = DateTimeOffset.Now, + PreferredTorchVersion = torchVersion, + PreferredSharedFolderMethod = recommendedSharedFolderMethod + }; + var downloadStep = new DownloadPackageVersionStep( selectedPackage, installLocation, - downloadVersion + new DownloadPackageOptions { VersionOptions = downloadVersion } ); steps.Add(downloadStep); @@ -157,10 +170,14 @@ private void InstallPackage(BasePackage selectedPackage) var installStep = new InstallPackageStep( selectedPackage, - torchVersion, - recommendedSharedFolderMethod, - downloadVersion, - installLocation + installLocation, + installedPackage, + new InstallPackageOptions + { + SharedFolderMethod = recommendedSharedFolderMethod, + VersionOptions = downloadVersion, + PythonOptions = { TorchVersion = torchVersion } + } ); steps.Add(installStep); @@ -171,19 +188,6 @@ private void InstallPackage(BasePackage selectedPackage) ); steps.Add(setupModelFoldersStep); - var installedPackage = new InstalledPackage - { - DisplayName = selectedPackage.DisplayName, - LibraryPath = Path.Combine("Packages", selectedPackage.Name), - Id = Guid.NewGuid(), - PackageName = selectedPackage.Name, - Version = installedVersion, - LaunchCommand = selectedPackage.LaunchCommand, - LastUpdateCheck = DateTimeOffset.Now, - PreferredTorchVersion = torchVersion, - PreferredSharedFolderMethod = recommendedSharedFolderMethod - }; - var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, installedPackage); steps.Add(addInstalledPackageStep); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs index f5fb6f90e..cdb0f73ff 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs @@ -156,24 +156,12 @@ private async Task DoInstall() var torchVersion = SelectedPackage.GetRecommendedTorchVersion(); var recommendedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod; - var downloadStep = new DownloadPackageVersionStep(SelectedPackage, installLocation, downloadVersion); - steps.Add(downloadStep); - - var installStep = new InstallPackageStep( + var downloadStep = new DownloadPackageVersionStep( SelectedPackage, - torchVersion, - recommendedSharedFolderMethod, - downloadVersion, - installLocation + installLocation, + new DownloadPackageOptions() { VersionOptions = downloadVersion } ); - steps.Add(installStep); - - var setupModelFoldersStep = new SetupModelFoldersStep( - SelectedPackage, - recommendedSharedFolderMethod, - installLocation - ); - steps.Add(setupModelFoldersStep); + steps.Add(downloadStep); var installedPackage = new InstalledPackage { @@ -188,6 +176,26 @@ private async Task DoInstall() PreferredSharedFolderMethod = recommendedSharedFolderMethod }; + var installStep = new InstallPackageStep( + SelectedPackage, + installLocation, + installedPackage, + new InstallPackageOptions + { + SharedFolderMethod = recommendedSharedFolderMethod, + VersionOptions = downloadVersion, + PythonOptions = { TorchVersion = torchVersion } + } + ); + steps.Add(installStep); + + var setupModelFoldersStep = new SetupModelFoldersStep( + SelectedPackage, + recommendedSharedFolderMethod, + installLocation + ); + steps.Add(setupModelFoldersStep); + var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, installedPackage); steps.Add(addInstalledPackageStep); diff --git a/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs index dc0356db0..850e196f5 100644 --- a/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs @@ -333,7 +333,7 @@ await basePackage.UpdateModelFolders( // Use input command if provided, otherwise use package launch command command ??= basePackage.LaunchCommand; - await basePackage.RunPackage(packagePath, command, userArgsString, OnProcessOutputReceived); + // await basePackage.RunPackage(packagePath, command, userArgsString, OnProcessOutputReceived); RunningPackage = new PackagePair(activeInstall, basePackage); EventManager.Instance.OnRunningPackageStatusChanged(RunningPackage); diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index ea8ac463a..b50aa0146 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -439,9 +439,10 @@ public async Task Update() var updatePackageStep = new UpdatePackageStep( settingsManager, + basePackage, + Package.FullPath!.Unwrap(), Package, - versionOptions, - basePackage + new UpdatePackageOptions { VersionOptions = versionOptions } ); var steps = new List { updatePackageStep }; @@ -607,9 +608,10 @@ private async Task ChangeVersion() var updatePackageStep = new UpdatePackageStep( settingsManager, + basePackage, + Package.FullPath!.Unwrap(), Package, - versionOptions, - basePackage + new UpdatePackageOptions { VersionOptions = versionOptions } ); var steps = new List { updatePackageStep }; diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index ab7c6ac0d..662ba2aab 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -179,8 +179,6 @@ private async Task Install() InstallName = InstallName.Trim(); - var setPackageInstallingStep = new SetPackageInstallingStep(settingsManager, InstallName); - var installLocation = Path.Combine(settingsManager.LibraryDir, "Packages", InstallName); if (Directory.Exists(installLocation)) { @@ -188,9 +186,6 @@ private async Task Install() await installPath.DeleteVerboseAsync(logger); } - var prereqStep = new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, SelectedPackage); - var unpackSiteCustomizeStep = new UnpackSiteCustomizeStep(Path.Combine(installLocation, "venv")); - var downloadOptions = new DownloadPackageVersionOptions(); var installedVersion = new InstalledPackageVersion(); if (IsReleaseMode) @@ -216,23 +211,6 @@ private async Task Install() installedVersion.InstalledCommitSha = downloadOptions.CommitHash; } - var downloadStep = new DownloadPackageVersionStep(SelectedPackage, installLocation, downloadOptions); - var installStep = new InstallPackageStep( - SelectedPackage, - SelectedTorchVersion, - SelectedSharedFolderMethod, - downloadOptions, - installLocation - ); - - var setupModelFoldersStep = new SetupModelFoldersStep( - SelectedPackage, - SelectedSharedFolderMethod, - installLocation - ); - - var setupOutputSharingStep = new SetupOutputSharingStep(SelectedPackage, installLocation); - var package = new InstalledPackage { DisplayName = InstallName, @@ -247,24 +225,37 @@ private async Task Install() UseSharedOutputFolder = IsOutputSharingEnabled }; - var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, package); - var steps = new List { - setPackageInstallingStep, - prereqStep, - downloadStep, - unpackSiteCustomizeStep, - installStep, - setupModelFoldersStep, - addInstalledPackageStep + new SetPackageInstallingStep(settingsManager, InstallName), + new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, SelectedPackage), + new DownloadPackageVersionStep( + SelectedPackage, + installLocation, + new DownloadPackageOptions { VersionOptions = downloadOptions } + ), + new UnpackSiteCustomizeStep(Path.Combine(installLocation, "venv")), + new InstallPackageStep( + SelectedPackage, + installLocation, + package, + new InstallPackageOptions + { + SharedFolderMethod = SelectedSharedFolderMethod, + VersionOptions = downloadOptions, + PythonOptions = { TorchVersion = SelectedTorchVersion } + } + ), + new SetupModelFoldersStep(SelectedPackage, SelectedSharedFolderMethod, installLocation) }; if (IsOutputSharingEnabled) { - steps.Insert(steps.IndexOf(addInstalledPackageStep), setupOutputSharingStep); + steps.Add(new SetupOutputSharingStep(SelectedPackage, installLocation)); } + steps.Add(new AddInstalledPackageStep(settingsManager, package)); + var packageName = SelectedPackage.Name; var runner = new PackageModificationRunner @@ -279,7 +270,7 @@ private async Task Install() }; EventManager.Instance.OnPackageInstallProgressAdded(runner); - await runner.ExecuteSteps(steps.ToList()); + await runner.ExecuteSteps(steps); if (!runner.Failed) { diff --git a/StabilityMatrix.Core/Extensions/ProgressExtensions.cs b/StabilityMatrix.Core/Extensions/ProgressExtensions.cs index 2d2185a68..965a1c5c0 100644 --- a/StabilityMatrix.Core/Extensions/ProgressExtensions.cs +++ b/StabilityMatrix.Core/Extensions/ProgressExtensions.cs @@ -7,21 +7,28 @@ namespace StabilityMatrix.Core.Extensions; public static class ProgressExtensions { [return: NotNullIfNotNull(nameof(progress))] - public static Action? AsProcessOutputHandler(this IProgress? progress) + public static Action? AsProcessOutputHandler( + this IProgress? progress, + bool setMessageAsOutput = true + ) { - return progress == null - ? null - : output => - { - progress.Report( - new ProgressReport - { - IsIndeterminate = true, - Message = output.Text, - ProcessOutput = output, - PrintToConsole = true - } - ); - }; + if (progress is null) + { + return null; + } + + return output => + { + progress.Report( + new ProgressReport + { + Progress = -1f, + IsIndeterminate = true, + Message = setMessageAsOutput ? output.Text : null, + ProcessOutput = output, + PrintToConsole = true + } + ); + }; } } diff --git a/StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs b/StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs index f397e77fc..010ecf519 100644 --- a/StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs +++ b/StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs @@ -3,25 +3,19 @@ namespace StabilityMatrix.Core.Models.PackageModification; -public class DownloadPackageVersionStep : IPackageStep +public class DownloadPackageVersionStep( + BasePackage package, + string installPath, + DownloadPackageOptions options +) : ICancellablePackageStep { - private readonly BasePackage package; - private readonly string installPath; - private readonly DownloadPackageVersionOptions downloadOptions; - - public DownloadPackageVersionStep( - BasePackage package, - string installPath, - DownloadPackageVersionOptions downloadOptions + public Task ExecuteAsync( + IProgress? progress = null, + CancellationToken cancellationToken = default ) { - this.package = package; - this.installPath = installPath; - this.downloadOptions = downloadOptions; + return package.DownloadPackage(installPath, options, progress, cancellationToken); } - public Task ExecuteAsync(IProgress? progress = null) => - package.DownloadPackage(installPath, downloadOptions, progress); - public string ProgressTitle => "Downloading package..."; } diff --git a/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs b/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs index 0ccc279d7..59fc3fdbb 100644 --- a/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs +++ b/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs @@ -1,35 +1,32 @@ -using StabilityMatrix.Core.Models.Packages; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models.Packages; using StabilityMatrix.Core.Models.Progress; -using StabilityMatrix.Core.Processes; namespace StabilityMatrix.Core.Models.PackageModification; public class InstallPackageStep( - BasePackage package, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, - string installPath -) : IPackageStep + BasePackage basePackage, + string installLocation, + InstalledPackage installedPackage, + InstallPackageOptions options +) : ICancellablePackageStep { - public async Task ExecuteAsync(IProgress? progress = null) + public async Task ExecuteAsync( + IProgress? progress = null, + CancellationToken cancellationToken = default + ) { - void OnConsoleOutput(ProcessOutput output) - { - progress?.Report(new ProgressReport(-1f, isIndeterminate: true) { ProcessOutput = output }); - } - - await package + await basePackage .InstallPackage( - installPath, - torchVersion, - selectedSharedFolderMethod, - versionOptions, + installLocation, + installedPackage, + options, progress, - OnConsoleOutput + progress.AsProcessOutputHandler(setMessageAsOutput: false), + cancellationToken ) .ConfigureAwait(false); } - public string ProgressTitle => $"Installing {package.DisplayName}..."; + public string ProgressTitle => $"Installing {basePackage.DisplayName}..."; } diff --git a/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs b/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs index 164da9427..430524da9 100644 --- a/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs +++ b/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs @@ -1,54 +1,31 @@ -using StabilityMatrix.Core.Models.Packages; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Models.Packages; using StabilityMatrix.Core.Models.Progress; -using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; namespace StabilityMatrix.Core.Models.PackageModification; -public class UpdatePackageStep : IPackageStep +public class UpdatePackageStep( + ISettingsManager settingsManager, + BasePackage basePackage, + string installLocation, + InstalledPackage installedPackage, + UpdatePackageOptions options +) : ICancellablePackageStep { - private readonly ISettingsManager settingsManager; - private readonly InstalledPackage installedPackage; - private readonly DownloadPackageVersionOptions versionOptions; - private readonly BasePackage basePackage; - - public UpdatePackageStep( - ISettingsManager settingsManager, - InstalledPackage installedPackage, - DownloadPackageVersionOptions versionOptions, - BasePackage basePackage + public async Task ExecuteAsync( + IProgress? progress = null, + CancellationToken cancellationToken = default ) { - this.settingsManager = settingsManager; - this.installedPackage = installedPackage; - this.versionOptions = versionOptions; - this.basePackage = basePackage; - } - - public async Task ExecuteAsync(IProgress? progress = null) - { - var torchVersion = installedPackage.PreferredTorchVersion ?? basePackage.GetRecommendedTorchVersion(); - - void OnConsoleOutput(ProcessOutput output) - { - progress?.Report( - new ProgressReport - { - IsIndeterminate = true, - Message = output.Text, - ProcessOutput = output, - PrintToConsole = true - } - ); - } - var updateResult = await basePackage .Update( + installLocation, installedPackage, - torchVersion, - versionOptions, + options, progress, - onConsoleOutput: OnConsoleOutput + progress.AsProcessOutputHandler(), + cancellationToken ) .ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 6e1a83a23..9667a23fd 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using NLog; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Helper.HardwareInfo; @@ -192,11 +193,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); @@ -210,22 +211,24 @@ public override async Task InstallPackage( progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + var requirements = new FilePath(installLocation, "requirements_versions.txt"); var pipArgs = new PipInstallArgs() .WithTorch("==2.1.2") .WithTorchVision("==0.16.2") .WithTorchExtraIndex( - torchVersion switch + options.PythonOptions.TorchVersion switch { TorchVersion.Cpu => "cpu", TorchVersion.Cuda => "cu121", TorchVersion.Rocm => "rocm5.6", TorchVersion.Mps => "cpu", - _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) + _ => throw new NotSupportedException($"Unsupported torch version: {torchVersion}") } ) .WithParsedFromRequirementsTxt( - await requirements.ReadAllTextAsync().ConfigureAwait(false), + await requirements.ReadAllTextAsync(cancellationToken).ConfigureAwait(false), excludePattern: "torch" ); @@ -257,13 +260,14 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -281,15 +285,15 @@ void HandleConsoleOutput(ProcessOutput s) OnStartupComplete(WebUrl); } - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } - public override string? ExtraLaunchArguments { get; set; } = - settingsManager.IsLibraryDirSet - ? $"--gradio-allowed-path \"{settingsManager.ImagesDirectory}\"" - : string.Empty; + public override IReadOnlyList ExtraLaunchArguments => + settingsManager.IsLibraryDirSet ? ["--gradio-allowed-path", settingsManager.ImagesDirectory] : []; private class A3WebUiExtensionManager(A3WebUI package) : GitPackageExtensionManager(package.PrerequisiteHelper) diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index 999569b97..65fbc4540 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -210,11 +210,15 @@ public override async Task> GetReleaseTags() public override async Task DownloadPackage( string installLocation, - DownloadPackageVersionOptions versionOptions, - IProgress? progress = null + DownloadPackageOptions options, + IProgress? progress = null, + CancellationToken cancellationToken = default ) { + var versionOptions = options.VersionOptions; + const long fiveGigs = 5 * SystemInfo.Gibibyte; + if (SystemInfo.GetDiskFreeSpaceBytes(installLocation) is < fiveGigs) { throw new ApplicationException( @@ -378,12 +382,12 @@ await GetAllCommits(currentVersion.InstalledBranch!).ConfigureAwait(false) } public override async Task Update( + string installLocation, InstalledPackage installedPackage, - TorchVersion torchVersion, - DownloadPackageVersionOptions versionOptions, + UpdatePackageOptions options, IProgress? progress = null, - bool includePrerelease = false, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { if (installedPackage.Version == null) @@ -405,6 +409,8 @@ await PrerequisiteHelper .ConfigureAwait(false); } + var versionOptions = options.VersionOptions; + if (!string.IsNullOrWhiteSpace(versionOptions.VersionTag)) { progress?.Report(new ProgressReport(-1f, "Fetching tags...", isIndeterminate: true)); @@ -424,12 +430,12 @@ await PrerequisiteHelper .ConfigureAwait(false); await InstallPackage( - installedPackage.FullPath!, - torchVersion, - installedPackage.PreferredSharedFolderMethod ?? SharedFolderMethod.Symlink, - versionOptions, + installLocation, + installedPackage, + options.AsInstallOptions(), progress, - onConsoleOutput + onConsoleOutput, + cancellationToken ) .ConfigureAwait(false); @@ -494,12 +500,12 @@ await PrerequisiteHelper } await InstallPackage( - installedPackage.FullPath, - torchVersion, - installedPackage.PreferredSharedFolderMethod ?? SharedFolderMethod.Symlink, - versionOptions, + installLocation, + installedPackage, + options.AsInstallOptions(), progress, - onConsoleOutput + onConsoleOutput, + cancellationToken ) .ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 03400dbf2..962fe6a71 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -53,35 +53,37 @@ public abstract class BasePackage public abstract Task DownloadPackage( string installLocation, - DownloadPackageVersionOptions versionOptions, - IProgress? progress1 + DownloadPackageOptions options, + IProgress? progress = null, + CancellationToken cancellationToken = default ); public abstract Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null - ); - - public abstract Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ); public abstract Task CheckForUpdates(InstalledPackage package); public abstract Task Update( + string installLocation, InstalledPackage installedPackage, - TorchVersion torchVersion, - DownloadPackageVersionOptions versionOptions, + UpdatePackageOptions options, IProgress? progress = null, - bool includePrerelease = false, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default + ); + + public abstract Task RunPackage( + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ); public virtual IEnumerable AvailableSharedFolderMethods => @@ -160,7 +162,7 @@ public virtual TorchVersion GetRecommendedTorchVersion() public abstract Task> GetReleaseTags(); public abstract List LaunchOptions { get; } - public virtual string? ExtraLaunchArguments { get; set; } = null; + public virtual IReadOnlyList ExtraLaunchArguments { get; } = Array.Empty(); /// /// The shared folders that this package supports. diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 57f37b64c..7ba2bce56 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using System.Text.Json; +using System.Text.Json; using System.Text.RegularExpressions; using NLog; using StabilityMatrix.Core.Attributes; @@ -180,11 +179,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true)); @@ -192,6 +191,8 @@ public override async Task InstallPackage( await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + var pipArgs = new PipInstallArgs(); pipArgs = torchVersion switch @@ -244,23 +245,22 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; + await SetupVenv(installLocation).ConfigureAwait(false); - VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); - return; + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); - void HandleExit(int i) - { - Debug.WriteLine($"Venv process exited with code {i}"); - OnExit(i); - } + return; void HandleConsoleOutput(ProcessOutput s) { diff --git a/StabilityMatrix.Core/Models/Packages/DankDiffusion.cs b/StabilityMatrix.Core/Models/Packages/DankDiffusion.cs index 9b04169ef..90efc9e7a 100644 --- a/StabilityMatrix.Core/Models/Packages/DankDiffusion.cs +++ b/StabilityMatrix.Core/Models/Packages/DankDiffusion.cs @@ -21,8 +21,7 @@ IPrerequisiteHelper prerequisiteHelper public override string DisplayName { get; set; } = "Dank Diffusion"; public override string Author => "mohnjiles"; 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"; public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink; @@ -36,21 +35,22 @@ IPrerequisiteHelper prerequisiteHelper public override Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); } public override Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); @@ -85,10 +85,7 @@ SharedFolderMethod sharedFolderMethod public override List LaunchOptions { get; } public override Dictionary>? SharedFolders { get; } - public override Dictionary< - SharedOutputType, - IReadOnlyList - >? SharedOutputFolders { get; } + public override Dictionary>? SharedOutputFolders { get; } public override string MainBranch { get; } } diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index a79c4ccbd..c283e2309 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -276,11 +276,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false); @@ -290,6 +290,8 @@ public override async Task InstallPackage( // Pip version 24.1 deprecated numpy requirement spec used by torchsde 0.2.5 await venvRunner.PipInstall(["pip==23.3.2"], onConsoleOutput).ConfigureAwait(false); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + var pipArgs = new PipInstallArgs(); if (torchVersion == TorchVersion.DirectMl) @@ -324,13 +326,14 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -348,15 +351,11 @@ void HandleConsoleOutput(ProcessOutput s) } } - void HandleExit(int i) - { - Debug.WriteLine($"Venv process exited with code {i}"); - OnExit(i); - } - - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } public override Task SetupModelFolders( diff --git a/StabilityMatrix.Core/Models/Packages/FooocusMre.cs b/StabilityMatrix.Core/Models/Packages/FooocusMre.cs index 1a1d1da72..339cc21f0 100644 --- a/StabilityMatrix.Core/Models/Packages/FooocusMre.cs +++ b/StabilityMatrix.Core/Models/Packages/FooocusMre.cs @@ -103,17 +103,19 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false); progress?.Report(new ProgressReport(-1f, "Installing torch...", isIndeterminate: true)); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + if (torchVersion == TorchVersion.DirectMl) { await venvRunner @@ -154,13 +156,14 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -178,14 +181,10 @@ void HandleConsoleOutput(ProcessOutput s) } } - void HandleExit(int i) - { - Debug.WriteLine($"Venv process exited with code {i}"); - OnExit(i); - } - - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } } diff --git a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs index 7e155c056..1d64791e6 100644 --- a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs +++ b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs @@ -148,11 +148,11 @@ public override TorchVersion GetRecommendedTorchVersion() public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { // Setup venv @@ -176,6 +176,8 @@ await SetupAndBuildInvokeFrontend( var pipCommandArgs = "-e . --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu"; + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + switch (torchVersion) { // If has Nvidia Gpu, install CUDA version @@ -298,11 +300,19 @@ await PrerequisiteHelper } public override Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput - ) => RunInvokeCommand(installedPackagePath, command, arguments, true, onConsoleOutput); + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default + ) => + RunInvokeCommand( + installLocation, + options.Command ?? LaunchCommand, + new ProcessArgs(options.Arguments.ToArray()), + true, + onConsoleOutput + ); private async Task RunInvokeCommand( string installedPackagePath, diff --git a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs index 8e6c738f0..b5e60e357 100644 --- a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs +++ b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs @@ -106,11 +106,11 @@ IPyRunner runner public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Updating submodules", isIndeterminate: true)); @@ -153,13 +153,14 @@ await venvRunner } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -177,9 +178,11 @@ void HandleConsoleOutput(ProcessOutput s) OnStartupComplete(WebUrl); } - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } public override Dictionary>? SharedFolders { get; } diff --git a/StabilityMatrix.Core/Models/Packages/OneTrainer.cs b/StabilityMatrix.Core/Models/Packages/OneTrainer.cs index 52c49b355..3f33d106a 100644 --- a/StabilityMatrix.Core/Models/Packages/OneTrainer.cs +++ b/StabilityMatrix.Core/Models/Packages/OneTrainer.cs @@ -45,11 +45,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); @@ -63,28 +63,20 @@ public override async Task InstallPackage( } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); - return; - - void HandleExit(int i) - { - Debug.WriteLine($"Venv process exited with code {i}"); - OnExit(i); - } + await SetupVenv(installLocation).ConfigureAwait(false); - void HandleConsoleOutput(ProcessOutput s) - { - onConsoleOutput?.Invoke(s); - } + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + onConsoleOutput, + OnExit + ); } public override List LaunchOptions => [LaunchOptionDefinition.Extras]; diff --git a/StabilityMatrix.Core/Models/Packages/Options/DownloadPackageOptions.cs b/StabilityMatrix.Core/Models/Packages/Options/DownloadPackageOptions.cs new file mode 100644 index 000000000..3c564802a --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Options/DownloadPackageOptions.cs @@ -0,0 +1,6 @@ +namespace StabilityMatrix.Core.Models.Packages; + +public class DownloadPackageOptions +{ + public required DownloadPackageVersionOptions VersionOptions { get; init; } +} diff --git a/StabilityMatrix.Core/Models/Packages/Options/InstallPackageOptions.cs b/StabilityMatrix.Core/Models/Packages/Options/InstallPackageOptions.cs new file mode 100644 index 000000000..b732b3af7 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Options/InstallPackageOptions.cs @@ -0,0 +1,10 @@ +namespace StabilityMatrix.Core.Models.Packages; + +public class InstallPackageOptions +{ + public DownloadPackageVersionOptions VersionOptions { get; init; } = new(); + + public PythonPackageOptions PythonOptions { get; init; } = new(); + + public SharedFolderMethod SharedFolderMethod { get; init; } = SharedFolderMethod.None; +} diff --git a/StabilityMatrix.Core/Models/Packages/Options/PythonPackageOptions.cs b/StabilityMatrix.Core/Models/Packages/Options/PythonPackageOptions.cs new file mode 100644 index 000000000..11b35edf7 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Options/PythonPackageOptions.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace StabilityMatrix.Core.Models.Packages; + +public class PythonPackageOptions +{ + [JsonConverter(typeof(JsonStringEnumConverter))] + public TorchVersion? TorchVersion { get; set; } +} diff --git a/StabilityMatrix.Core/Models/Packages/Options/RunPackageOptions.cs b/StabilityMatrix.Core/Models/Packages/Options/RunPackageOptions.cs new file mode 100644 index 000000000..1318974a8 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Options/RunPackageOptions.cs @@ -0,0 +1,8 @@ +namespace StabilityMatrix.Core.Models.Packages; + +public class RunPackageOptions +{ + public string? Command { get; set; } + + public IReadOnlyList Arguments { get; set; } = Array.Empty(); +} diff --git a/StabilityMatrix.Core/Models/Packages/Options/UpdatePackageOptions.cs b/StabilityMatrix.Core/Models/Packages/Options/UpdatePackageOptions.cs new file mode 100644 index 000000000..471ae1655 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Options/UpdatePackageOptions.cs @@ -0,0 +1,13 @@ +namespace StabilityMatrix.Core.Models.Packages; + +public class UpdatePackageOptions +{ + public DownloadPackageVersionOptions VersionOptions { get; init; } = new(); + + public PythonPackageOptions PythonOptions { get; init; } = new(); + + public InstallPackageOptions AsInstallOptions() + { + return new InstallPackageOptions { VersionOptions = VersionOptions, PythonOptions = PythonOptions }; + } +} diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index f6def17b4..a5adbd43c 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -106,13 +106,15 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + if (torchVersion == TorchVersion.Cuda) { await using var venvRunner = await SetupVenvPure(installLocation, forceRecreate: true) @@ -141,11 +143,11 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), { await base.InstallPackage( installLocation, - torchVersion, - selectedSharedFolderMethod, - versionOptions, + installedPackage, + options, progress, - onConsoleOutput + onConsoleOutput, + cancellationToken ) .ConfigureAwait(false); } diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index 4f1314eb3..9a009064c 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -146,11 +146,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); @@ -162,9 +162,13 @@ public override async Task InstallPackage( progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); var requirements = new FilePath(installLocation, "requirements_versions.txt"); - var requirementsContent = await requirements.ReadAllTextAsync().ConfigureAwait(false); + var requirementsContent = await requirements + .ReadAllTextAsync(cancellationToken) + .ConfigureAwait(false); var pipArgs = new PipInstallArgs("setuptools==69.5.1"); + + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); if (torchVersion is TorchVersion.DirectMl) { pipArgs = pipArgs.WithTorchDirectML(); diff --git a/StabilityMatrix.Core/Models/Packages/Sdfx.cs b/StabilityMatrix.Core/Models/Packages/Sdfx.cs index 6e6c579b4..f0d566baf 100644 --- a/StabilityMatrix.Core/Models/Packages/Sdfx.cs +++ b/StabilityMatrix.Core/Models/Packages/Sdfx.cs @@ -75,11 +75,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true)); @@ -91,6 +91,8 @@ public override async Task InstallPackage( new ProgressReport(-1f, "Installing Package Requirements...", isIndeterminate: true) ); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); + var gpuArg = torchVersion switch { TorchVersion.Cuda => "--nvidia", @@ -98,7 +100,7 @@ public override async Task InstallPackage( TorchVersion.DirectMl => "--directml", TorchVersion.Cpu => "--cpu", TorchVersion.Mps => "--mac", - _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) + _ => throw new NotSupportedException($"Torch version {torchVersion} is not supported.") }; await venvRunner @@ -109,13 +111,14 @@ await venvRunner } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - var venvRunner = await SetupVenv(installedPackagePath).ConfigureAwait(false); + var venvRunner = await SetupVenv(installLocation).ConfigureAwait(false); venvRunner.UpdateEnvironmentVariables(GetEnvVars); void HandleConsoleOutput(ProcessOutput s) @@ -134,9 +137,11 @@ void HandleConsoleOutput(ProcessOutput s) OnStartupComplete(WebUrl); } - var args = $"\"{Path.Combine(installedPackagePath, command)}\" --run {arguments}"; - - venvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); + venvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), "--run", ..options.Arguments], + HandleConsoleOutput, + OnExit + ); // Cuz node was getting detached on process exit if (Compat.IsWindows) diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs index 84b03d3cd..0d1ee8cd3 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs @@ -65,17 +65,18 @@ public override List LaunchOptions public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); // Setup venv await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); switch (torchVersion) { case TorchVersion.DirectMl: diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs index f158c1b3f..7298fa0df 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs @@ -179,17 +179,18 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); switch (torchVersion) { case TorchVersion.Cpu: @@ -233,13 +234,14 @@ await requirements.ReadAllTextAsync().ConfigureAwait(false), } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -257,9 +259,11 @@ void HandleConsoleOutput(ProcessOutput s) OnStartupComplete(WebUrl); } - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } private async Task InstallRocmTorch( diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index b64f4ca43..b68b5b344 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -124,11 +124,11 @@ private FilePath GetBackendsPath(string installLocation) => public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Installing SwarmUI...", isIndeterminate: true)); @@ -182,7 +182,7 @@ await prerequisiteHelper // set default settings var settings = new StableSwarmSettings { IsInstalled = true }; - if (selectedSharedFolderMethod is SharedFolderMethod.Configuration) + if (options.SharedFolderMethod is SharedFolderMethod.Configuration) { settings.Paths = new StableSwarmSettings.PathsData { @@ -243,10 +243,11 @@ await prerequisiteHelper } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { var aspEnvVars = new Dictionary @@ -271,7 +272,7 @@ void HandleConsoleOutput(ProcessOutput s) } } - var releaseFolder = Path.Combine(installedPackagePath, "src", "bin", "live_release"); + var releaseFolder = Path.Combine(installLocation, "src", "bin", "live_release"); var dllName = "StableSwarmUI.dll"; if (File.Exists(Path.Combine(releaseFolder, "SwarmUI.dll"))) { @@ -280,10 +281,8 @@ void HandleConsoleOutput(ProcessOutput s) dotnetProcess = await prerequisiteHelper .RunDotnet( - args: new ProcessArgs(new[] { Path.Combine(releaseFolder, dllName) }).Concat( - arguments.TrimEnd() - ), - workingDirectory: installedPackagePath, + args: [Path.Combine(releaseFolder, dllName), ..options.Arguments], + workingDirectory: installLocation, envVars: aspEnvVars, onProcessOutput: HandleConsoleOutput, waitForExit: false diff --git a/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs b/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs index b1e523399..dd8fcfe77 100644 --- a/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs @@ -31,8 +31,9 @@ public class UnknownPackage : BasePackage public override Task DownloadPackage( string installLocation, - DownloadPackageVersionOptions versionOptions, - IProgress? progress1 + DownloadPackageOptions options, + IProgress? progress = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); @@ -41,21 +42,22 @@ public override Task DownloadPackage( /// public override Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); } public override Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); @@ -121,12 +123,12 @@ public override Task CheckForUpdates(InstalledPackage package) /// public override Task Update( + string installLocation, InstalledPackage installedPackage, - TorchVersion torchVersion, - DownloadPackageVersionOptions versionOptions, + UpdatePackageOptions options, IProgress? progress = null, - bool includePrerelease = false, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { throw new NotImplementedException(); diff --git a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs index 8d01ed998..9f1d30c86 100644 --- a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs +++ b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs @@ -186,23 +186,22 @@ IPrerequisiteHelper prerequisiteHelper LaunchOptionDefinition.Extras ]; - public override string ExtraLaunchArguments => ""; - public override string MainBranch => "master"; public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { progress?.Report(new ProgressReport(-1f, "Installing package...", isIndeterminate: true)); // Setup venv await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false); + var torchVersion = options.PythonOptions.TorchVersion ?? GetRecommendedTorchVersion(); switch (torchVersion) { // Run initial install @@ -244,8 +243,9 @@ await venvRunner public override async Task DownloadPackage( string installLocation, - DownloadPackageVersionOptions downloadOptions, - IProgress? progress = null + DownloadPackageOptions options, + IProgress? progress = null, + CancellationToken cancellationToken = default ) { progress?.Report( @@ -260,9 +260,11 @@ public override async Task DownloadPackage( var installDir = new DirectoryPath(installLocation); installDir.Create(); - if (string.IsNullOrWhiteSpace(downloadOptions.BranchName)) + var versionOptions = options.VersionOptions; + + if (string.IsNullOrWhiteSpace(versionOptions.BranchName)) { - throw new ArgumentNullException(nameof(downloadOptions)); + throw new InvalidOperationException("Branch name is required for VladAutomatic"); } await PrerequisiteHelper @@ -271,29 +273,30 @@ await PrerequisiteHelper { "clone", "-b", - downloadOptions.BranchName, + versionOptions.BranchName, "https://github.com/vladmandic/automatic", installDir.Name }, installDir.Parent?.FullPath ?? "" ) .ConfigureAwait(false); - if (!string.IsNullOrWhiteSpace(downloadOptions.CommitHash) && !downloadOptions.IsLatest) + if (!string.IsNullOrWhiteSpace(versionOptions.CommitHash) && !versionOptions.IsLatest) { await PrerequisiteHelper - .RunGit(new[] { "checkout", downloadOptions.CommitHash }, installLocation) + .RunGit(new[] { "checkout", versionOptions.CommitHash }, installLocation) .ConfigureAwait(false); } } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); + await SetupVenv(installLocation).ConfigureAwait(false); void HandleConsoleOutput(ProcessOutput s) { @@ -310,33 +313,29 @@ void HandleConsoleOutput(ProcessOutput s) } } - void HandleExit(int i) - { - Debug.WriteLine($"Venv process exited with code {i}"); - OnExit(i); - } - - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; - - VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } public override async Task Update( + string installLocation, InstalledPackage installedPackage, - TorchVersion torchVersion, - DownloadPackageVersionOptions versionOptions, + UpdatePackageOptions options, IProgress? progress = null, - bool includePrerelease = false, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { var baseUpdateResult = await base.Update( + installLocation, installedPackage, - torchVersion, - versionOptions, + options, progress, - includePrerelease, - onConsoleOutput + onConsoleOutput, + cancellationToken ) .ConfigureAwait(false); @@ -354,7 +353,7 @@ public override async Task Update( return new InstalledPackageVersion { - InstalledBranch = versionOptions.BranchName, + InstalledBranch = options.VersionOptions.BranchName, InstalledCommitSha = result .StandardOutput?.Replace(Environment.NewLine, "") .Replace("\n", ""), diff --git a/StabilityMatrix.Core/Models/Packages/VoltaML.cs b/StabilityMatrix.Core/Models/Packages/VoltaML.cs index 6286ed709..3e9a0c216 100644 --- a/StabilityMatrix.Core/Models/Packages/VoltaML.cs +++ b/StabilityMatrix.Core/Models/Packages/VoltaML.cs @@ -146,11 +146,11 @@ IPrerequisiteHelper prerequisiteHelper public override async Task InstallPackage( string installLocation, - TorchVersion torchVersion, - SharedFolderMethod selectedSharedFolderMethod, - DownloadPackageVersionOptions versionOptions, + InstalledPackage installedPackage, + InstallPackageOptions options, IProgress? progress = null, - Action? onConsoleOutput = null + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { // Setup venv @@ -165,15 +165,14 @@ public override async Task InstallPackage( } public override async Task RunPackage( - string installedPackagePath, - string command, - string arguments, - Action? onConsoleOutput + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default ) { - await SetupVenv(installedPackagePath).ConfigureAwait(false); - - var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}"; + await SetupVenv(installLocation).ConfigureAwait(false); var foundIndicator = false; @@ -201,6 +200,10 @@ void HandleConsoleOutput(ProcessOutput s) foundIndicator = false; } - VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments], + HandleConsoleOutput, + OnExit + ); } } From a3fe497f004b9245954acc18b087ea10e7f6a78d Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 8 Aug 2024 19:57:38 -0700 Subject: [PATCH 165/325] actually pass the env vars to swarm --- CHANGELOG.md | 1 + StabilityMatrix.Core/Models/Packages/StableSwarm.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f26a9522f..994d2702f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed potential memory leak of transient controls (Inference Prompt and Output Image Viewer) not being garbage collected due to event subscriptions - Fixed Batch Count seeds not being recorded properly in Inference projects and image metadata - Fixed [#795](https://github.com/LykosAI/StabilityMatrix/issues/795) - SwarmUI launch args not working properly +- Fixed [#745](https://github.com/LykosAI/StabilityMatrix/issues/745) - not passing Environment Variables to SwarmUI ### Supporters #### Visionaries - Shoutout to our Visionary-tier Patreon supporter, **Scopp Mcdee**! Huge thanks for your continued support! diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index b64f4ca43..65f6a75b4 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -3,6 +3,7 @@ using FreneticUtilities.FreneticDataSyntax; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Exceptions; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Models.FDS; @@ -254,6 +255,7 @@ public override async Task RunPackage( ["ASPNETCORE_ENVIRONMENT"] = "Production", ["ASPNETCORE_URLS"] = "http://*:7801" }; + aspEnvVars.Update(settingsManager.Settings.EnvironmentVariables); void HandleConsoleOutput(ProcessOutput s) { From b66f511b3681949cf6808efb8fd4fe2f4fd84a3f Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 10 Aug 2024 02:30:01 -0400 Subject: [PATCH 166/325] Improved mac build script --- Build/_utils.sh | 9 ++++++++ Build/build_macos_app.sh | 45 ++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 Build/_utils.sh diff --git a/Build/_utils.sh b/Build/_utils.sh new file mode 100644 index 000000000..1abf1f395 --- /dev/null +++ b/Build/_utils.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +print_hyperlink() { + local url="$1" + local text="$2" + + # macOS Terminal supports clickable links in the following format + printf "\033]8;;%s\a%s\033]8;;\a" "$url" "$text" +} diff --git a/Build/build_macos_app.sh b/Build/build_macos_app.sh index acdfcd4b3..55dd1ed65 100755 --- a/Build/build_macos_app.sh +++ b/Build/build_macos_app.sh @@ -1,13 +1,30 @@ -#!/bin/sh +#!/bin/bash +output_dir="$(pwd)/out/osx-arm64/" +app_name="Stability Matrix.app" + +. "./_utils.sh" > /dev/null 2>&1 || . "${BASH_SOURCE%/*}/_utils.sh" + +# Parse args while getopts v: flag do case "${flag}" in - v) version=${OPTARG};; - *) echo "Invalid option";; + v) + version=${OPTARG} + ;; + *) + echo "Invalid option: -$OPTARG" >&2 + exit 2 + ;; esac done +shift $((OPTIND - 1)) +echo $"Passing extra args to msbuild: $@" + +set -e + +# Build the app dotnet \ msbuild \ StabilityMatrix.Avalonia \ @@ -15,12 +32,28 @@ StabilityMatrix.Avalonia \ -p:RuntimeIdentifier=osx-arm64 \ -p:UseAppHost=true \ -p:Configuration=Release \ --p:CFBundleShortVersionString="$version" \ -p:SelfContained=true \ -p:CFBundleName="Stability Matrix" \ -p:CFBundleDisplayName="Stability Matrix" \ -p:CFBundleVersion="$version" \ --p:PublishDir="$(pwd)/out/osx-arm64/bin" \ +-p:CFBundleShortVersionString="$version" \ +-p:PublishDir="${output_dir:?}/bin" \ +"$@" + +target_plist_path="${output_dir:?}/bin/${app_name:?}/Contents/Info.plist" +echo "> Checking Info.plist..." +file "${target_plist_path:?}" +plutil -lint "${target_plist_path:?}" + +echo "> Copying app to output..." +# Delete existing file +rm -rf "${output_dir:?}/${app_name:?}" # Copy the app out of bin -cp -r ./out/osx-arm64/bin/Stability\ Matrix.app ./out/osx-arm64/Stability\ Matrix.app +cp -r "${output_dir:?}/bin/${app_name:?}" "${output_dir:?}/${app_name:?}" + +# Print output location +echo "[App Build Completed]" +print_hyperlink "file:///${output_dir:?}" "${output_dir:?}" +print_hyperlink "file:///${output_dir:?}/${app_name:?}" "${app_name:?}" +echo "" From 3655afeacab655b8f8a14e0bc153260a816bf21c Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 10 Aug 2024 02:31:40 -0400 Subject: [PATCH 167/325] Support uri handling on macos --- StabilityMatrix.Avalonia/App.axaml.cs | 45 ++++++++++++- .../Helpers/UriHandler.cs | 4 +- StabilityMatrix.Avalonia/Program.cs | 44 +++++++++---- .../StabilityMatrix.Avalonia.csproj | 64 +++++++++++++++---- 4 files changed, 129 insertions(+), 28 deletions(-) diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index c87e0eebd..7b510db86 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -255,6 +255,13 @@ private void Setup() // Setup uri handler for `stabilitymatrix://` protocol Program.UriHandler.RegisterUriScheme(); + + // Setup activation protocol handlers (uri handler on macOS) + if (Compat.IsMacOS && this.TryGetFeature() is { } activatableLifetime) + { + Logger.Debug("ActivatableLifetime available, setting up activation protocol handlers"); + activatableLifetime.Activated += OnActivated; + } } private void ShowMainWindow() @@ -402,7 +409,16 @@ internal static IServiceCollection ConfigureServices() services.AddMemoryCache(); services.AddLazyInstance(); - services.AddMessagePipe().AddNamedPipeInterprocess("StabilityMatrix"); + // Named pipe interprocess communication on Windows and Linux for uri handling + if (Compat.IsWindows || Compat.IsLinux) + { + services.AddMessagePipe().AddNamedPipeInterprocess("StabilityMatrix"); + } + else + { + // Use activation events on macOS, so just in-memory message pipe + services.AddMessagePipe().AddInMemoryDistributedMessageBroker(); + } var exportedTypes = AppDomain .CurrentDomain.GetAssemblies() @@ -952,6 +968,33 @@ UnobservedTaskExceptionEventArgs e } } + private static async void OnActivated(object? sender, ActivatedEventArgs args) + { + if (args is not ProtocolActivatedEventArgs protocolArgs) + { + Logger.Warn("Activated with unknown args: {Args}", args); + return; + } + + if (protocolArgs.Kind is ActivationKind.OpenUri) + { + Logger.Info("Activated with Protocol OpenUri: {Uri}", protocolArgs.Uri); + + // Ensure the uri scheme is our custom scheme + if ( + !protocolArgs.Uri.Scheme.Equals(Program.UriHandler.Scheme, StringComparison.OrdinalIgnoreCase) + ) + { + Logger.Warn("Unknown scheme for OpenUri: {Uri}", protocolArgs.Uri); + return; + } + + var publisher = Services.GetRequiredService>(); + + await publisher.PublishAsync(UriHandler.IpcKeySend, protocolArgs.Uri); + } + } + private static LoggingConfiguration ConfigureLogging() { var setupBuilder = LogManager.Setup(); diff --git a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs index ad019ba69..c60ec9d1b 100644 --- a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs +++ b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs @@ -5,6 +5,8 @@ using System.Runtime.Versioning; using System.Text.Json; using System.Threading.Tasks; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform; using MessagePipe; using Microsoft.Extensions.DependencyInjection; using Microsoft.Win32; @@ -56,8 +58,6 @@ public void SendAndExit(Uri uri) public void RegisterUriScheme() { - // Not supported on macos - if (Compat.IsWindows) { RegisterUriSchemeWin(); diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 203d039e8..eab18ea54 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -86,24 +86,17 @@ public static void Main(string[] args) GlobalConfig.HomeDir = homeDir; } - // Launched for custom URI scheme, handle and exit - if (Args.Uri is { } uriArg) + // Launched for custom URI scheme, handle and + // on macOS we use activation events so ignore this + if (!Compat.IsMacOS && Args.Uri is { } uriArg) { - try + if (Uri.TryCreate(uriArg, UriKind.Absolute, out var uri)) { - if ( - Uri.TryCreate(uriArg, UriKind.Absolute, out var uri) - && string.Equals(uri.Scheme, UriHandler.Scheme, StringComparison.OrdinalIgnoreCase) - ) - { - UriHandler.SendAndExit(uri); - } - - Environment.Exit(0); + HandleUriScheme(uri); } - catch (Exception e) + else { - Console.Error.WriteLine($"Uri handler encountered an error: {e.Message}"); + Console.Error.WriteLine($"Invalid URI argument: {uriArg}"); Environment.Exit(1); } } @@ -139,6 +132,29 @@ public static void Main(string[] args) BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } + [DoesNotReturn] + private static void HandleUriScheme(Uri uri) + { + Console.Error.WriteLine($"Handling URI: {uri}"); + + if (!string.Equals(uri.Scheme, UriHandler.Scheme, StringComparison.OrdinalIgnoreCase)) + { + Console.Error.WriteLine($"Unknown URI scheme: {uri.Scheme}"); + Environment.Exit(1); + } + + try + { + UriHandler.SendAndExit(uri); + Environment.Exit(0); + } + catch (Exception e) + { + Console.Error.WriteLine($"Uri handler encountered an error: {e.Message}"); + Environment.Exit(1); + } + } + /// /// Called in and UI tests to setup static configurations /// diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 60fd0db69..19536bca8 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -7,14 +7,10 @@ - Stability Matrix - Assets/AppIcon.icns - APPL WinExe win-x64;linux-x64;osx-x64;osx-arm64 enable true - app.manifest true ./Assets/Icon.ico 2.12.0-dev.999 @@ -22,13 +18,59 @@ true true - - - - StabilityMatrix.URL - stabilitymatrix;stabilitymatrix:// - - + + + app.manifest + + + + Stability Matrix + ai.lykos.stabilitymatrix + Assets/AppIcon.icns + APPL + + + + + + + + + + $(PlistDictOriginal.Substring(6, + $([MSBuild]::Subtract( + $(PlistDictOriginal.Length), + 13 + )) + )) + + + CFBundleURLTypes + + + CFBundleTypeRole + Viewer + CFBundleURLName + ai.lykos.stabilitymatrix + CFBundleURLIconFile + AppIcon.icns + CFBundleURLSchemes + + stabilitymatrix + + + + ]]> + + + + From 54c67a816de1bd539a8f9adf50741c9fd43fb1c9 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 10 Aug 2024 02:32:28 -0400 Subject: [PATCH 168/325] Add error dialogs for OAuth connection results --- .../Controls/BetterContentDialog.cs | 5 +- .../Languages/Resources.Designer.cs | 2405 +++++------------ .../Languages/Resources.resx | 3 + .../Dialogs/OAuthConnectViewModel.cs | 46 +- 4 files changed, 740 insertions(+), 1719 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs index b5b992d25..df8cb39d0 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs @@ -339,10 +339,11 @@ private void OnLoaded(object? sender, RoutedEventArgs? e) faBorder!.MinWidth = MinDialogWidth; } - if (MinDialogHeight > 0) + // This kind of bork for some reason + /*if (MinDialogHeight > 0) { faBorder!.MinHeight = MinDialogHeight; - } + }*/ if (MaxDialogHeight > 0) { diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 9114e0d0e..1168cbda4 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -11,46 +11,32 @@ namespace StabilityMatrix.Avalonia.Languages { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StabilityMatrix.Avalonia.Languages.Resources", typeof(Resources).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("StabilityMatrix.Avalonia.Languages.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,3054 +45,2043 @@ internal Resources() { } } - /// - /// Looks up a localized string similar to Add for All Users. - /// - public static string Action_AddForAllUsers { + public static string Action_Launch { get { - return ResourceManager.GetString("Action_AddForAllUsers", resourceCulture); + return ResourceManager.GetString("Action_Launch", resourceCulture); } } - /// - /// Looks up a localized string similar to Add for Current User. - /// - public static string Action_AddForCurrentUser { + public static string Action_Quit { get { - return ResourceManager.GetString("Action_AddForCurrentUser", resourceCulture); + return ResourceManager.GetString("Action_Quit", resourceCulture); } } - /// - /// Looks up a localized string similar to Add Package. - /// - public static string Action_AddPackage { + public static string Action_Save { get { - return ResourceManager.GetString("Action_AddPackage", resourceCulture); + return ResourceManager.GetString("Action_Save", resourceCulture); } } - /// - /// Looks up a localized string similar to Cancel. - /// public static string Action_Cancel { get { return ResourceManager.GetString("Action_Cancel", resourceCulture); } } - /// - /// Looks up a localized string similar to Check for Updates. - /// - public static string Action_CheckForUpdates { + public static string Label_Language { get { - return ResourceManager.GetString("Action_CheckForUpdates", resourceCulture); + return ResourceManager.GetString("Label_Language", resourceCulture); } } - /// - /// Looks up a localized string similar to Check Version. - /// - public static string Action_CheckVersion { + public static string Text_RelaunchRequiredToApplyLanguage { get { - return ResourceManager.GetString("Action_CheckVersion", resourceCulture); + return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); } } - /// - /// Looks up a localized string similar to Clear Selection. - /// - public static string Action_ClearSelection { + public static string Action_Relaunch { get { - return ResourceManager.GetString("Action_ClearSelection", resourceCulture); + return ResourceManager.GetString("Action_Relaunch", resourceCulture); } } - /// - /// Looks up a localized string similar to Close. - /// - public static string Action_Close { + public static string Action_RelaunchLater { get { - return ResourceManager.GetString("Action_Close", resourceCulture); + return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); } } - /// - /// Looks up a localized string similar to Connect. - /// - public static string Action_Connect { + public static string Label_RelaunchRequired { get { - return ResourceManager.GetString("Action_Connect", resourceCulture); + return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); } } - /// - /// Looks up a localized string similar to Consolidate. - /// - public static string Action_Consolidate { + public static string Label_UnknownPackage { get { - return ResourceManager.GetString("Action_Consolidate", resourceCulture); + return ResourceManager.GetString("Label_UnknownPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Continue. - /// - public static string Action_Continue { + public static string Action_Import { get { - return ResourceManager.GetString("Action_Continue", resourceCulture); + return ResourceManager.GetString("Action_Import", resourceCulture); } } - /// - /// Looks up a localized string similar to Copy. - /// - public static string Action_Copy { + public static string Label_PackageType { get { - return ResourceManager.GetString("Action_Copy", resourceCulture); + return ResourceManager.GetString("Label_PackageType", resourceCulture); } } - /// - /// Looks up a localized string similar to Copy as Bitmap. - /// - public static string Action_CopyAsBitmap { + public static string Label_Version { get { - return ResourceManager.GetString("Action_CopyAsBitmap", resourceCulture); + return ResourceManager.GetString("Label_Version", resourceCulture); } } - /// - /// Looks up a localized string similar to Copy Details. - /// - public static string Action_CopyDetails { + public static string Label_VersionType { get { - return ResourceManager.GetString("Action_CopyDetails", resourceCulture); + return ResourceManager.GetString("Label_VersionType", resourceCulture); } } - /// - /// Looks up a localized string similar to Copy Trigger Words. - /// - public static string Action_CopyTriggerWords { + public static string Label_Releases { get { - return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); + return ResourceManager.GetString("Label_Releases", resourceCulture); } } - /// - /// Looks up a localized string similar to Delete. - /// - public static string Action_Delete { + public static string Label_Branches { get { - return ResourceManager.GetString("Action_Delete", resourceCulture); + return ResourceManager.GetString("Label_Branches", resourceCulture); } } - /// - /// Looks up a localized string similar to Disconnect. - /// - public static string Action_Disconnect { + public static string Label_DragAndDropCheckpointsHereToImport { get { - return ResourceManager.GetString("Action_Disconnect", resourceCulture); + return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); } } - /// - /// Looks up a localized string similar to Downgrade. - /// - public static string Action_Downgrade { + public static string Label_Emphasis { get { - return ResourceManager.GetString("Action_Downgrade", resourceCulture); + return ResourceManager.GetString("Label_Emphasis", resourceCulture); } } - /// - /// Looks up a localized string similar to Download. - /// - public static string Action_Download { + public static string Label_Deemphasis { get { - return ResourceManager.GetString("Action_Download", resourceCulture); + return ResourceManager.GetString("Label_Deemphasis", resourceCulture); } } - /// - /// Looks up a localized string similar to Edit. - /// - public static string Action_Edit { + public static string Label_EmbeddingsOrTextualInversion { get { - return ResourceManager.GetString("Action_Edit", resourceCulture); + return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); } } - /// - /// Looks up a localized string similar to Exit Application. - /// - public static string Action_ExitApplication { + public static string Label_NetworksLoraOrLycoris { get { - return ResourceManager.GetString("Action_ExitApplication", resourceCulture); + return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); } } - /// - /// Looks up a localized string similar to Hide. - /// - public static string Action_Hide { + public static string Label_Comments { get { - return ResourceManager.GetString("Action_Hide", resourceCulture); + return ResourceManager.GetString("Label_Comments", resourceCulture); } } - /// - /// Looks up a localized string similar to Import. - /// - public static string Action_Import { + public static string Label_ShowPixelGridAtHighZoomLevels { get { - return ResourceManager.GetString("Action_Import", resourceCulture); + return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); } } - /// - /// Looks up a localized string similar to Install. - /// - public static string Action_Install { + public static string Label_Steps { get { - return ResourceManager.GetString("Action_Install", resourceCulture); + return ResourceManager.GetString("Label_Steps", resourceCulture); } } - /// - /// Looks up a localized string similar to Install Now. - /// - public static string Action_InstallNow { + public static string Label_StepsBase { get { - return ResourceManager.GetString("Action_InstallNow", resourceCulture); + return ResourceManager.GetString("Label_StepsBase", resourceCulture); } } - /// - /// Looks up a localized string similar to Launch. - /// - public static string Action_Launch { + public static string Label_StepsRefiner { get { - return ResourceManager.GetString("Action_Launch", resourceCulture); + return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); } } - /// - /// Looks up a localized string similar to Login. - /// - public static string Action_Login { + public static string Label_CFGScale { get { - return ResourceManager.GetString("Action_Login", resourceCulture); + return ResourceManager.GetString("Label_CFGScale", resourceCulture); } } - /// - /// Looks up a localized string similar to Move to Trash. - /// - public static string Action_MoveToTrash { + public static string Label_DenoisingStrength { get { - return ResourceManager.GetString("Action_MoveToTrash", resourceCulture); + return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); } } - /// - /// Looks up a localized string similar to New. - /// - public static string Action_New { + public static string Label_Width { get { - return ResourceManager.GetString("Action_New", resourceCulture); + return ResourceManager.GetString("Label_Width", resourceCulture); } } - /// - /// Looks up a localized string similar to OK. - /// - public static string Action_OK { + public static string Label_Height { get { - return ResourceManager.GetString("Action_OK", resourceCulture); + return ResourceManager.GetString("Label_Height", resourceCulture); } } - /// - /// Looks up a localized string similar to Open on GitHub. - /// - public static string Action_OpenGithub { + public static string Label_Refiner { get { - return ResourceManager.GetString("Action_OpenGithub", resourceCulture); + return ResourceManager.GetString("Label_Refiner", resourceCulture); } } - /// - /// Looks up a localized string similar to Open in Browser. - /// - public static string Action_OpenInBrowser { + public static string Label_VAE { get { - return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); + return ResourceManager.GetString("Label_VAE", resourceCulture); } } - /// - /// Looks up a localized string similar to Open in Explorer. - /// - public static string Action_OpenInExplorer { + public static string Label_Model { get { - return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); + return ResourceManager.GetString("Label_Model", resourceCulture); } } - /// - /// Looks up a localized string similar to Open in Finder. - /// - public static string Action_OpenInFinder { + public static string Action_Connect { get { - return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); + return ResourceManager.GetString("Action_Connect", resourceCulture); } } - /// - /// Looks up a localized string similar to Open in Image Viewer. - /// - public static string Action_OpenInViewer { + public static string Label_ConnectingEllipsis { get { - return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); + return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); } } - /// - /// Looks up a localized string similar to Open on CivitAI. - /// - public static string Action_OpenOnCivitAi { + public static string Action_Close { get { - return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); + return ResourceManager.GetString("Action_Close", resourceCulture); } } - /// - /// Looks up a localized string similar to Open on Hugging Face. - /// - public static string Action_OpenOnHuggingFace { + public static string Label_WaitingToConnectEllipsis { get { - return ResourceManager.GetString("Action_OpenOnHuggingFace", resourceCulture); + return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); } } - /// - /// Looks up a localized string similar to Open on OpenArt. - /// - public static string Action_OpenOnOpenArt { + public static string Label_UpdateAvailable { get { - return ResourceManager.GetString("Action_OpenOnOpenArt", resourceCulture); + return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); } } - /// - /// Looks up a localized string similar to Open Project.... - /// - public static string Action_OpenProjectEllipsis { + public static string Label_BecomeAPatron { get { - return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); + return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); } } - /// - /// Looks up a localized string similar to Open Web UI. - /// - public static string Action_OpenWebUI { + public static string Label_JoinDiscord { get { - return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); + return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); } } - /// - /// Looks up a localized string similar to Preview Preprocessor. - /// - public static string Action_PreviewPreprocessor { + public static string Label_Downloads { get { - return ResourceManager.GetString("Action_PreviewPreprocessor", resourceCulture); + return ResourceManager.GetString("Label_Downloads", resourceCulture); } } - /// - /// Looks up a localized string similar to Quit. - /// - public static string Action_Quit { + public static string Action_Install { get { - return ResourceManager.GetString("Action_Quit", resourceCulture); + return ResourceManager.GetString("Action_Install", resourceCulture); } } - /// - /// Looks up a localized string similar to Refresh. - /// - public static string Action_Refresh { + public static string Label_SkipSetup { get { - return ResourceManager.GetString("Action_Refresh", resourceCulture); + return ResourceManager.GetString("Label_SkipSetup", resourceCulture); } } - /// - /// Looks up a localized string similar to Relaunch. - /// - public static string Action_Relaunch { + public static string Label_UnexpectedErrorOccurred { get { - return ResourceManager.GetString("Action_Relaunch", resourceCulture); + return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); } } - /// - /// Looks up a localized string similar to Relaunch Later. - /// - public static string Action_RelaunchLater { + public static string Action_ExitApplication { get { - return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); + return ResourceManager.GetString("Action_ExitApplication", resourceCulture); } } - /// - /// Looks up a localized string similar to Remind Me Later. - /// - public static string Action_RemindMeLater { + public static string Label_DisplayName { get { - return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); + return ResourceManager.GetString("Label_DisplayName", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove. - /// - public static string Action_Remove { + public static string Label_InstallationWithThisNameExists { get { - return ResourceManager.GetString("Action_Remove", resourceCulture); + return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); } } - /// - /// Looks up a localized string similar to Rename. - /// - public static string Action_Rename { + public static string Label_PleaseChooseDifferentName { get { - return ResourceManager.GetString("Action_Rename", resourceCulture); + return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); } } - /// - /// Looks up a localized string similar to Replace Contents. - /// - public static string Action_ReplaceContents { + public static string Label_AdvancedOptions { get { - return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); + return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); } } - /// - /// Looks up a localized string similar to Restart. - /// - public static string Action_Restart { + public static string Label_Commit { get { - return ResourceManager.GetString("Action_Restart", resourceCulture); + return ResourceManager.GetString("Label_Commit", resourceCulture); } } - /// - /// Looks up a localized string similar to Restore Default Layout. - /// - public static string Action_RestoreDefaultLayout { + public static string Label_SharedModelFolderStrategy { get { - return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); + return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); } } - /// - /// Looks up a localized string similar to Retry. - /// - public static string Action_Retry { + public static string Label_PyTorchVersion { get { - return ResourceManager.GetString("Action_Retry", resourceCulture); + return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); } } - /// - /// Looks up a localized string similar to Save. - /// - public static string Action_Save { + public static string Label_CloseDialogWhenFinished { get { - return ResourceManager.GetString("Action_Save", resourceCulture); + return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); } } - /// - /// Looks up a localized string similar to Save As.... - /// - public static string Action_SaveAsEllipsis { + public static string Label_DataDirectory { get { - return ResourceManager.GetString("Action_SaveAsEllipsis", resourceCulture); + return ResourceManager.GetString("Label_DataDirectory", resourceCulture); } } - /// - /// Looks up a localized string similar to Search. - /// - public static string Action_Search { + public static string Label_DataDirectoryExplanation { get { - return ResourceManager.GetString("Action_Search", resourceCulture); + return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); } } - /// - /// Looks up a localized string similar to Select All. - /// - public static string Action_SelectAll { + public static string Label_FatWarning { get { - return ResourceManager.GetString("Action_SelectAll", resourceCulture); + return ResourceManager.GetString("Label_FatWarning", resourceCulture); } } - /// - /// Looks up a localized string similar to Select Directory. - /// - public static string Action_SelectDirectory { + public static string Label_PortableMode { get { - return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); + return ResourceManager.GetString("Label_PortableMode", resourceCulture); } } - /// - /// Looks up a localized string similar to Select File. - /// - public static string Action_SelectFile { + public static string Label_PortableModeExplanation { get { - return ResourceManager.GetString("Action_SelectFile", resourceCulture); + return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); } } - /// - /// Looks up a localized string similar to Send. - /// - public static string Action_Send { + public static string Action_Continue { get { - return ResourceManager.GetString("Action_Send", resourceCulture); + return ResourceManager.GetString("Action_Continue", resourceCulture); } } - /// - /// Looks up a localized string similar to Send Input. - /// - public static string Action_SendInput { + public static string Label_PreviousImage { get { - return ResourceManager.GetString("Action_SendInput", resourceCulture); + return ResourceManager.GetString("Label_PreviousImage", resourceCulture); } } - /// - /// Looks up a localized string similar to Send to Inference. - /// - public static string Action_SendToInference { + public static string Label_NextImage { get { - return ResourceManager.GetString("Action_SendToInference", resourceCulture); + return ResourceManager.GetString("Label_NextImage", resourceCulture); } } - /// - /// Looks up a localized string similar to Show in Explorer. - /// - public static string Action_ShowInExplorer { + public static string Label_ModelDescription { get { - return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); + return ResourceManager.GetString("Label_ModelDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to Signup. - /// - public static string Action_Signup { + public static string Label_NewVersionAvailable { get { - return ResourceManager.GetString("Action_Signup", resourceCulture); + return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); } } - /// - /// Looks up a localized string similar to Stop. - /// - public static string Action_Stop { + public static string Label_ImportLatest { get { - return ResourceManager.GetString("Action_Stop", resourceCulture); + return ResourceManager.GetString("Label_ImportLatest", resourceCulture); } } - /// - /// Looks up a localized string similar to Toggle Visibility. - /// - public static string Action_ToggleVisibility { + public static string Label_AllVersions { get { - return ResourceManager.GetString("Action_ToggleVisibility", resourceCulture); + return ResourceManager.GetString("Label_AllVersions", resourceCulture); } } - /// - /// Looks up a localized string similar to Uninstall. - /// - public static string Action_Uninstall { + public static string Label_ModelSearchWatermark { get { - return ResourceManager.GetString("Action_Uninstall", resourceCulture); + return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); } } - /// - /// Looks up a localized string similar to Update. - /// - public static string Action_Update { + public static string Action_Search { get { - return ResourceManager.GetString("Action_Update", resourceCulture); + return ResourceManager.GetString("Action_Search", resourceCulture); } } - /// - /// Looks up a localized string similar to Update Existing Metadata. - /// - public static string Action_UpdateExistingMetadata { + public static string Label_Sort { get { - return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); + return ResourceManager.GetString("Label_Sort", resourceCulture); } } - /// - /// Looks up a localized string similar to Upgrade. - /// - public static string Action_Upgrade { + public static string Label_TimePeriod { get { - return ResourceManager.GetString("Action_Upgrade", resourceCulture); + return ResourceManager.GetString("Label_TimePeriod", resourceCulture); } } - /// - /// Looks up a localized string similar to Yes. - /// - public static string Action_Yes { + public static string Label_ModelType { get { - return ResourceManager.GetString("Action_Yes", resourceCulture); + return ResourceManager.GetString("Label_ModelType", resourceCulture); } } - /// - /// Looks up a localized string similar to Please select a download location.. - /// - public static string Error_PleaseSelectDownloadLocation { + public static string Label_BaseModel { get { - return ResourceManager.GetString("Error_PleaseSelectDownloadLocation", resourceCulture); + return ResourceManager.GetString("Label_BaseModel", resourceCulture); } } - /// - /// Looks up a localized string similar to About. - /// - public static string Label_About { + public static string Label_ShowNsfwContent { get { - return ResourceManager.GetString("Label_About", resourceCulture); + return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); } } - /// - /// Looks up a localized string similar to Accounts. - /// - public static string Label_Accounts { + public static string Label_DataProvidedByCivitAi { get { - return ResourceManager.GetString("Label_Accounts", resourceCulture); + return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); } } - /// - /// Looks up a localized string similar to This action cannot be undone.. - /// - public static string Label_ActionCannotBeUndone { + public static string Label_Page { get { - return ResourceManager.GetString("Label_ActionCannotBeUndone", resourceCulture); + return ResourceManager.GetString("Label_Page", resourceCulture); } } - /// - /// Looks up a localized string similar to Addons. - /// - public static string Label_Addons { + public static string Label_FirstPage { get { - return ResourceManager.GetString("Label_Addons", resourceCulture); + return ResourceManager.GetString("Label_FirstPage", resourceCulture); } } - /// - /// Looks up a localized string similar to Add Stability Matrix to the Start Menu. - /// - public static string Label_AddToStartMenu { + public static string Label_PreviousPage { get { - return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); + return ResourceManager.GetString("Label_PreviousPage", resourceCulture); } } - /// - /// Looks up a localized string similar to Uses the current app location, you can run this again if you move the app. - /// - public static string Label_AddToStartMenu_Details { + public static string Label_NextPage { get { - return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); + return ResourceManager.GetString("Label_NextPage", resourceCulture); } } - /// - /// Looks up a localized string similar to Advanced Options. - /// - public static string Label_AdvancedOptions { + public static string Label_LastPage { get { - return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); + return ResourceManager.GetString("Label_LastPage", resourceCulture); } } - /// - /// Looks up a localized string similar to All Versions. - /// - public static string Label_AllVersions { + public static string Action_Rename { get { - return ResourceManager.GetString("Label_AllVersions", resourceCulture); + return ResourceManager.GetString("Action_Rename", resourceCulture); } } - /// - /// Looks up a localized string similar to Another instance of Stability Matrix is already running. Please close it before starting a new one.. - /// - public static string Label_AnotherInstanceAlreadyRunning { + public static string Action_Delete { get { - return ResourceManager.GetString("Label_AnotherInstanceAlreadyRunning", resourceCulture); + return ResourceManager.GetString("Action_Delete", resourceCulture); } } - /// - /// Looks up a localized string similar to API Key. - /// - public static string Label_ApiKey { + public static string Action_OpenOnCivitAi { get { - return ResourceManager.GetString("Label_ApiKey", resourceCulture); + return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); } } - /// - /// Looks up a localized string similar to App Data. - /// - public static string Label_AppData { + public static string Label_ConnectedModel { get { - return ResourceManager.GetString("Label_AppData", resourceCulture); + return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); } } - /// - /// Looks up a localized string similar to Appearance. - /// - public static string Label_Appearance { + public static string Label_LocalModel { get { - return ResourceManager.GetString("Label_Appearance", resourceCulture); + return ResourceManager.GetString("Label_LocalModel", resourceCulture); } } - /// - /// Looks up a localized string similar to App Folders. - /// - public static string Label_AppFolders { + public static string Action_ShowInExplorer { get { - return ResourceManager.GetString("Label_AppFolders", resourceCulture); + return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); } } - /// - /// Looks up a localized string similar to Are you sure?. - /// - public static string Label_AreYouSure { + public static string Action_New { get { - return ResourceManager.GetString("Label_AreYouSure", resourceCulture); + return ResourceManager.GetString("Action_New", resourceCulture); } } - /// - /// Looks up a localized string similar to Are you sure you want to delete {0} images?. - /// - public static string Label_AreYouSureDeleteImages { + public static string Label_Folder { get { - return ResourceManager.GetString("Label_AreYouSureDeleteImages", resourceCulture); + return ResourceManager.GetString("Label_Folder", resourceCulture); } } - /// - /// Looks up a localized string similar to Are you sure you want to delete {0} models?. - /// - public static string Label_AreYouSureDeleteModels { + public static string Label_DropFileToImport { get { - return ResourceManager.GetString("Label_AreYouSureDeleteModels", resourceCulture); + return ResourceManager.GetString("Label_DropFileToImport", resourceCulture); } } - /// - /// Looks up a localized string similar to Augmentation Level. - /// - public static string Label_AugmentationLevel { + public static string Label_ImportAsConnected { get { - return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); } } - /// - /// Looks up a localized string similar to Auto Completion. - /// - public static string Label_AutoCompletion { + public static string Label_ImportAsConnectedExplanation { get { - return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); } } - /// - /// Looks up a localized string similar to Automatically scroll to end of console output. - /// - public static string Label_AutoScrollToEnd { + public static string Label_Indexing { get { - return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); + return ResourceManager.GetString("Label_Indexing", resourceCulture); } } - /// - /// Looks up a localized string similar to Auto-Search on Load. - /// - public static string Label_AutoSearchOnLoad { + public static string Label_ModelsFolder { get { - return ResourceManager.GetString("Label_AutoSearchOnLoad", resourceCulture); + return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); } } - /// - /// Looks up a localized string similar to Automatically initiate a search when the model browser page is loaded. - /// - public static string Label_AutoSearchOnLoad_Description { + public static string Label_Categories { get { - return ResourceManager.GetString("Label_AutoSearchOnLoad_Description", resourceCulture); + return ResourceManager.GetString("Label_Categories", resourceCulture); } } - /// - /// Looks up a localized string similar to Auto Updates. - /// - public static string Label_AutoUpdates { + public static string Label_LetsGetStarted { get { - return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); + return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); } } - /// - /// Looks up a localized string similar to Base Model. - /// - public static string Label_BaseModel { + public static string Label_ReadAndAgree { get { - return ResourceManager.GetString("Label_BaseModel", resourceCulture); + return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); } } - /// - /// Looks up a localized string similar to Batch Index. - /// - public static string Label_BatchIndex { + public static string Label_LicenseAgreement { get { - return ResourceManager.GetString("Label_BatchIndex", resourceCulture); + return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); } } - /// - /// Looks up a localized string similar to Become a Patron. - /// - public static string Label_BecomeAPatron { + public static string Label_FindConnectedMetadata { get { - return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); + return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); } } - /// - /// Looks up a localized string similar to Branch. - /// - public static string Label_Branch { + public static string Label_ShowModelImages { get { - return ResourceManager.GetString("Label_Branch", resourceCulture); + return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); } } - /// - /// Looks up a localized string similar to Branches. - /// - public static string Label_Branches { + public static string Label_Appearance { get { - return ResourceManager.GetString("Label_Branches", resourceCulture); + return ResourceManager.GetString("Label_Appearance", resourceCulture); } } - /// - /// Looks up a localized string similar to Callstack. - /// - public static string Label_Callstack { + public static string Label_Theme { get { - return ResourceManager.GetString("Label_Callstack", resourceCulture); + return ResourceManager.GetString("Label_Theme", resourceCulture); } } - /// - /// Looks up a localized string similar to Categories. - /// - public static string Label_Categories { + public static string Label_CheckpointManager { get { - return ResourceManager.GetString("Label_Categories", resourceCulture); + return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); } } - /// - /// Looks up a localized string similar to CFG Scale. - /// - public static string Label_CFGScale { + public static string Label_RemoveSymlinksOnShutdown { get { - return ResourceManager.GetString("Label_CFGScale", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); } } - /// - /// Looks up a localized string similar to We're checking some hardware specifications to determine compatibility.. - /// - public static string Label_CheckingHardware { + public static string Label_RemoveSymlinksOnShutdown_Details { get { - return ResourceManager.GetString("Label_CheckingHardware", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to Checkpoint Manager. - /// - public static string Label_CheckpointManager { + public static string Label_ResetCheckpointsCache { get { - return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); } } - /// - /// Looks up a localized string similar to Checkpoints. - /// - public static string Label_Checkpoints { + public static string Label_ResetCheckpointsCache_Details { get { - return ResourceManager.GetString("Label_Checkpoints", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to CivitAI. - /// - public static string Label_CivitAi { + public static string Label_PackageEnvironment { get { - return ResourceManager.GetString("Label_CivitAi", resourceCulture); + return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); } } - /// - /// Looks up a localized string similar to You must be logged in to download this checkpoint. Please enter a CivitAI API Key in the settings.. - /// - public static string Label_CivitAiLoginRequired { + public static string Action_Edit { get { - return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); + return ResourceManager.GetString("Action_Edit", resourceCulture); } } - /// - /// Looks up a localized string similar to Clipping Mask. - /// - public static string Label_ClippingMask { + public static string Label_EnvironmentVariables { get { - return ResourceManager.GetString("Label_ClippingMask", resourceCulture); + return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); } } - /// - /// Looks up a localized string similar to CLIP Skip. - /// - public static string Label_CLIPSkip { + public static string Label_EmbeddedPython { get { - return ResourceManager.GetString("Label_CLIPSkip", resourceCulture); + return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); } } - /// - /// Looks up a localized string similar to CLIP Strength. - /// - public static string Label_CLIPStrength { + public static string Action_CheckVersion { get { - return ResourceManager.GetString("Label_CLIPStrength", resourceCulture); + return ResourceManager.GetString("Action_CheckVersion", resourceCulture); } } - /// - /// Looks up a localized string similar to Close dialog when finished. - /// - public static string Label_CloseDialogWhenFinished { + public static string Label_Integrations { get { - return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); + return ResourceManager.GetString("Label_Integrations", resourceCulture); } } - /// - /// Looks up a localized string similar to ComfyUI is required to install this package. Would you like to install it now?. - /// - public static string Label_ComfyRequiredDetail { + public static string Label_DiscordRichPresence { get { - return ResourceManager.GetString("Label_ComfyRequiredDetail", resourceCulture); + return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); } } - /// - /// Looks up a localized string similar to ComfyUI Required. - /// - public static string Label_ComfyRequiredTitle { + public static string Label_System { get { - return ResourceManager.GetString("Label_ComfyRequiredTitle", resourceCulture); + return ResourceManager.GetString("Label_System", resourceCulture); } } - /// - /// Looks up a localized string similar to Comments. - /// - public static string Label_Comments { + public static string Label_AddToStartMenu { get { - return ResourceManager.GetString("Label_Comments", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); } } - /// - /// Looks up a localized string similar to Commit. - /// - public static string Label_Commit { + public static string Label_AddToStartMenu_Details { get { - return ResourceManager.GetString("Label_Commit", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to Replace underscores with spaces when inserting completions. - /// - public static string Label_CompletionReplaceUnderscoresWithSpaces { + public static string Label_OnlyAvailableOnWindows { get { - return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); + return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); } } - /// - /// Looks up a localized string similar to Config. - /// - public static string Label_Config { + public static string Action_AddForCurrentUser { get { - return ResourceManager.GetString("Label_Config", resourceCulture); + return ResourceManager.GetString("Action_AddForCurrentUser", resourceCulture); } } - /// - /// Looks up a localized string similar to Confirm Delete. - /// - public static string Label_ConfirmDelete { + public static string Action_AddForAllUsers { get { - return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); + return ResourceManager.GetString("Action_AddForAllUsers", resourceCulture); } } - /// - /// Looks up a localized string similar to Confirm Exit. - /// - public static string Label_ConfirmExit { + public static string Label_SelectNewDataDirectory { get { - return ResourceManager.GetString("Label_ConfirmExit", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); } } - /// - /// Looks up a localized string similar to Are you sure you want to exit? This will also close any currently running packages.. - /// - public static string Label_ConfirmExitDetail { + public static string Label_SelectNewDataDirectory_Details { get { - return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to Confirm Password. - /// - public static string Label_ConfirmPassword { + public static string Action_SelectDirectory { get { - return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); + return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); } } - /// - /// Looks up a localized string similar to Confirm?. - /// - public static string Label_ConfirmQuestion { + public static string Label_About { get { - return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); + return ResourceManager.GetString("Label_About", resourceCulture); } } - /// - /// Looks up a localized string similar to Connected. - /// - public static string Label_Connected { + public static string Label_StabilityMatrix { get { - return ResourceManager.GetString("Label_Connected", resourceCulture); + return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); } } - /// - /// Looks up a localized string similar to Connected Model. - /// - public static string Label_ConnectedModel { + public static string Label_LicenseAndOpenSourceNotices { get { - return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); + return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); } } - /// - /// Looks up a localized string similar to Connecting.... - /// - public static string Label_ConnectingEllipsis { + public static string TeachingTip_ClickLaunchToGetStarted { get { - return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); + return ResourceManager.GetString("TeachingTip_ClickLaunchToGetStarted", resourceCulture); } } - /// - /// Looks up a localized string similar to Console. - /// - public static string Label_Console { + public static string Action_Stop { get { - return ResourceManager.GetString("Label_Console", resourceCulture); + return ResourceManager.GetString("Action_Stop", resourceCulture); } } - /// - /// Looks up a localized string similar to This will move all generated images from the selected packages to the Consolidated directory of the shared outputs folder. This action cannot be undone.. - /// - public static string Label_ConsolidateExplanation { + public static string Action_SendInput { get { - return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); + return ResourceManager.GetString("Action_SendInput", resourceCulture); } } - /// - /// Looks up a localized string similar to Control Steps. - /// - public static string Label_ControlSteps { + public static string Label_Input { get { - return ResourceManager.GetString("Label_ControlSteps", resourceCulture); + return ResourceManager.GetString("Label_Input", resourceCulture); } } - /// - /// Looks up a localized string similar to Control Weight. - /// - public static string Label_ControlWeight { + public static string Action_Send { get { - return ResourceManager.GetString("Label_ControlWeight", resourceCulture); + return ResourceManager.GetString("Action_Send", resourceCulture); } } - /// - /// Looks up a localized string similar to Current directory:. - /// - public static string Label_CurrentDirectory { + public static string Label_InputRequired { get { - return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); + return ResourceManager.GetString("Label_InputRequired", resourceCulture); } } - /// - /// Looks up a localized string similar to Data Directory. - /// - public static string Label_DataDirectory { + public static string Label_ConfirmQuestion { get { - return ResourceManager.GetString("Label_DataDirectory", resourceCulture); + return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); } } - /// - /// Looks up a localized string similar to This is where application data (model checkpoints, web UIs, etc.) will be installed.. - /// - public static string Label_DataDirectoryExplanation { + public static string Action_Yes { get { - return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); + return ResourceManager.GetString("Action_Yes", resourceCulture); } } - /// - /// Looks up a localized string similar to Data Folder Name. - /// - public static string Label_DataFolderName { + public static string Label_No { get { - return ResourceManager.GetString("Label_DataFolderName", resourceCulture); + return ResourceManager.GetString("Label_No", resourceCulture); } } - /// - /// Looks up a localized string similar to Data provided by CivitAI. - /// - public static string Label_DataProvidedByCivitAi { + public static string Action_OpenWebUI { get { - return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); + return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); } } - /// - /// Looks up a localized string similar to Deemphasis. - /// - public static string Label_Deemphasis { + public static string Text_WelcomeToStabilityMatrix { get { - return ResourceManager.GetString("Label_Deemphasis", resourceCulture); + return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); } } - /// - /// Looks up a localized string similar to Delete Permanently. - /// - public static string Label_DeletePermanently { + public static string Text_OneClickInstaller_SubHeader { get { - return ResourceManager.GetString("Label_DeletePermanently", resourceCulture); + return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Denoising Strength. - /// - public static string Label_DenoisingStrength { + public static string Label_Installing { get { - return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); + return ResourceManager.GetString("Label_Installing", resourceCulture); } } - /// - /// Looks up a localized string similar to Details. - /// - public static string Label_Details { + public static string Text_ProceedingToLaunchPage { get { - return ResourceManager.GetString("Label_Details", resourceCulture); + return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); } } - /// - /// Looks up a localized string similar to Disable Update Check. - /// - public static string Label_DisableUpdateCheck { + public static string Progress_DownloadingPackage { get { - return ResourceManager.GetString("Label_DisableUpdateCheck", resourceCulture); + return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Discord Rich Presence. - /// - public static string Label_DiscordRichPresence { + public static string Progress_DownloadComplete { get { - return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); + return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); } } - /// - /// Looks up a localized string similar to Display Name. - /// - public static string Label_DisplayName { + public static string Progress_InstallationComplete { get { - return ResourceManager.GetString("Label_DisplayName", resourceCulture); + return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); } } - /// - /// Looks up a localized string similar to Download Failed. - /// - public static string Label_DownloadFailed { + public static string Progress_InstallingPrerequisites { get { - return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); } } - /// - /// Looks up a localized string similar to Downloads. - /// - public static string Label_Downloads { + public static string Progress_InstallingPackageRequirements { get { - return ResourceManager.GetString("Label_Downloads", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); } } - /// - /// Looks up a localized string similar to Drag & Drop checkpoints here to import. - /// - public static string Label_DragAndDropCheckpointsHereToImport { + public static string Action_OpenInExplorer { get { - return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); + return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); } } - /// - /// Looks up a localized string similar to Drop file here to import. - /// - public static string Label_DropFileToImport { + public static string Action_OpenInFinder { get { - return ResourceManager.GetString("Label_DropFileToImport", resourceCulture); + return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); } } - /// - /// Looks up a localized string similar to Email. - /// - public static string Label_Email { + public static string Action_Uninstall { get { - return ResourceManager.GetString("Label_Email", resourceCulture); + return ResourceManager.GetString("Action_Uninstall", resourceCulture); } } - /// - /// Looks up a localized string similar to Embedded Python. - /// - public static string Label_EmbeddedPython { + public static string Action_CheckForUpdates { get { - return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); + return ResourceManager.GetString("Action_CheckForUpdates", resourceCulture); } } - /// - /// Looks up a localized string similar to Embeddings / Textual Inversion. - /// - public static string Label_EmbeddingsOrTextualInversion { + public static string Action_Update { get { - return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); + return ResourceManager.GetString("Action_Update", resourceCulture); } } - /// - /// Looks up a localized string similar to Emphasis. - /// - public static string Label_Emphasis { + public static string Action_AddPackage { get { - return ResourceManager.GetString("Label_Emphasis", resourceCulture); + return ResourceManager.GetString("Action_AddPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Environment Variables. - /// - public static string Label_EnvironmentVariables { + public static string TeachingTip_AddPackageToGetStarted { get { - return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); + return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); } } - /// - /// Looks up a localized string similar to Name. - /// public static string Label_EnvVarsTable_Name { get { return ResourceManager.GetString("Label_EnvVarsTable_Name", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// public static string Label_EnvVarsTable_Value { get { return ResourceManager.GetString("Label_EnvVarsTable_Value", resourceCulture); } } - /// - /// Looks up a localized string similar to Error installing package. - /// - public static string Label_ErrorInstallingPackage { + public static string Action_Remove { get { - return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); + return ResourceManager.GetString("Action_Remove", resourceCulture); } } - /// - /// Looks up a localized string similar to Error retrieving workflows. - /// - public static string Label_ErrorRetrievingWorkflows { + public static string Label_Details { get { - return ResourceManager.GetString("Label_ErrorRetrievingWorkflows", resourceCulture); + return ResourceManager.GetString("Label_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to Everything looks good!. - /// - public static string Label_EverythingLooksGood { + public static string Label_Callstack { get { - return ResourceManager.GetString("Label_EverythingLooksGood", resourceCulture); + return ResourceManager.GetString("Label_Callstack", resourceCulture); } } - /// - /// Looks up a localized string similar to Extra Networks (Lora / LyCORIS). - /// - public static string Label_ExtraNetworks { + public static string Label_InnerException { get { - return ResourceManager.GetString("Label_ExtraNetworks", resourceCulture); + return ResourceManager.GetString("Label_InnerException", resourceCulture); } } - /// - /// Looks up a localized string similar to You may encounter errors when using a FAT32 or exFAT drive. Select a different drive for a smoother experience.. - /// - public static string Label_FatWarning { + public static string Label_SearchEllipsis { get { - return ResourceManager.GetString("Label_FatWarning", resourceCulture); + return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); } } - /// - /// Looks up a localized string similar to Find Connected Metadata. - /// - public static string Label_FindConnectedMetadata { + public static string Action_OK { get { - return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); + return ResourceManager.GetString("Action_OK", resourceCulture); } } - /// - /// Looks up a localized string similar to Find in Model Browser. - /// - public static string Label_FindInModelBrowser { + public static string Action_Retry { get { - return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); + return ResourceManager.GetString("Action_Retry", resourceCulture); } } - /// - /// Looks up a localized string similar to Finished importing workflow and custom nodes. - /// - public static string Label_FinishedImportingWorkflow { + public static string Label_PythonVersionInfo { get { - return ResourceManager.GetString("Label_FinishedImportingWorkflow", resourceCulture); + return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); } } - /// - /// Looks up a localized string similar to First Page. - /// - public static string Label_FirstPage { + public static string Action_Restart { get { - return ResourceManager.GetString("Label_FirstPage", resourceCulture); + return ResourceManager.GetString("Action_Restart", resourceCulture); } } - /// - /// Looks up a localized string similar to Folder. - /// - public static string Label_Folder { + public static string Label_ConfirmDelete { get { - return ResourceManager.GetString("Label_Folder", resourceCulture); + return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); } } - /// - /// Looks up a localized string similar to Frames Per Second. - /// - public static string Label_Fps { + public static string Text_PackageUninstall_Details { get { - return ResourceManager.GetString("Label_Fps", resourceCulture); + return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); } } - /// - /// Looks up a localized string similar to Frames. - /// - public static string Label_Frames { + public static string Progress_UninstallingPackage { get { - return ResourceManager.GetString("Label_Frames", resourceCulture); + return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to General. - /// - public static string Label_General { + public static string Label_PackageUninstalled { get { - return ResourceManager.GetString("Label_General", resourceCulture); + return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); } } - /// - /// Looks up a localized string similar to Height. - /// - public static string Label_Height { + public static string Text_SomeFilesCouldNotBeDeleted { get { - return ResourceManager.GetString("Label_Height", resourceCulture); + return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); } } - /// - /// Looks up a localized string similar to History Size. - /// - public static string Label_HistorySize { + public static string Label_InvalidPackageType { get { - return ResourceManager.GetString("Label_HistorySize", resourceCulture); + return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); } } - /// - /// Looks up a localized string similar to The number of lines above the ones displayed in the console you can scroll back to. - /// - public static string Label_HistorySize_Description { + public static string TextTemplate_UpdatingPackage { get { - return ResourceManager.GetString("Label_HistorySize_Description", resourceCulture); + return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Holiday Mode. - /// - public static string Label_HolidayMode { + public static string Progress_UpdateComplete { get { - return ResourceManager.GetString("Label_HolidayMode", resourceCulture); + return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); } } - /// - /// Looks up a localized string similar to Hugging Face. - /// - public static string Label_HuggingFace { + public static string TextTemplate_PackageUpdatedToLatest { get { - return ResourceManager.GetString("Label_HuggingFace", resourceCulture); + return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); } } - /// - /// Looks up a localized string similar to Image to Image. - /// - public static string Label_ImageToImage { + public static string TextTemplate_ErrorUpdatingPackage { get { - return ResourceManager.GetString("Label_ImageToImage", resourceCulture); + return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Image to Video. - /// - public static string Label_ImageToVideo { + public static string Progress_UpdateFailed { get { - return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); + return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); } } - /// - /// Looks up a localized string similar to Image Viewer. - /// - public static string Label_ImageViewer { + public static string Action_OpenInBrowser { get { - return ResourceManager.GetString("Label_ImageViewer", resourceCulture); + return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); } } - /// - /// Looks up a localized string similar to Import with Metadata. - /// - public static string Label_ImportAsConnected { + public static string Label_ErrorInstallingPackage { get { - return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); + return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); } } - /// - /// Looks up a localized string similar to Search for connected metadata on new local imports. - /// - public static string Label_ImportAsConnectedExplanation { + public static string Label_Branch { get { - return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); + return ResourceManager.GetString("Label_Branch", resourceCulture); } } - /// - /// Looks up a localized string similar to Import Latest -. - /// - public static string Label_ImportLatest { + public static string Label_AutoScrollToEnd { get { - return ResourceManager.GetString("Label_ImportLatest", resourceCulture); + return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); } } - /// - /// Looks up a localized string similar to Indexing.... - /// - public static string Label_Indexing { + public static string Label_License { get { - return ResourceManager.GetString("Label_Indexing", resourceCulture); + return ResourceManager.GetString("Label_License", resourceCulture); } } - /// - /// Looks up a localized string similar to Inference. - /// - public static string Label_Inference { + public static string Label_SharedModelStrategyShort { get { - return ResourceManager.GetString("Label_Inference", resourceCulture); + return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); } } - /// - /// Looks up a localized string similar to Infinite Scrolling. - /// - public static string Label_InfiniteScrolling { + public static string Label_PleaseSelectDataDirectory { get { - return ResourceManager.GetString("Label_InfiniteScrolling", resourceCulture); + return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); } } - /// - /// Looks up a localized string similar to Inner exception. - /// - public static string Label_InnerException { + public static string Label_DataFolderName { get { - return ResourceManager.GetString("Label_InnerException", resourceCulture); + return ResourceManager.GetString("Label_DataFolderName", resourceCulture); } } - /// - /// Looks up a localized string similar to Inpainting. - /// - public static string Label_Inpainting { + public static string Label_CurrentDirectory { get { - return ResourceManager.GetString("Label_Inpainting", resourceCulture); + return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); } } - /// - /// Looks up a localized string similar to Input. - /// - public static string Label_Input { + public static string Text_AppWillRelaunchAfterUpdate { get { - return ResourceManager.GetString("Label_Input", resourceCulture); + return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); } } - /// - /// Looks up a localized string similar to Input required. - /// - public static string Label_InputRequired { + public static string Action_RemindMeLater { get { - return ResourceManager.GetString("Label_InputRequired", resourceCulture); + return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); } } - /// - /// Looks up a localized string similar to An installation with this name already exists.. - /// - public static string Label_InstallationWithThisNameExists { + public static string Action_InstallNow { get { - return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); + return ResourceManager.GetString("Action_InstallNow", resourceCulture); } } - /// - /// Looks up a localized string similar to Installed. - /// - public static string Label_Installed { + public static string Label_ReleaseNotes { get { - return ResourceManager.GetString("Label_Installed", resourceCulture); + return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); } } - /// - /// Looks up a localized string similar to Installing. - /// - public static string Label_Installing { + public static string Action_OpenProjectEllipsis { get { - return ResourceManager.GetString("Label_Installing", resourceCulture); + return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); } } - /// - /// Looks up a localized string similar to Integrations. - /// - public static string Label_Integrations { + public static string Action_SaveAsEllipsis { get { - return ResourceManager.GetString("Label_Integrations", resourceCulture); + return ResourceManager.GetString("Action_SaveAsEllipsis", resourceCulture); } } - /// - /// Looks up a localized string similar to Invalid Package type. - /// - public static string Label_InvalidPackageType { + public static string Action_RestoreDefaultLayout { get { - return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); + return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); } } - /// - /// Looks up a localized string similar to Join Discord Server. - /// - public static string Label_JoinDiscord { + public static string Label_UseSharedOutputFolder { get { - return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); + return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); } } - /// - /// Looks up a localized string similar to Language. - /// - public static string Label_Language { + public static string Label_BatchIndex { get { - return ResourceManager.GetString("Label_Language", resourceCulture); + return ResourceManager.GetString("Label_BatchIndex", resourceCulture); } } - /// - /// Looks up a localized string similar to Last Page. - /// - public static string Label_LastPage { + public static string Action_Copy { get { - return ResourceManager.GetString("Label_LastPage", resourceCulture); + return ResourceManager.GetString("Action_Copy", resourceCulture); } } - /// - /// Looks up a localized string similar to Let's get started. - /// - public static string Label_LetsGetStarted { + public static string Action_OpenInViewer { get { - return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); + return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); } } - /// - /// Looks up a localized string similar to License. - /// - public static string Label_License { + public static string Label_NumImagesSelected { get { - return ResourceManager.GetString("Label_License", resourceCulture); + return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); } } - /// - /// Looks up a localized string similar to License Agreement.. - /// - public static string Label_LicenseAgreement { + public static string Label_OutputFolder { get { - return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); + return ResourceManager.GetString("Label_OutputFolder", resourceCulture); } } - /// - /// Looks up a localized string similar to License and Open Source Notices. - /// - public static string Label_LicenseAndOpenSourceNotices { + public static string Label_OutputType { get { - return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); + return ResourceManager.GetString("Label_OutputType", resourceCulture); } } - /// - /// Looks up a localized string similar to Local Model. - /// - public static string Label_LocalModel { + public static string Action_ClearSelection { get { - return ResourceManager.GetString("Label_LocalModel", resourceCulture); + return ResourceManager.GetString("Action_ClearSelection", resourceCulture); } } - /// - /// Looks up a localized string similar to Logs. - /// - public static string Label_Logs { + public static string Action_SelectAll { get { - return ResourceManager.GetString("Label_Logs", resourceCulture); + return ResourceManager.GetString("Action_SelectAll", resourceCulture); } } - /// - /// Looks up a localized string similar to Lossless. - /// - public static string Label_Lossless { + public static string Action_SendToInference { get { - return ResourceManager.GetString("Label_Lossless", resourceCulture); + return ResourceManager.GetString("Action_SendToInference", resourceCulture); } } - /// - /// Looks up a localized string similar to Min CFG. - /// - public static string Label_MinCfg { + public static string Label_TextToImage { get { - return ResourceManager.GetString("Label_MinCfg", resourceCulture); + return ResourceManager.GetString("Label_TextToImage", resourceCulture); } } - /// - /// Looks up a localized string similar to Missing Image File. - /// - public static string Label_MissingImageFile { + public static string Label_ImageToImage { get { - return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); + return ResourceManager.GetString("Label_ImageToImage", resourceCulture); } } - /// - /// Looks up a localized string similar to Model. - /// - public static string Label_Model { + public static string Label_Inpainting { get { - return ResourceManager.GetString("Label_Model", resourceCulture); + return ResourceManager.GetString("Label_Inpainting", resourceCulture); } } - /// - /// Looks up a localized string similar to Model Browser. - /// - public static string Label_ModelBrowser { + public static string Label_Upscale { get { - return ResourceManager.GetString("Label_ModelBrowser", resourceCulture); + return ResourceManager.GetString("Label_Upscale", resourceCulture); } } - /// - /// Looks up a localized string similar to Model Description. - /// - public static string Label_ModelDescription { + public static string Label_OutputsPageTitle { get { - return ResourceManager.GetString("Label_ModelDescription", resourceCulture); + return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Search models, #tags, or @users. - /// - public static string Label_ModelSearchWatermark { + public static string Label_OneImageSelected { get { - return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); + return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); } } - /// - /// Looks up a localized string similar to Models Folder. - /// - public static string Label_ModelsFolder { + public static string Label_Preprocessor { get { - return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); + return ResourceManager.GetString("Label_Preprocessor", resourceCulture); } } - /// - /// Looks up a localized string similar to Model Type. - /// - public static string Label_ModelType { + public static string Label_Strength { get { - return ResourceManager.GetString("Label_ModelType", resourceCulture); + return ResourceManager.GetString("Label_Strength", resourceCulture); } } - /// - /// Looks up a localized string similar to Motion Bucket ID. - /// - public static string Label_MotionBucketId { + public static string Label_ControlWeight { get { - return ResourceManager.GetString("Label_MotionBucketId", resourceCulture); + return ResourceManager.GetString("Label_ControlWeight", resourceCulture); } } - /// - /// Looks up a localized string similar to Networks (Lora / LyCORIS). - /// - public static string Label_NetworksLoraOrLycoris { + public static string Label_ControlSteps { get { - return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); + return ResourceManager.GetString("Label_ControlSteps", resourceCulture); } } - /// - /// Looks up a localized string similar to A new version of Stability Matrix is available!. - /// - public static string Label_NewVersionAvailable { + public static string Label_PythonPackages { get { - return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); + return ResourceManager.GetString("Label_PythonPackages", resourceCulture); } } - /// - /// Looks up a localized string similar to Next Image. - /// - public static string Label_NextImage { + public static string Action_Consolidate { get { - return ResourceManager.GetString("Label_NextImage", resourceCulture); + return ResourceManager.GetString("Action_Consolidate", resourceCulture); + } + } + + public static string Label_AreYouSure { + get { + return ResourceManager.GetString("Label_AreYouSure", resourceCulture); + } + } + + public static string Label_ConsolidateExplanation { + get { + return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); } } - /// - /// Looks up a localized string similar to Next Page. - /// - public static string Label_NextPage { + public static string Action_Refresh { get { - return ResourceManager.GetString("Label_NextPage", resourceCulture); + return ResourceManager.GetString("Action_Refresh", resourceCulture); } } - /// - /// Looks up a localized string similar to No. - /// - public static string Label_No { + public static string Action_Upgrade { get { - return ResourceManager.GetString("Label_No", resourceCulture); + return ResourceManager.GetString("Action_Upgrade", resourceCulture); } } - /// - /// Looks up a localized string similar to Node Details. - /// - public static string Label_NodeDetails { + public static string Action_Downgrade { get { - return ResourceManager.GetString("Label_NodeDetails", resourceCulture); + return ResourceManager.GetString("Action_Downgrade", resourceCulture); } } - /// - /// Looks up a localized string similar to No extensions found.. - /// - public static string Label_NoExtensionsFound { + public static string Action_OpenGithub { get { - return ResourceManager.GetString("Label_NoExtensionsFound", resourceCulture); + return ResourceManager.GetString("Action_OpenGithub", resourceCulture); } } - /// - /// Looks up a localized string similar to None. - /// - public static string Label_NotificationOption_None { + public static string Label_Connected { get { - return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture); + return ResourceManager.GetString("Label_Connected", resourceCulture); } } - /// - /// Looks up a localized string similar to Notifications. - /// - public static string Label_Notifications { + public static string Action_Disconnect { get { - return ResourceManager.GetString("Label_Notifications", resourceCulture); + return ResourceManager.GetString("Action_Disconnect", resourceCulture); } } - /// - /// Looks up a localized string similar to Number Format. - /// - public static string Label_NumberFormat { + public static string Label_Email { get { - return ResourceManager.GetString("Label_NumberFormat", resourceCulture); + return ResourceManager.GetString("Label_Email", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} images selected. - /// - public static string Label_NumImagesSelected { + public static string Label_Username { get { - return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); + return ResourceManager.GetString("Label_Username", resourceCulture); } } - /// - /// Looks up a localized string similar to We recommend a GPU with CUDA support for the best experience. You can continue without one, but some packages may not work, and inference may be slower.. - /// - public static string Label_NvidiaGpuRecommended { + public static string Label_Password { get { - return ResourceManager.GetString("Label_NvidiaGpuRecommended", resourceCulture); + return ResourceManager.GetString("Label_Password", resourceCulture); } } - /// - /// Looks up a localized string similar to 1 image selected. - /// - public static string Label_OneImageSelected { + public static string Action_Login { get { - return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); + return ResourceManager.GetString("Action_Login", resourceCulture); } } - /// - /// Looks up a localized string similar to Only available on Windows. - /// - public static string Label_OnlyAvailableOnWindows { + public static string Action_Signup { get { - return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); + return ResourceManager.GetString("Action_Signup", resourceCulture); } } - /// - /// Looks up a localized string similar to OpenArt Browser. - /// - public static string Label_OpenArtBrowser { + public static string Label_ConfirmPassword { get { - return ResourceManager.GetString("Label_OpenArtBrowser", resourceCulture); + return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); } } - /// - /// Looks up a localized string similar to Output Folder. - /// - public static string Label_OutputFolder { + public static string Label_ApiKey { get { - return ResourceManager.GetString("Label_OutputFolder", resourceCulture); + return ResourceManager.GetString("Label_ApiKey", resourceCulture); } } - /// - /// Looks up a localized string similar to Output Image Files. - /// - public static string Label_OutputImageFiles { + public static string Label_Accounts { get { - return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); + return ResourceManager.GetString("Label_Accounts", resourceCulture); } } - /// - /// Looks up a localized string similar to Output Browser. - /// - public static string Label_OutputsPageTitle { + public static string Label_CivitAiLoginRequired { get { - return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); + return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); } } - /// - /// Looks up a localized string similar to Output Type. - /// - public static string Label_OutputType { + public static string Label_DownloadFailed { get { - return ResourceManager.GetString("Label_OutputType", resourceCulture); + return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); } } - /// - /// Looks up a localized string similar to Package Environment. - /// - public static string Label_PackageEnvironment { + public static string Label_AutoUpdates { get { - return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); + return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); } } - /// - /// Looks up a localized string similar to Packages. - /// - public static string Label_Packages { + public static string Label_UpdatesPreviewChannelDescription { get { - return ResourceManager.GetString("Label_Packages", resourceCulture); + return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to Package Type. - /// - public static string Label_PackageType { + public static string Label_UpdatesDevChannelDescription { get { - return ResourceManager.GetString("Label_PackageType", resourceCulture); + return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to Package Uninstalled. - /// - public static string Label_PackageUninstalled { + public static string Label_Updates { get { - return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); + return ResourceManager.GetString("Label_Updates", resourceCulture); } } - /// - /// Looks up a localized string similar to Page. - /// - public static string Label_Page { + public static string Label_YouAreUpToDate { get { - return ResourceManager.GetString("Label_Page", resourceCulture); + return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); } } - /// - /// Looks up a localized string similar to Password. - /// - public static string Label_Password { + public static string TextTemplate_LastChecked { get { - return ResourceManager.GetString("Label_Password", resourceCulture); + return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); } } - /// - /// Looks up a localized string similar to Please choose a different name or select a different install location.. - /// - public static string Label_PleaseChooseDifferentName { + public static string Action_CopyTriggerWords { get { - return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); + return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); } } - /// - /// Looks up a localized string similar to Please Select a Data Directory. - /// - public static string Label_PleaseSelectDataDirectory { + public static string Label_TriggerWords { get { - return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_TriggerWords", resourceCulture); } } - /// - /// Looks up a localized string similar to Portable Mode. - /// - public static string Label_PortableMode { + public static string TeachingTip_MoreCheckpointCategories { get { - return ResourceManager.GetString("Label_PortableMode", resourceCulture); + return ResourceManager.GetString("TeachingTip_MoreCheckpointCategories", resourceCulture); } } - /// - /// Looks up a localized string similar to In Portable Mode, all data and settings will be stored in the same directory as the application. You will be able to move the application with its 'Data' folder to a different location or computer.. - /// - public static string Label_PortableModeExplanation { + public static string Action_OpenOnHuggingFace { get { - return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); + return ResourceManager.GetString("Action_OpenOnHuggingFace", resourceCulture); } } - /// - /// Looks up a localized string similar to Preprocessor. - /// - public static string Label_Preprocessor { + public static string Action_UpdateExistingMetadata { get { - return ResourceManager.GetString("Label_Preprocessor", resourceCulture); + return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); } } - /// - /// Looks up a localized string similar to Previous Image. - /// - public static string Label_PreviousImage { + public static string Label_General { get { - return ResourceManager.GetString("Label_PreviousImage", resourceCulture); + return ResourceManager.GetString("Label_General", resourceCulture); } } - /// - /// Looks up a localized string similar to Previous Page. - /// - public static string Label_PreviousPage { + public static string Label_Inference { get { - return ResourceManager.GetString("Label_PreviousPage", resourceCulture); + return ResourceManager.GetString("Label_Inference", resourceCulture); } } - /// - /// Looks up a localized string similar to Prompt. - /// public static string Label_Prompt { get { return ResourceManager.GetString("Label_Prompt", resourceCulture); } } - /// - /// Looks up a localized string similar to Prompt Tags. - /// - public static string Label_PromptTags { - get { - return ResourceManager.GetString("Label_PromptTags", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tags file to use for suggesting completions (Supports the a1111-sd-webui-tagcomplete .csv format). - /// - public static string Label_PromptTagsDescription { + public static string Label_OutputImageFiles { get { - return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); + return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); } } - /// - /// Looks up a localized string similar to Import Prompt tags. - /// - public static string Label_PromptTagsImport { + public static string Label_ImageViewer { get { - return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); + return ResourceManager.GetString("Label_ImageViewer", resourceCulture); } } - /// - /// Looks up a localized string similar to Python Packages. - /// - public static string Label_PythonPackages { + public static string Label_AutoCompletion { get { - return ResourceManager.GetString("Label_PythonPackages", resourceCulture); + return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); } } - /// - /// Looks up a localized string similar to Python Version Info. - /// - public static string Label_PythonVersionInfo { + public static string Label_CompletionReplaceUnderscoresWithSpaces { get { - return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); + return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); } } - /// - /// Looks up a localized string similar to PyTorch Version. - /// - public static string Label_PyTorchVersion { + public static string Label_PromptTags { get { - return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); + return ResourceManager.GetString("Label_PromptTags", resourceCulture); } } - /// - /// Looks up a localized string similar to I have read and agree to the. - /// - public static string Label_ReadAndAgree { + public static string Label_PromptTagsImport { get { - return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); } } - /// - /// Looks up a localized string similar to Recommended Models. - /// - public static string Label_RecommendedModels { + public static string Label_PromptTagsDescription { get { - return ResourceManager.GetString("Label_RecommendedModels", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to While your package is installing, here are some models we recommend to help you get started.. - /// - public static string Label_RecommendedModelsSubText { + public static string Label_SystemInformation { get { - return ResourceManager.GetString("Label_RecommendedModelsSubText", resourceCulture); + return ResourceManager.GetString("Label_SystemInformation", resourceCulture); } } - /// - /// Looks up a localized string similar to Refiner. - /// - public static string Label_Refiner { + public static string Label_CivitAi { get { - return ResourceManager.GetString("Label_Refiner", resourceCulture); + return ResourceManager.GetString("Label_CivitAi", resourceCulture); } } - /// - /// Looks up a localized string similar to Relaunch Required. - /// - public static string Label_RelaunchRequired { + public static string Label_HuggingFace { get { - return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); + return ResourceManager.GetString("Label_HuggingFace", resourceCulture); } } - /// - /// Looks up a localized string similar to Release Notes. - /// - public static string Label_ReleaseNotes { + public static string Label_Addons { get { - return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); + return ResourceManager.GetString("Label_Addons", resourceCulture); } } - /// - /// Looks up a localized string similar to Releases. - /// - public static string Label_Releases { + public static string Label_SaveIntermediateImage { get { - return ResourceManager.GetString("Label_Releases", resourceCulture); + return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove shared checkpoints directory symbolic links on shutdown. - /// - public static string Label_RemoveSymlinksOnShutdown { + public static string Label_Settings { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); + return ResourceManager.GetString("Label_Settings", resourceCulture); } } - /// - /// Looks up a localized string similar to Select this option if you're having problems moving Stability Matrix to another drive. - /// - public static string Label_RemoveSymlinksOnShutdown_Details { + public static string Action_SelectFile { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); + return ResourceManager.GetString("Action_SelectFile", resourceCulture); } } - /// - /// Looks up a localized string similar to Reset Checkpoints Cache. - /// - public static string Label_ResetCheckpointsCache { + public static string Action_ReplaceContents { get { - return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); + return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); } } - /// - /// Looks up a localized string similar to Rebuilds the installed checkpoints cache. Use if checkpoints are incorrectly labeled in the Model Browser. - /// - public static string Label_ResetCheckpointsCache_Details { + public static string Label_WipFeature { get { - return ResourceManager.GetString("Label_ResetCheckpointsCache_Details", resourceCulture); + return ResourceManager.GetString("Label_WipFeature", resourceCulture); } } - /// - /// Looks up a localized string similar to Save Intermediate Image. - /// - public static string Label_SaveIntermediateImage { + public static string Label_WipFeatureDescription { get { - return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); + return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to Search.... - /// - public static string Label_SearchEllipsis { + public static string Label_MissingImageFile { get { - return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); + return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); } } - /// - /// Looks up a localized string similar to Select Download Location:. - /// - public static string Label_SelectDownloadLocation { + public static string Label_HolidayMode { get { - return ResourceManager.GetString("Label_SelectDownloadLocation", resourceCulture); + return ResourceManager.GetString("Label_HolidayMode", resourceCulture); } } - /// - /// Looks up a localized string similar to Select new Data Directory. - /// - public static string Label_SelectNewDataDirectory { + public static string Label_CLIPSkip { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_CLIPSkip", resourceCulture); } } - /// - /// Looks up a localized string similar to Does not move existing data. - /// - public static string Label_SelectNewDataDirectory_Details { + public static string Label_ImageToVideo { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); + return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); } } - /// - /// Looks up a localized string similar to Settings. - /// - public static string Label_Settings { + public static string Label_Fps { get { - return ResourceManager.GetString("Label_Settings", resourceCulture); + return ResourceManager.GetString("Label_Fps", resourceCulture); } } - /// - /// Looks up a localized string similar to Shared Model Folder Strategy. - /// - public static string Label_SharedModelFolderStrategy { + public static string Label_MinCfg { get { - return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); + return ResourceManager.GetString("Label_MinCfg", resourceCulture); } } - /// - /// Looks up a localized string similar to Model Sharing. - /// - public static string Label_SharedModelStrategyShort { + public static string Label_Lossless { get { - return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); + return ResourceManager.GetString("Label_Lossless", resourceCulture); } } - /// - /// Looks up a localized string similar to Show Model Images. - /// - public static string Label_ShowModelImages { + public static string Label_Frames { get { - return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); + return ResourceManager.GetString("Label_Frames", resourceCulture); } } - /// - /// Looks up a localized string similar to Show NSFW Content. - /// - public static string Label_ShowNsfwContent { + public static string Label_MotionBucketId { get { - return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); + return ResourceManager.GetString("Label_MotionBucketId", resourceCulture); } } - /// - /// Looks up a localized string similar to Show pixel grid at high zoom levels. - /// - public static string Label_ShowPixelGridAtHighZoomLevels { + public static string Label_AugmentationLevel { get { - return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); + return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); } } - /// - /// Looks up a localized string similar to Skip first-time setup. - /// - public static string Label_SkipSetup { + public static string Label_VideoOutputMethod { get { - return ResourceManager.GetString("Label_SkipSetup", resourceCulture); + return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); } } - /// - /// Looks up a localized string similar to Sort. - /// - public static string Label_Sort { + public static string Label_VideoQuality { get { - return ResourceManager.GetString("Label_Sort", resourceCulture); + return ResourceManager.GetString("Label_VideoQuality", resourceCulture); } } - /// - /// Looks up a localized string similar to Stability Matrix. - /// - public static string Label_StabilityMatrix { + public static string Label_FindInModelBrowser { get { - return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); } } - /// - /// Looks up a localized string similar to Stability Matrix is already running. - /// - public static string Label_StabilityMatrixAlreadyRunning { + public static string Label_Installed { get { - return ResourceManager.GetString("Label_StabilityMatrixAlreadyRunning", resourceCulture); + return ResourceManager.GetString("Label_Installed", resourceCulture); } } - /// - /// Looks up a localized string similar to Steps. - /// - public static string Label_Steps { + public static string Label_NoExtensionsFound { get { - return ResourceManager.GetString("Label_Steps", resourceCulture); + return ResourceManager.GetString("Label_NoExtensionsFound", resourceCulture); } } - /// - /// Looks up a localized string similar to Steps - Base. - /// - public static string Label_StepsBase { + public static string Action_Hide { get { - return ResourceManager.GetString("Label_StepsBase", resourceCulture); + return ResourceManager.GetString("Action_Hide", resourceCulture); } } - /// - /// Looks up a localized string similar to Steps - Refiner. - /// - public static string Label_StepsRefiner { + public static string Action_CopyDetails { get { - return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); + return ResourceManager.GetString("Action_CopyDetails", resourceCulture); } } - /// - /// Looks up a localized string similar to Strength. - /// - public static string Label_Strength { + public static string Label_Notifications { get { - return ResourceManager.GetString("Label_Strength", resourceCulture); + return ResourceManager.GetString("Label_Notifications", resourceCulture); } } - /// - /// Looks up a localized string similar to System. - /// - public static string Label_System { + public static string Label_NotificationOption_None { get { - return ResourceManager.GetString("Label_System", resourceCulture); + return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture); } } - /// - /// Looks up a localized string similar to System Information. - /// - public static string Label_SystemInformation { + public static string Action_Download { get { - return ResourceManager.GetString("Label_SystemInformation", resourceCulture); + return ResourceManager.GetString("Action_Download", resourceCulture); } } - /// - /// Looks up a localized string similar to Text to Image. - /// - public static string Label_TextToImage { + public static string TeachingTip_DownloadsExplanation { get { - return ResourceManager.GetString("Label_TextToImage", resourceCulture); + return ResourceManager.GetString("TeachingTip_DownloadsExplanation", resourceCulture); } } - /// - /// Looks up a localized string similar to Theme. - /// - public static string Label_Theme { + public static string Label_RecommendedModels { get { - return ResourceManager.GetString("Label_Theme", resourceCulture); + return ResourceManager.GetString("Label_RecommendedModels", resourceCulture); } } - /// - /// Looks up a localized string similar to Period. - /// - public static string Label_TimePeriod { + public static string Label_RecommendedModelsSubText { get { - return ResourceManager.GetString("Label_TimePeriod", resourceCulture); + return ResourceManager.GetString("Label_RecommendedModelsSubText", resourceCulture); } } - /// - /// Looks up a localized string similar to Auto-Scroll to End. - /// - public static string Label_ToggleAutoScrolling { + public static string Label_ComfyRequiredTitle { get { - return ResourceManager.GetString("Label_ToggleAutoScrolling", resourceCulture); + return ResourceManager.GetString("Label_ComfyRequiredTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Trigger words:. - /// - public static string Label_TriggerWords { + public static string Label_ComfyRequiredDetail { get { - return ResourceManager.GetString("Label_TriggerWords", resourceCulture); + return ResourceManager.GetString("Label_ComfyRequiredDetail", resourceCulture); } } - /// - /// Looks up a localized string similar to An unexpected error occurred. - /// - public static string Label_UnexpectedErrorOccurred { + public static string Error_PleaseSelectDownloadLocation { get { - return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); + return ResourceManager.GetString("Error_PleaseSelectDownloadLocation", resourceCulture); } } - /// - /// Looks up a localized string similar to Unknown Package. - /// - public static string Label_UnknownPackage { + public static string Label_SelectDownloadLocation { get { - return ResourceManager.GetString("Label_UnknownPackage", resourceCulture); + return ResourceManager.GetString("Label_SelectDownloadLocation", resourceCulture); } } - /// - /// Looks up a localized string similar to Update Available. - /// - public static string Label_UpdateAvailable { + public static string Label_Workflows { get { - return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); + return ResourceManager.GetString("Label_Workflows", resourceCulture); } } - /// - /// Looks up a localized string similar to Updates. - /// - public static string Label_Updates { + public static string Label_InfiniteScrolling { get { - return ResourceManager.GetString("Label_Updates", resourceCulture); + return ResourceManager.GetString("Label_InfiniteScrolling", resourceCulture); } } - /// - /// Looks up a localized string similar to For technical users. Be the first to access our Development builds from feature branches as soon as they are available. There may be some rough edges and bugs as we experiment with new features.. - /// - public static string Label_UpdatesDevChannelDescription { + public static string Label_WorkflowBrowser { get { - return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_WorkflowBrowser", resourceCulture); } } - /// - /// Looks up a localized string similar to For early adopters. Preview builds will be more reliable than those from the Dev channel, and will be available closer to stable releases. Your feedback will help us greatly in discovering issues and polishing design elements.. - /// - public static string Label_UpdatesPreviewChannelDescription { + public static string Label_Config { get { - return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_Config", resourceCulture); } } - /// - /// Looks up a localized string similar to Upscale. - /// - public static string Label_Upscale { + public static string Action_OpenOnOpenArt { get { - return ResourceManager.GetString("Label_Upscale", resourceCulture); + return ResourceManager.GetString("Action_OpenOnOpenArt", resourceCulture); } } - /// - /// Looks up a localized string similar to Username. - /// - public static string Label_Username { + public static string Label_NodeDetails { get { - return ResourceManager.GetString("Label_Username", resourceCulture); + return ResourceManager.GetString("Label_NodeDetails", resourceCulture); } } - /// - /// Looks up a localized string similar to Output Sharing. - /// - public static string Label_UseSharedOutputFolder { + public static string Label_WorkflowDescription { get { - return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDescription", resourceCulture); } } - /// - /// Looks up a localized string similar to VAE. - /// - public static string Label_VAE { + public static string Label_OpenArtBrowser { get { - return ResourceManager.GetString("Label_VAE", resourceCulture); + return ResourceManager.GetString("Label_OpenArtBrowser", resourceCulture); } } - /// - /// Looks up a localized string similar to Version. - /// - public static string Label_Version { + public static string Action_PreviewPreprocessor { get { - return ResourceManager.GetString("Label_Version", resourceCulture); + return ResourceManager.GetString("Action_PreviewPreprocessor", resourceCulture); } } - /// - /// Looks up a localized string similar to Version Type. - /// - public static string Label_VersionType { + public static string Label_ToggleAutoScrolling { get { - return ResourceManager.GetString("Label_VersionType", resourceCulture); + return ResourceManager.GetString("Label_ToggleAutoScrolling", resourceCulture); } } - /// - /// Looks up a localized string similar to Method. - /// - public static string Label_VideoOutputMethod { + public static string Label_ConfirmExit { get { - return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); + return ResourceManager.GetString("Label_ConfirmExit", resourceCulture); } } - /// - /// Looks up a localized string similar to Quality. - /// - public static string Label_VideoQuality { + public static string Label_ConfirmExitDetail { get { - return ResourceManager.GetString("Label_VideoQuality", resourceCulture); + return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture); } } - /// - /// Looks up a localized string similar to Waiting to connect.... - /// - public static string Label_WaitingToConnectEllipsis { + public static string Label_Console { get { - return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); + return ResourceManager.GetString("Label_Console", resourceCulture); } } - /// - /// Looks up a localized string similar to Web UI. - /// public static string Label_WebUi { get { return ResourceManager.GetString("Label_WebUi", resourceCulture); } } - /// - /// Looks up a localized string similar to Width. - /// - public static string Label_Width { + public static string Label_Packages { get { - return ResourceManager.GetString("Label_Width", resourceCulture); + return ResourceManager.GetString("Label_Packages", resourceCulture); } } - /// - /// Looks up a localized string similar to Not yet available. - /// - public static string Label_WipFeature { + public static string Label_ActionCannotBeUndone { get { - return ResourceManager.GetString("Label_WipFeature", resourceCulture); + return ResourceManager.GetString("Label_ActionCannotBeUndone", resourceCulture); } } - /// - /// Looks up a localized string similar to Feature will be available in a future update. - /// - public static string Label_WipFeatureDescription { + public static string Label_AreYouSureDeleteImages { get { - return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); + return ResourceManager.GetString("Label_AreYouSureDeleteImages", resourceCulture); } } - /// - /// Looks up a localized string similar to Workflow Browser. - /// - public static string Label_WorkflowBrowser { + public static string Label_CheckingHardware { get { - return ResourceManager.GetString("Label_WorkflowBrowser", resourceCulture); + return ResourceManager.GetString("Label_CheckingHardware", resourceCulture); } } - /// - /// Looks up a localized string similar to Workflow Deleted. - /// - public static string Label_WorkflowDeleted { + public static string Label_EverythingLooksGood { get { - return ResourceManager.GetString("Label_WorkflowDeleted", resourceCulture); + return ResourceManager.GetString("Label_EverythingLooksGood", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} deleted successfully. - /// - public static string Label_WorkflowDeletedSuccessfully { + public static string Label_NvidiaGpuRecommended { get { - return ResourceManager.GetString("Label_WorkflowDeletedSuccessfully", resourceCulture); + return ResourceManager.GetString("Label_NvidiaGpuRecommended", resourceCulture); } } - /// - /// Looks up a localized string similar to Workflow Description. - /// - public static string Label_WorkflowDescription { + public static string Label_Checkpoints { get { - return ResourceManager.GetString("Label_WorkflowDescription", resourceCulture); + return ResourceManager.GetString("Label_Checkpoints", resourceCulture); } } - /// - /// Looks up a localized string similar to The workflow and custom nodes have been imported.. - /// - public static string Label_WorkflowImportComplete { + public static string Label_ModelBrowser { get { - return ResourceManager.GetString("Label_WorkflowImportComplete", resourceCulture); + return ResourceManager.GetString("Label_ModelBrowser", resourceCulture); } } - /// - /// Looks up a localized string similar to Workflow Imported. - /// - public static string Label_WorkflowImported { + public static string TeachingTip_WebUiButtonMoved { get { - return ResourceManager.GetString("Label_WorkflowImported", resourceCulture); + return ResourceManager.GetString("TeachingTip_WebUiButtonMoved", resourceCulture); } } - /// - /// Looks up a localized string similar to Workflows. - /// - public static string Label_Workflows { + public static string Label_AnotherInstanceAlreadyRunning { get { - return ResourceManager.GetString("Label_Workflows", resourceCulture); + return ResourceManager.GetString("Label_AnotherInstanceAlreadyRunning", resourceCulture); } } - /// - /// Looks up a localized string similar to You're up to date. - /// - public static string Label_YouAreUpToDate { + public static string Label_StabilityMatrixAlreadyRunning { get { - return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); + return ResourceManager.GetString("Label_StabilityMatrixAlreadyRunning", resourceCulture); } } - /// - /// Looks up a localized string similar to Download complete. - /// - public static string Progress_DownloadComplete { + public static string Label_WorkflowDeletedSuccessfully { get { - return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDeletedSuccessfully", resourceCulture); } } - /// - /// Looks up a localized string similar to Downloading package.... - /// - public static string Progress_DownloadingPackage { + public static string Label_WorkflowDeleted { get { - return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDeleted", resourceCulture); } } - /// - /// Looks up a localized string similar to Installation complete. - /// - public static string Progress_InstallationComplete { + public static string Label_ErrorRetrievingWorkflows { get { - return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); + return ResourceManager.GetString("Label_ErrorRetrievingWorkflows", resourceCulture); } } - /// - /// Looks up a localized string similar to Installing package requirements.... - /// - public static string Progress_InstallingPackageRequirements { + public static string TabLabel_InstalledWorkflows { get { - return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); + return ResourceManager.GetString("TabLabel_InstalledWorkflows", resourceCulture); } } - /// - /// Looks up a localized string similar to Installing prerequisites.... - /// - public static string Progress_InstallingPrerequisites { + public static string Label_WorkflowImported { get { - return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); + return ResourceManager.GetString("Label_WorkflowImported", resourceCulture); } } - /// - /// Looks up a localized string similar to Uninstalling package.... - /// - public static string Progress_UninstallingPackage { + public static string Label_FinishedImportingWorkflow { get { - return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); + return ResourceManager.GetString("Label_FinishedImportingWorkflow", resourceCulture); } } - /// - /// Looks up a localized string similar to Update complete. - /// - public static string Progress_UpdateComplete { + public static string Label_WorkflowImportComplete { get { - return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); + return ResourceManager.GetString("Label_WorkflowImportComplete", resourceCulture); } } - /// - /// Looks up a localized string similar to Update failed. - /// - public static string Progress_UpdateFailed { + public static string TeachingTip_InferencePromptHelpButton { get { - return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); + return ResourceManager.GetString("TeachingTip_InferencePromptHelpButton", resourceCulture); } } - /// - /// Looks up a localized string similar to Installed Workflows. - /// - public static string TabLabel_InstalledWorkflows { + public static string Label_ExtraNetworks { get { - return ResourceManager.GetString("TabLabel_InstalledWorkflows", resourceCulture); + return ResourceManager.GetString("Label_ExtraNetworks", resourceCulture); } } - /// - /// Looks up a localized string similar to Add a package to get started!. - /// - public static string TeachingTip_AddPackageToGetStarted { + public static string Label_CLIPStrength { get { - return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_CLIPStrength", resourceCulture); } } - /// - /// Looks up a localized string similar to Click Launch to get started!. - /// - public static string TeachingTip_ClickLaunchToGetStarted { + public static string Label_NumberFormat { get { - return ResourceManager.GetString("TeachingTip_ClickLaunchToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_NumberFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to Check the progress of your package installations and model downloads here.. - /// - public static string TeachingTip_DownloadsExplanation { + public static string Text_DeleteFollowingItems { get { - return ResourceManager.GetString("TeachingTip_DownloadsExplanation", resourceCulture); + return ResourceManager.GetString("Text_DeleteFollowingItems", resourceCulture); } } - /// - /// Looks up a localized string similar to Click here to review prompt syntax and how to include Lora / Embeddings.. - /// - public static string TeachingTip_InferencePromptHelpButton { + public static string TextTemplate_DeleteFollowingCountItems { get { - return ResourceManager.GetString("TeachingTip_InferencePromptHelpButton", resourceCulture); + return ResourceManager.GetString("TextTemplate_DeleteFollowingCountItems", resourceCulture); } } - /// - /// Looks up a localized string similar to Additional folders such as IPAdapters and TextualInversions (embeddings) can be enabled here. - /// - public static string TeachingTip_MoreCheckpointCategories { + public static string Label_DeletePermanently { get { - return ResourceManager.GetString("TeachingTip_MoreCheckpointCategories", resourceCulture); + return ResourceManager.GetString("Label_DeletePermanently", resourceCulture); } } - /// - /// Looks up a localized string similar to The 'Open Web UI' button has moved to the command bar. - /// - public static string TeachingTip_WebUiButtonMoved { + public static string Action_MoveToTrash { get { - return ResourceManager.GetString("TeachingTip_WebUiButtonMoved", resourceCulture); + return ResourceManager.GetString("Action_MoveToTrash", resourceCulture); } } - /// - /// Looks up a localized string similar to The app will relaunch after updating. - /// - public static string Text_AppWillRelaunchAfterUpdate { + public static string Label_AreYouSureDeleteModels { get { - return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); + return ResourceManager.GetString("Label_AreYouSureDeleteModels", resourceCulture); } } - /// - /// Looks up a localized string similar to You are about to delete the following items:. - /// - public static string Text_DeleteFollowingItems { + public static string Label_AutoSearchOnLoad { get { - return ResourceManager.GetString("Text_DeleteFollowingItems", resourceCulture); + return ResourceManager.GetString("Label_AutoSearchOnLoad", resourceCulture); } } - /// - /// Looks up a localized string similar to Choose your preferred interface to get started. - /// - public static string Text_OneClickInstaller_SubHeader { + public static string Label_AutoSearchOnLoad_Description { get { - return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); + return ResourceManager.GetString("Label_AutoSearchOnLoad_Description", resourceCulture); } } - /// - /// Looks up a localized string similar to This will delete the package folder and all its contents, including any generated images and files you may have added.. - /// - public static string Text_PackageUninstall_Details { + public static string Action_ToggleVisibility { get { - return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); + return ResourceManager.GetString("Action_ToggleVisibility", resourceCulture); } } - /// - /// Looks up a localized string similar to Proceeding to Launch page. - /// - public static string Text_ProceedingToLaunchPage { + public static string Label_ClippingMask { get { - return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); + return ResourceManager.GetString("Label_ClippingMask", resourceCulture); } } - /// - /// Looks up a localized string similar to Relaunch is required for new language option to take effect. - /// - public static string Text_RelaunchRequiredToApplyLanguage { + public static string Label_AppFolders { get { - return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); + return ResourceManager.GetString("Label_AppFolders", resourceCulture); } } - /// - /// Looks up a localized string similar to Some files could not be deleted. Please close any open files in the package directory and try again.. - /// - public static string Text_SomeFilesCouldNotBeDeleted { + public static string Label_Logs { get { - return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); + return ResourceManager.GetString("Label_Logs", resourceCulture); } } - /// - /// Looks up a localized string similar to Welcome to Stability Matrix!. - /// - public static string Text_WelcomeToStabilityMatrix { + public static string Label_AppData { get { - return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_AppData", resourceCulture); } } - /// - /// Looks up a localized string similar to You are about to delete the following {0} items:. - /// - public static string TextTemplate_DeleteFollowingCountItems { + public static string TextTemplate_PackageUpdatedToSelected { get { - return ResourceManager.GetString("TextTemplate_DeleteFollowingCountItems", resourceCulture); + return ResourceManager.GetString("TextTemplate_PackageUpdatedToSelected", resourceCulture); } } - /// - /// Looks up a localized string similar to Error updating {0}. - /// - public static string TextTemplate_ErrorUpdatingPackage { + public static string Action_CopyAsBitmap { get { - return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); + return ResourceManager.GetString("Action_CopyAsBitmap", resourceCulture); } } - /// - /// Looks up a localized string similar to Last checked: {0}. - /// - public static string TextTemplate_LastChecked { + public static string Label_DisableUpdateCheck { get { - return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); + return ResourceManager.GetString("Label_DisableUpdateCheck", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} has been updated to the latest version. - /// - public static string TextTemplate_PackageUpdatedToLatest { + public static string Warning_PleaseExtractFirst { get { - return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); + return ResourceManager.GetString("Warning_PleaseExtractFirst", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} has been updated to the selected version. - /// - public static string TextTemplate_PackageUpdatedToSelected { + public static string Label_HistorySize { get { - return ResourceManager.GetString("TextTemplate_PackageUpdatedToSelected", resourceCulture); + return ResourceManager.GetString("Label_HistorySize", resourceCulture); } } - /// - /// Looks up a localized string similar to Updating {0}. - /// - public static string TextTemplate_UpdatingPackage { + public static string Label_HistorySize_Description { get { - return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); + return ResourceManager.GetString("Label_HistorySize_Description", resourceCulture); } } - /// - /// Looks up a localized string similar to PLEASE EXTRACT THE APP FROM THE ZIP FILE BEFORE RUNNING STABILITY MATRIX. - /// - public static string Warning_PleaseExtractFirst { + public static string Label_ConnectAccountFailed { get { - return ResourceManager.GetString("Warning_PleaseExtractFirst", resourceCulture); + return ResourceManager.GetString("Label_ConnectAccountFailed", resourceCulture); } } } diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index af0451a28..a4dfe19e9 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -1134,4 +1134,7 @@ The number of lines above the ones displayed in the console you can scroll back to + + We had some trouble connecting your account + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthConnectViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthConnectViewModel.cs index a2c9d4eb3..db781c373 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthConnectViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthConnectViewModel.cs @@ -1,11 +1,14 @@ using System; using System.Threading.Tasks; +using System.Web; +using AsyncAwaitBestPractices; using CommunityToolkit.Mvvm.ComponentModel; using MessagePipe; using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Helpers; using StabilityMatrix.Avalonia.Languages; +using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Attributes; @@ -53,11 +56,50 @@ public override async Task OnLoadedAsync() UriHandler.IpcKeySend, receivedUri => { - logger.LogDebug("UriHandler Received URI: {Uri}", receivedUri.PathAndQuery); - if (receivedUri.PathAndQuery.StartsWith("/oauth/patreon/callback")) + logger.LogDebug("UriHandler Received URI: {Uri}", receivedUri.ToString()); + + // Ignore if path not matching + if ( + !receivedUri.PathAndQuery.StartsWith( + "/oauth/patreon/callback", + StringComparison.OrdinalIgnoreCase + ) + ) { + return; + } + + var queryCollection = HttpUtility.ParseQueryString(receivedUri.Query); + var status = queryCollection.Get("status"); + var error = queryCollection.Get("error"); + + if (status == "success") + { + logger.LogInformation("OAuth connection successful"); OnPrimaryButtonClick(); } + else if (status == "failure") + { + logger.LogError("OAuth connection failed ({Status}): {Error}", status, error); + + var dialog = DialogHelper.CreateMarkdownDialog( + $"- {error}", + Resources.Label_ConnectAccountFailed + ); + + dialog.ShowAsync().ContinueWith(_ => OnCloseButtonClick()).SafeFireAndForget(); + } + else + { + logger.LogError("OAuth connection unknown status ({Status}): {Error}", status, error); + + var dialog = DialogHelper.CreateMarkdownDialog( + $"- {error}", + Resources.Label_ConnectAccountFailed + ); + + dialog.ShowAsync().ContinueWith(_ => OnCloseButtonClick()).SafeFireAndForget(); + } } ); } From c7d29274078c92cf80d9666f566f9f7d377df9d8 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 10 Aug 2024 02:39:23 -0400 Subject: [PATCH 169/325] Regenerate Resources.Designer.cs --- .../Languages/Resources.Designer.cs | 2410 ++++++++++++----- 1 file changed, 1722 insertions(+), 688 deletions(-) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 1168cbda4..d7af51cd4 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -11,32 +11,46 @@ namespace StabilityMatrix.Avalonia.Languages { using System; - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { - private static System.Resources.ResourceManager resourceMan; + private static global::System.Resources.ResourceManager resourceMan; - private static System.Globalization.CultureInfo resourceCulture; + private static global::System.Globalization.CultureInfo resourceCulture; - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Resources.ResourceManager ResourceManager { + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("StabilityMatrix.Avalonia.Languages.Resources", typeof(Resources).Assembly); + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StabilityMatrix.Avalonia.Languages.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Globalization.CultureInfo Culture { + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -45,2043 +59,3063 @@ public static System.Globalization.CultureInfo Culture { } } - public static string Action_Launch { + /// + /// Looks up a localized string similar to Add for All Users. + /// + public static string Action_AddForAllUsers { get { - return ResourceManager.GetString("Action_Launch", resourceCulture); + return ResourceManager.GetString("Action_AddForAllUsers", resourceCulture); } } - public static string Action_Quit { + /// + /// Looks up a localized string similar to Add for Current User. + /// + public static string Action_AddForCurrentUser { get { - return ResourceManager.GetString("Action_Quit", resourceCulture); + return ResourceManager.GetString("Action_AddForCurrentUser", resourceCulture); } } - public static string Action_Save { + /// + /// Looks up a localized string similar to Add Package. + /// + public static string Action_AddPackage { get { - return ResourceManager.GetString("Action_Save", resourceCulture); + return ResourceManager.GetString("Action_AddPackage", resourceCulture); } } + /// + /// Looks up a localized string similar to Cancel. + /// public static string Action_Cancel { get { return ResourceManager.GetString("Action_Cancel", resourceCulture); } } - public static string Label_Language { + /// + /// Looks up a localized string similar to Check for Updates. + /// + public static string Action_CheckForUpdates { get { - return ResourceManager.GetString("Label_Language", resourceCulture); + return ResourceManager.GetString("Action_CheckForUpdates", resourceCulture); } } - public static string Text_RelaunchRequiredToApplyLanguage { + /// + /// Looks up a localized string similar to Check Version. + /// + public static string Action_CheckVersion { get { - return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); + return ResourceManager.GetString("Action_CheckVersion", resourceCulture); } } - public static string Action_Relaunch { + /// + /// Looks up a localized string similar to Clear Selection. + /// + public static string Action_ClearSelection { get { - return ResourceManager.GetString("Action_Relaunch", resourceCulture); + return ResourceManager.GetString("Action_ClearSelection", resourceCulture); } } - public static string Action_RelaunchLater { + /// + /// Looks up a localized string similar to Close. + /// + public static string Action_Close { get { - return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); + return ResourceManager.GetString("Action_Close", resourceCulture); } } - public static string Label_RelaunchRequired { + /// + /// Looks up a localized string similar to Connect. + /// + public static string Action_Connect { get { - return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); + return ResourceManager.GetString("Action_Connect", resourceCulture); } } - public static string Label_UnknownPackage { + /// + /// Looks up a localized string similar to Consolidate. + /// + public static string Action_Consolidate { get { - return ResourceManager.GetString("Label_UnknownPackage", resourceCulture); + return ResourceManager.GetString("Action_Consolidate", resourceCulture); } } - public static string Action_Import { + /// + /// Looks up a localized string similar to Continue. + /// + public static string Action_Continue { get { - return ResourceManager.GetString("Action_Import", resourceCulture); + return ResourceManager.GetString("Action_Continue", resourceCulture); } } - public static string Label_PackageType { + /// + /// Looks up a localized string similar to Copy. + /// + public static string Action_Copy { get { - return ResourceManager.GetString("Label_PackageType", resourceCulture); + return ResourceManager.GetString("Action_Copy", resourceCulture); } } - public static string Label_Version { + /// + /// Looks up a localized string similar to Copy as Bitmap. + /// + public static string Action_CopyAsBitmap { get { - return ResourceManager.GetString("Label_Version", resourceCulture); + return ResourceManager.GetString("Action_CopyAsBitmap", resourceCulture); } } - public static string Label_VersionType { + /// + /// Looks up a localized string similar to Copy Details. + /// + public static string Action_CopyDetails { get { - return ResourceManager.GetString("Label_VersionType", resourceCulture); + return ResourceManager.GetString("Action_CopyDetails", resourceCulture); } } - public static string Label_Releases { + /// + /// Looks up a localized string similar to Copy Trigger Words. + /// + public static string Action_CopyTriggerWords { get { - return ResourceManager.GetString("Label_Releases", resourceCulture); + return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); } } - public static string Label_Branches { + /// + /// Looks up a localized string similar to Delete. + /// + public static string Action_Delete { get { - return ResourceManager.GetString("Label_Branches", resourceCulture); + return ResourceManager.GetString("Action_Delete", resourceCulture); } } - public static string Label_DragAndDropCheckpointsHereToImport { + /// + /// Looks up a localized string similar to Disconnect. + /// + public static string Action_Disconnect { get { - return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); + return ResourceManager.GetString("Action_Disconnect", resourceCulture); } } - public static string Label_Emphasis { + /// + /// Looks up a localized string similar to Downgrade. + /// + public static string Action_Downgrade { get { - return ResourceManager.GetString("Label_Emphasis", resourceCulture); + return ResourceManager.GetString("Action_Downgrade", resourceCulture); } } - public static string Label_Deemphasis { + /// + /// Looks up a localized string similar to Download. + /// + public static string Action_Download { get { - return ResourceManager.GetString("Label_Deemphasis", resourceCulture); + return ResourceManager.GetString("Action_Download", resourceCulture); } } - public static string Label_EmbeddingsOrTextualInversion { + /// + /// Looks up a localized string similar to Edit. + /// + public static string Action_Edit { get { - return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); + return ResourceManager.GetString("Action_Edit", resourceCulture); } } - public static string Label_NetworksLoraOrLycoris { + /// + /// Looks up a localized string similar to Exit Application. + /// + public static string Action_ExitApplication { get { - return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); + return ResourceManager.GetString("Action_ExitApplication", resourceCulture); } } - public static string Label_Comments { + /// + /// Looks up a localized string similar to Hide. + /// + public static string Action_Hide { get { - return ResourceManager.GetString("Label_Comments", resourceCulture); + return ResourceManager.GetString("Action_Hide", resourceCulture); } } - public static string Label_ShowPixelGridAtHighZoomLevels { + /// + /// Looks up a localized string similar to Import. + /// + public static string Action_Import { get { - return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); + return ResourceManager.GetString("Action_Import", resourceCulture); } } - public static string Label_Steps { + /// + /// Looks up a localized string similar to Install. + /// + public static string Action_Install { get { - return ResourceManager.GetString("Label_Steps", resourceCulture); + return ResourceManager.GetString("Action_Install", resourceCulture); } } - public static string Label_StepsBase { + /// + /// Looks up a localized string similar to Install Now. + /// + public static string Action_InstallNow { get { - return ResourceManager.GetString("Label_StepsBase", resourceCulture); + return ResourceManager.GetString("Action_InstallNow", resourceCulture); } } - public static string Label_StepsRefiner { + /// + /// Looks up a localized string similar to Launch. + /// + public static string Action_Launch { get { - return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); + return ResourceManager.GetString("Action_Launch", resourceCulture); } } - public static string Label_CFGScale { + /// + /// Looks up a localized string similar to Login. + /// + public static string Action_Login { get { - return ResourceManager.GetString("Label_CFGScale", resourceCulture); + return ResourceManager.GetString("Action_Login", resourceCulture); } } - public static string Label_DenoisingStrength { + /// + /// Looks up a localized string similar to Move to Trash. + /// + public static string Action_MoveToTrash { get { - return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); + return ResourceManager.GetString("Action_MoveToTrash", resourceCulture); } } - public static string Label_Width { + /// + /// Looks up a localized string similar to New. + /// + public static string Action_New { get { - return ResourceManager.GetString("Label_Width", resourceCulture); + return ResourceManager.GetString("Action_New", resourceCulture); } } - public static string Label_Height { + /// + /// Looks up a localized string similar to OK. + /// + public static string Action_OK { get { - return ResourceManager.GetString("Label_Height", resourceCulture); + return ResourceManager.GetString("Action_OK", resourceCulture); } } - public static string Label_Refiner { + /// + /// Looks up a localized string similar to Open on GitHub. + /// + public static string Action_OpenGithub { get { - return ResourceManager.GetString("Label_Refiner", resourceCulture); + return ResourceManager.GetString("Action_OpenGithub", resourceCulture); } } - public static string Label_VAE { + /// + /// Looks up a localized string similar to Open in Browser. + /// + public static string Action_OpenInBrowser { get { - return ResourceManager.GetString("Label_VAE", resourceCulture); + return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); } } - public static string Label_Model { + /// + /// Looks up a localized string similar to Open in Explorer. + /// + public static string Action_OpenInExplorer { get { - return ResourceManager.GetString("Label_Model", resourceCulture); + return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); } } - public static string Action_Connect { + /// + /// Looks up a localized string similar to Open in Finder. + /// + public static string Action_OpenInFinder { get { - return ResourceManager.GetString("Action_Connect", resourceCulture); + return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); } } - public static string Label_ConnectingEllipsis { + /// + /// Looks up a localized string similar to Open in Image Viewer. + /// + public static string Action_OpenInViewer { get { - return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); + return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); } } - public static string Action_Close { + /// + /// Looks up a localized string similar to Open on CivitAI. + /// + public static string Action_OpenOnCivitAi { get { - return ResourceManager.GetString("Action_Close", resourceCulture); + return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); } } - public static string Label_WaitingToConnectEllipsis { + /// + /// Looks up a localized string similar to Open on Hugging Face. + /// + public static string Action_OpenOnHuggingFace { get { - return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); + return ResourceManager.GetString("Action_OpenOnHuggingFace", resourceCulture); } } - public static string Label_UpdateAvailable { + /// + /// Looks up a localized string similar to Open on OpenArt. + /// + public static string Action_OpenOnOpenArt { get { - return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); + return ResourceManager.GetString("Action_OpenOnOpenArt", resourceCulture); } } - public static string Label_BecomeAPatron { + /// + /// Looks up a localized string similar to Open Project.... + /// + public static string Action_OpenProjectEllipsis { get { - return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); + return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); } } - public static string Label_JoinDiscord { + /// + /// Looks up a localized string similar to Open Web UI. + /// + public static string Action_OpenWebUI { get { - return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); + return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); } } - public static string Label_Downloads { + /// + /// Looks up a localized string similar to Preview Preprocessor. + /// + public static string Action_PreviewPreprocessor { get { - return ResourceManager.GetString("Label_Downloads", resourceCulture); + return ResourceManager.GetString("Action_PreviewPreprocessor", resourceCulture); } } - public static string Action_Install { + /// + /// Looks up a localized string similar to Quit. + /// + public static string Action_Quit { get { - return ResourceManager.GetString("Action_Install", resourceCulture); + return ResourceManager.GetString("Action_Quit", resourceCulture); } } - public static string Label_SkipSetup { + /// + /// Looks up a localized string similar to Refresh. + /// + public static string Action_Refresh { get { - return ResourceManager.GetString("Label_SkipSetup", resourceCulture); + return ResourceManager.GetString("Action_Refresh", resourceCulture); } } - public static string Label_UnexpectedErrorOccurred { + /// + /// Looks up a localized string similar to Relaunch. + /// + public static string Action_Relaunch { get { - return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); + return ResourceManager.GetString("Action_Relaunch", resourceCulture); } } - public static string Action_ExitApplication { + /// + /// Looks up a localized string similar to Relaunch Later. + /// + public static string Action_RelaunchLater { get { - return ResourceManager.GetString("Action_ExitApplication", resourceCulture); + return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); } } - public static string Label_DisplayName { + /// + /// Looks up a localized string similar to Remind Me Later. + /// + public static string Action_RemindMeLater { get { - return ResourceManager.GetString("Label_DisplayName", resourceCulture); + return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); } } - public static string Label_InstallationWithThisNameExists { + /// + /// Looks up a localized string similar to Remove. + /// + public static string Action_Remove { get { - return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); + return ResourceManager.GetString("Action_Remove", resourceCulture); } } - public static string Label_PleaseChooseDifferentName { + /// + /// Looks up a localized string similar to Rename. + /// + public static string Action_Rename { get { - return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); + return ResourceManager.GetString("Action_Rename", resourceCulture); } } - public static string Label_AdvancedOptions { + /// + /// Looks up a localized string similar to Replace Contents. + /// + public static string Action_ReplaceContents { get { - return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); + return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); } } - public static string Label_Commit { + /// + /// Looks up a localized string similar to Restart. + /// + public static string Action_Restart { get { - return ResourceManager.GetString("Label_Commit", resourceCulture); + return ResourceManager.GetString("Action_Restart", resourceCulture); } } - public static string Label_SharedModelFolderStrategy { + /// + /// Looks up a localized string similar to Restore Default Layout. + /// + public static string Action_RestoreDefaultLayout { get { - return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); + return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); } } - public static string Label_PyTorchVersion { + /// + /// Looks up a localized string similar to Retry. + /// + public static string Action_Retry { get { - return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); + return ResourceManager.GetString("Action_Retry", resourceCulture); } } - public static string Label_CloseDialogWhenFinished { + /// + /// Looks up a localized string similar to Save. + /// + public static string Action_Save { get { - return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); + return ResourceManager.GetString("Action_Save", resourceCulture); } } - public static string Label_DataDirectory { + /// + /// Looks up a localized string similar to Save As.... + /// + public static string Action_SaveAsEllipsis { get { - return ResourceManager.GetString("Label_DataDirectory", resourceCulture); + return ResourceManager.GetString("Action_SaveAsEllipsis", resourceCulture); } } - public static string Label_DataDirectoryExplanation { + /// + /// Looks up a localized string similar to Search. + /// + public static string Action_Search { get { - return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); + return ResourceManager.GetString("Action_Search", resourceCulture); } } - public static string Label_FatWarning { + /// + /// Looks up a localized string similar to Select All. + /// + public static string Action_SelectAll { get { - return ResourceManager.GetString("Label_FatWarning", resourceCulture); + return ResourceManager.GetString("Action_SelectAll", resourceCulture); } } - public static string Label_PortableMode { + /// + /// Looks up a localized string similar to Select Directory. + /// + public static string Action_SelectDirectory { get { - return ResourceManager.GetString("Label_PortableMode", resourceCulture); + return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); } } - public static string Label_PortableModeExplanation { + /// + /// Looks up a localized string similar to Select File. + /// + public static string Action_SelectFile { get { - return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); + return ResourceManager.GetString("Action_SelectFile", resourceCulture); } } - public static string Action_Continue { + /// + /// Looks up a localized string similar to Send. + /// + public static string Action_Send { get { - return ResourceManager.GetString("Action_Continue", resourceCulture); + return ResourceManager.GetString("Action_Send", resourceCulture); } } - public static string Label_PreviousImage { + /// + /// Looks up a localized string similar to Send Input. + /// + public static string Action_SendInput { get { - return ResourceManager.GetString("Label_PreviousImage", resourceCulture); + return ResourceManager.GetString("Action_SendInput", resourceCulture); } } - public static string Label_NextImage { + /// + /// Looks up a localized string similar to Send to Inference. + /// + public static string Action_SendToInference { get { - return ResourceManager.GetString("Label_NextImage", resourceCulture); + return ResourceManager.GetString("Action_SendToInference", resourceCulture); } } - public static string Label_ModelDescription { + /// + /// Looks up a localized string similar to Show in Explorer. + /// + public static string Action_ShowInExplorer { get { - return ResourceManager.GetString("Label_ModelDescription", resourceCulture); + return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); } } - public static string Label_NewVersionAvailable { + /// + /// Looks up a localized string similar to Signup. + /// + public static string Action_Signup { get { - return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); + return ResourceManager.GetString("Action_Signup", resourceCulture); } } - public static string Label_ImportLatest { + /// + /// Looks up a localized string similar to Stop. + /// + public static string Action_Stop { get { - return ResourceManager.GetString("Label_ImportLatest", resourceCulture); + return ResourceManager.GetString("Action_Stop", resourceCulture); } } - public static string Label_AllVersions { + /// + /// Looks up a localized string similar to Toggle Visibility. + /// + public static string Action_ToggleVisibility { get { - return ResourceManager.GetString("Label_AllVersions", resourceCulture); + return ResourceManager.GetString("Action_ToggleVisibility", resourceCulture); } } - public static string Label_ModelSearchWatermark { + /// + /// Looks up a localized string similar to Uninstall. + /// + public static string Action_Uninstall { get { - return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); + return ResourceManager.GetString("Action_Uninstall", resourceCulture); } } - public static string Action_Search { + /// + /// Looks up a localized string similar to Update. + /// + public static string Action_Update { get { - return ResourceManager.GetString("Action_Search", resourceCulture); + return ResourceManager.GetString("Action_Update", resourceCulture); } } - public static string Label_Sort { + /// + /// Looks up a localized string similar to Update Existing Metadata. + /// + public static string Action_UpdateExistingMetadata { get { - return ResourceManager.GetString("Label_Sort", resourceCulture); + return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); } } - public static string Label_TimePeriod { + /// + /// Looks up a localized string similar to Upgrade. + /// + public static string Action_Upgrade { get { - return ResourceManager.GetString("Label_TimePeriod", resourceCulture); + return ResourceManager.GetString("Action_Upgrade", resourceCulture); } } - public static string Label_ModelType { + /// + /// Looks up a localized string similar to Yes. + /// + public static string Action_Yes { get { - return ResourceManager.GetString("Label_ModelType", resourceCulture); + return ResourceManager.GetString("Action_Yes", resourceCulture); } } - public static string Label_BaseModel { + /// + /// Looks up a localized string similar to Please select a download location.. + /// + public static string Error_PleaseSelectDownloadLocation { get { - return ResourceManager.GetString("Label_BaseModel", resourceCulture); + return ResourceManager.GetString("Error_PleaseSelectDownloadLocation", resourceCulture); } } - public static string Label_ShowNsfwContent { + /// + /// Looks up a localized string similar to About. + /// + public static string Label_About { get { - return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); + return ResourceManager.GetString("Label_About", resourceCulture); } } - public static string Label_DataProvidedByCivitAi { + /// + /// Looks up a localized string similar to Accounts. + /// + public static string Label_Accounts { get { - return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); + return ResourceManager.GetString("Label_Accounts", resourceCulture); } } - public static string Label_Page { + /// + /// Looks up a localized string similar to This action cannot be undone.. + /// + public static string Label_ActionCannotBeUndone { get { - return ResourceManager.GetString("Label_Page", resourceCulture); + return ResourceManager.GetString("Label_ActionCannotBeUndone", resourceCulture); } } - public static string Label_FirstPage { + /// + /// Looks up a localized string similar to Addons. + /// + public static string Label_Addons { get { - return ResourceManager.GetString("Label_FirstPage", resourceCulture); + return ResourceManager.GetString("Label_Addons", resourceCulture); } } - public static string Label_PreviousPage { + /// + /// Looks up a localized string similar to Add Stability Matrix to the Start Menu. + /// + public static string Label_AddToStartMenu { get { - return ResourceManager.GetString("Label_PreviousPage", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); } } - public static string Label_NextPage { + /// + /// Looks up a localized string similar to Uses the current app location, you can run this again if you move the app. + /// + public static string Label_AddToStartMenu_Details { get { - return ResourceManager.GetString("Label_NextPage", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); } } - public static string Label_LastPage { + /// + /// Looks up a localized string similar to Advanced Options. + /// + public static string Label_AdvancedOptions { get { - return ResourceManager.GetString("Label_LastPage", resourceCulture); + return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); } } - public static string Action_Rename { + /// + /// Looks up a localized string similar to All Versions. + /// + public static string Label_AllVersions { get { - return ResourceManager.GetString("Action_Rename", resourceCulture); + return ResourceManager.GetString("Label_AllVersions", resourceCulture); } } - public static string Action_Delete { + /// + /// Looks up a localized string similar to Another instance of Stability Matrix is already running. Please close it before starting a new one.. + /// + public static string Label_AnotherInstanceAlreadyRunning { get { - return ResourceManager.GetString("Action_Delete", resourceCulture); + return ResourceManager.GetString("Label_AnotherInstanceAlreadyRunning", resourceCulture); } } - public static string Action_OpenOnCivitAi { + /// + /// Looks up a localized string similar to API Key. + /// + public static string Label_ApiKey { get { - return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); + return ResourceManager.GetString("Label_ApiKey", resourceCulture); } } - public static string Label_ConnectedModel { + /// + /// Looks up a localized string similar to App Data. + /// + public static string Label_AppData { get { - return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); + return ResourceManager.GetString("Label_AppData", resourceCulture); } } - public static string Label_LocalModel { + /// + /// Looks up a localized string similar to Appearance. + /// + public static string Label_Appearance { get { - return ResourceManager.GetString("Label_LocalModel", resourceCulture); + return ResourceManager.GetString("Label_Appearance", resourceCulture); } } - public static string Action_ShowInExplorer { + /// + /// Looks up a localized string similar to App Folders. + /// + public static string Label_AppFolders { get { - return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); + return ResourceManager.GetString("Label_AppFolders", resourceCulture); } } - public static string Action_New { + /// + /// Looks up a localized string similar to Are you sure?. + /// + public static string Label_AreYouSure { get { - return ResourceManager.GetString("Action_New", resourceCulture); + return ResourceManager.GetString("Label_AreYouSure", resourceCulture); } } - public static string Label_Folder { + /// + /// Looks up a localized string similar to Are you sure you want to delete {0} images?. + /// + public static string Label_AreYouSureDeleteImages { get { - return ResourceManager.GetString("Label_Folder", resourceCulture); + return ResourceManager.GetString("Label_AreYouSureDeleteImages", resourceCulture); } } - public static string Label_DropFileToImport { + /// + /// Looks up a localized string similar to Are you sure you want to delete {0} models?. + /// + public static string Label_AreYouSureDeleteModels { get { - return ResourceManager.GetString("Label_DropFileToImport", resourceCulture); + return ResourceManager.GetString("Label_AreYouSureDeleteModels", resourceCulture); } } - public static string Label_ImportAsConnected { + /// + /// Looks up a localized string similar to Augmentation Level. + /// + public static string Label_AugmentationLevel { get { - return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); + return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); } } - public static string Label_ImportAsConnectedExplanation { + /// + /// Looks up a localized string similar to Auto Completion. + /// + public static string Label_AutoCompletion { get { - return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); + return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); } } - public static string Label_Indexing { + /// + /// Looks up a localized string similar to Automatically scroll to end of console output. + /// + public static string Label_AutoScrollToEnd { get { - return ResourceManager.GetString("Label_Indexing", resourceCulture); + return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); } } - public static string Label_ModelsFolder { + /// + /// Looks up a localized string similar to Auto-Search on Load. + /// + public static string Label_AutoSearchOnLoad { get { - return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); + return ResourceManager.GetString("Label_AutoSearchOnLoad", resourceCulture); } } - public static string Label_Categories { + /// + /// Looks up a localized string similar to Automatically initiate a search when the model browser page is loaded. + /// + public static string Label_AutoSearchOnLoad_Description { get { - return ResourceManager.GetString("Label_Categories", resourceCulture); + return ResourceManager.GetString("Label_AutoSearchOnLoad_Description", resourceCulture); } } - public static string Label_LetsGetStarted { + /// + /// Looks up a localized string similar to Auto Updates. + /// + public static string Label_AutoUpdates { get { - return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); + return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); } } - public static string Label_ReadAndAgree { + /// + /// Looks up a localized string similar to Base Model. + /// + public static string Label_BaseModel { get { - return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); + return ResourceManager.GetString("Label_BaseModel", resourceCulture); } } - public static string Label_LicenseAgreement { + /// + /// Looks up a localized string similar to Batch Index. + /// + public static string Label_BatchIndex { get { - return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); + return ResourceManager.GetString("Label_BatchIndex", resourceCulture); } } - public static string Label_FindConnectedMetadata { + /// + /// Looks up a localized string similar to Become a Patron. + /// + public static string Label_BecomeAPatron { get { - return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); + return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); } } - public static string Label_ShowModelImages { + /// + /// Looks up a localized string similar to Branch. + /// + public static string Label_Branch { get { - return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); + return ResourceManager.GetString("Label_Branch", resourceCulture); } } - public static string Label_Appearance { + /// + /// Looks up a localized string similar to Branches. + /// + public static string Label_Branches { get { - return ResourceManager.GetString("Label_Appearance", resourceCulture); + return ResourceManager.GetString("Label_Branches", resourceCulture); } } - public static string Label_Theme { + /// + /// Looks up a localized string similar to Callstack. + /// + public static string Label_Callstack { get { - return ResourceManager.GetString("Label_Theme", resourceCulture); + return ResourceManager.GetString("Label_Callstack", resourceCulture); } } - public static string Label_CheckpointManager { + /// + /// Looks up a localized string similar to Categories. + /// + public static string Label_Categories { get { - return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); + return ResourceManager.GetString("Label_Categories", resourceCulture); } } - public static string Label_RemoveSymlinksOnShutdown { + /// + /// Looks up a localized string similar to CFG Scale. + /// + public static string Label_CFGScale { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); + return ResourceManager.GetString("Label_CFGScale", resourceCulture); } } - public static string Label_RemoveSymlinksOnShutdown_Details { + /// + /// Looks up a localized string similar to We're checking some hardware specifications to determine compatibility.. + /// + public static string Label_CheckingHardware { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); + return ResourceManager.GetString("Label_CheckingHardware", resourceCulture); } } - public static string Label_ResetCheckpointsCache { + /// + /// Looks up a localized string similar to Checkpoint Manager. + /// + public static string Label_CheckpointManager { get { - return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); + return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); } } - public static string Label_ResetCheckpointsCache_Details { + /// + /// Looks up a localized string similar to Checkpoints. + /// + public static string Label_Checkpoints { get { - return ResourceManager.GetString("Label_ResetCheckpointsCache_Details", resourceCulture); + return ResourceManager.GetString("Label_Checkpoints", resourceCulture); } } - public static string Label_PackageEnvironment { + /// + /// Looks up a localized string similar to CivitAI. + /// + public static string Label_CivitAi { get { - return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); + return ResourceManager.GetString("Label_CivitAi", resourceCulture); } } - public static string Action_Edit { + /// + /// Looks up a localized string similar to You must be logged in to download this checkpoint. Please enter a CivitAI API Key in the settings.. + /// + public static string Label_CivitAiLoginRequired { get { - return ResourceManager.GetString("Action_Edit", resourceCulture); + return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); } } - public static string Label_EnvironmentVariables { + /// + /// Looks up a localized string similar to Clipping Mask. + /// + public static string Label_ClippingMask { get { - return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); + return ResourceManager.GetString("Label_ClippingMask", resourceCulture); } } - public static string Label_EmbeddedPython { + /// + /// Looks up a localized string similar to CLIP Skip. + /// + public static string Label_CLIPSkip { get { - return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); + return ResourceManager.GetString("Label_CLIPSkip", resourceCulture); } } - public static string Action_CheckVersion { + /// + /// Looks up a localized string similar to CLIP Strength. + /// + public static string Label_CLIPStrength { get { - return ResourceManager.GetString("Action_CheckVersion", resourceCulture); + return ResourceManager.GetString("Label_CLIPStrength", resourceCulture); } } - public static string Label_Integrations { + /// + /// Looks up a localized string similar to Close dialog when finished. + /// + public static string Label_CloseDialogWhenFinished { get { - return ResourceManager.GetString("Label_Integrations", resourceCulture); + return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); } } - public static string Label_DiscordRichPresence { + /// + /// Looks up a localized string similar to ComfyUI is required to install this package. Would you like to install it now?. + /// + public static string Label_ComfyRequiredDetail { get { - return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); + return ResourceManager.GetString("Label_ComfyRequiredDetail", resourceCulture); } } - public static string Label_System { + /// + /// Looks up a localized string similar to ComfyUI Required. + /// + public static string Label_ComfyRequiredTitle { get { - return ResourceManager.GetString("Label_System", resourceCulture); + return ResourceManager.GetString("Label_ComfyRequiredTitle", resourceCulture); } } - public static string Label_AddToStartMenu { + /// + /// Looks up a localized string similar to Comments. + /// + public static string Label_Comments { get { - return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); + return ResourceManager.GetString("Label_Comments", resourceCulture); } } - public static string Label_AddToStartMenu_Details { + /// + /// Looks up a localized string similar to Commit. + /// + public static string Label_Commit { get { - return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); + return ResourceManager.GetString("Label_Commit", resourceCulture); } } - public static string Label_OnlyAvailableOnWindows { + /// + /// Looks up a localized string similar to Replace underscores with spaces when inserting completions. + /// + public static string Label_CompletionReplaceUnderscoresWithSpaces { get { - return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); + return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); } } - public static string Action_AddForCurrentUser { + /// + /// Looks up a localized string similar to Config. + /// + public static string Label_Config { get { - return ResourceManager.GetString("Action_AddForCurrentUser", resourceCulture); + return ResourceManager.GetString("Label_Config", resourceCulture); } } - public static string Action_AddForAllUsers { + /// + /// Looks up a localized string similar to Confirm Delete. + /// + public static string Label_ConfirmDelete { get { - return ResourceManager.GetString("Action_AddForAllUsers", resourceCulture); + return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); } } - public static string Label_SelectNewDataDirectory { + /// + /// Looks up a localized string similar to Confirm Exit. + /// + public static string Label_ConfirmExit { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_ConfirmExit", resourceCulture); } } - public static string Label_SelectNewDataDirectory_Details { + /// + /// Looks up a localized string similar to Are you sure you want to exit? This will also close any currently running packages.. + /// + public static string Label_ConfirmExitDetail { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); + return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture); } } - public static string Action_SelectDirectory { + /// + /// Looks up a localized string similar to Confirm Password. + /// + public static string Label_ConfirmPassword { get { - return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); + return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); } } - public static string Label_About { + /// + /// Looks up a localized string similar to Confirm?. + /// + public static string Label_ConfirmQuestion { get { - return ResourceManager.GetString("Label_About", resourceCulture); + return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); } } - public static string Label_StabilityMatrix { + /// + /// Looks up a localized string similar to We had some trouble connecting your account. + /// + public static string Label_ConnectAccountFailed { get { - return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_ConnectAccountFailed", resourceCulture); } } - public static string Label_LicenseAndOpenSourceNotices { + /// + /// Looks up a localized string similar to Connected. + /// + public static string Label_Connected { get { - return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); + return ResourceManager.GetString("Label_Connected", resourceCulture); } } - public static string TeachingTip_ClickLaunchToGetStarted { + /// + /// Looks up a localized string similar to Connected Model. + /// + public static string Label_ConnectedModel { get { - return ResourceManager.GetString("TeachingTip_ClickLaunchToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); } } - public static string Action_Stop { + /// + /// Looks up a localized string similar to Connecting.... + /// + public static string Label_ConnectingEllipsis { get { - return ResourceManager.GetString("Action_Stop", resourceCulture); + return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); } } - public static string Action_SendInput { + /// + /// Looks up a localized string similar to Console. + /// + public static string Label_Console { get { - return ResourceManager.GetString("Action_SendInput", resourceCulture); + return ResourceManager.GetString("Label_Console", resourceCulture); } } - public static string Label_Input { + /// + /// Looks up a localized string similar to This will move all generated images from the selected packages to the Consolidated directory of the shared outputs folder. This action cannot be undone.. + /// + public static string Label_ConsolidateExplanation { get { - return ResourceManager.GetString("Label_Input", resourceCulture); + return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); } } - public static string Action_Send { + /// + /// Looks up a localized string similar to Control Steps. + /// + public static string Label_ControlSteps { get { - return ResourceManager.GetString("Action_Send", resourceCulture); + return ResourceManager.GetString("Label_ControlSteps", resourceCulture); } } - public static string Label_InputRequired { + /// + /// Looks up a localized string similar to Control Weight. + /// + public static string Label_ControlWeight { get { - return ResourceManager.GetString("Label_InputRequired", resourceCulture); + return ResourceManager.GetString("Label_ControlWeight", resourceCulture); } } - public static string Label_ConfirmQuestion { + /// + /// Looks up a localized string similar to Current directory:. + /// + public static string Label_CurrentDirectory { get { - return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); + return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); } } - public static string Action_Yes { + /// + /// Looks up a localized string similar to Data Directory. + /// + public static string Label_DataDirectory { get { - return ResourceManager.GetString("Action_Yes", resourceCulture); + return ResourceManager.GetString("Label_DataDirectory", resourceCulture); } } - public static string Label_No { + /// + /// Looks up a localized string similar to This is where application data (model checkpoints, web UIs, etc.) will be installed.. + /// + public static string Label_DataDirectoryExplanation { get { - return ResourceManager.GetString("Label_No", resourceCulture); + return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); } } - public static string Action_OpenWebUI { + /// + /// Looks up a localized string similar to Data Folder Name. + /// + public static string Label_DataFolderName { get { - return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); + return ResourceManager.GetString("Label_DataFolderName", resourceCulture); } } - public static string Text_WelcomeToStabilityMatrix { + /// + /// Looks up a localized string similar to Data provided by CivitAI. + /// + public static string Label_DataProvidedByCivitAi { get { - return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); } } - public static string Text_OneClickInstaller_SubHeader { + /// + /// Looks up a localized string similar to Deemphasis. + /// + public static string Label_Deemphasis { get { - return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); + return ResourceManager.GetString("Label_Deemphasis", resourceCulture); } } - public static string Label_Installing { + /// + /// Looks up a localized string similar to Delete Permanently. + /// + public static string Label_DeletePermanently { get { - return ResourceManager.GetString("Label_Installing", resourceCulture); + return ResourceManager.GetString("Label_DeletePermanently", resourceCulture); } } - public static string Text_ProceedingToLaunchPage { + /// + /// Looks up a localized string similar to Denoising Strength. + /// + public static string Label_DenoisingStrength { get { - return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); + return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); } } - public static string Progress_DownloadingPackage { + /// + /// Looks up a localized string similar to Details. + /// + public static string Label_Details { get { - return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); + return ResourceManager.GetString("Label_Details", resourceCulture); } } - public static string Progress_DownloadComplete { + /// + /// Looks up a localized string similar to Disable Update Check. + /// + public static string Label_DisableUpdateCheck { get { - return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); + return ResourceManager.GetString("Label_DisableUpdateCheck", resourceCulture); } } - public static string Progress_InstallationComplete { + /// + /// Looks up a localized string similar to Discord Rich Presence. + /// + public static string Label_DiscordRichPresence { get { - return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); + return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); } } - public static string Progress_InstallingPrerequisites { + /// + /// Looks up a localized string similar to Display Name. + /// + public static string Label_DisplayName { get { - return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); + return ResourceManager.GetString("Label_DisplayName", resourceCulture); } } - public static string Progress_InstallingPackageRequirements { + /// + /// Looks up a localized string similar to Download Failed. + /// + public static string Label_DownloadFailed { get { - return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); + return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); } } - public static string Action_OpenInExplorer { + /// + /// Looks up a localized string similar to Downloads. + /// + public static string Label_Downloads { get { - return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); + return ResourceManager.GetString("Label_Downloads", resourceCulture); } } - public static string Action_OpenInFinder { + /// + /// Looks up a localized string similar to Drag & Drop checkpoints here to import. + /// + public static string Label_DragAndDropCheckpointsHereToImport { get { - return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); + return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); } } - public static string Action_Uninstall { + /// + /// Looks up a localized string similar to Drop file here to import. + /// + public static string Label_DropFileToImport { get { - return ResourceManager.GetString("Action_Uninstall", resourceCulture); + return ResourceManager.GetString("Label_DropFileToImport", resourceCulture); } } - public static string Action_CheckForUpdates { + /// + /// Looks up a localized string similar to Email. + /// + public static string Label_Email { + get { + return ResourceManager.GetString("Label_Email", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Embedded Python. + /// + public static string Label_EmbeddedPython { get { - return ResourceManager.GetString("Action_CheckForUpdates", resourceCulture); + return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); } } - public static string Action_Update { + /// + /// Looks up a localized string similar to Embeddings / Textual Inversion. + /// + public static string Label_EmbeddingsOrTextualInversion { get { - return ResourceManager.GetString("Action_Update", resourceCulture); + return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); } } - public static string Action_AddPackage { + /// + /// Looks up a localized string similar to Emphasis. + /// + public static string Label_Emphasis { get { - return ResourceManager.GetString("Action_AddPackage", resourceCulture); + return ResourceManager.GetString("Label_Emphasis", resourceCulture); } } - public static string TeachingTip_AddPackageToGetStarted { + /// + /// Looks up a localized string similar to Environment Variables. + /// + public static string Label_EnvironmentVariables { get { - return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); } } + /// + /// Looks up a localized string similar to Name. + /// public static string Label_EnvVarsTable_Name { get { return ResourceManager.GetString("Label_EnvVarsTable_Name", resourceCulture); } } + /// + /// Looks up a localized string similar to Value. + /// public static string Label_EnvVarsTable_Value { get { return ResourceManager.GetString("Label_EnvVarsTable_Value", resourceCulture); } } - public static string Action_Remove { - get { - return ResourceManager.GetString("Action_Remove", resourceCulture); - } - } - - public static string Label_Details { + /// + /// Looks up a localized string similar to Error installing package. + /// + public static string Label_ErrorInstallingPackage { get { - return ResourceManager.GetString("Label_Details", resourceCulture); + return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); } } - public static string Label_Callstack { + /// + /// Looks up a localized string similar to Error retrieving workflows. + /// + public static string Label_ErrorRetrievingWorkflows { get { - return ResourceManager.GetString("Label_Callstack", resourceCulture); + return ResourceManager.GetString("Label_ErrorRetrievingWorkflows", resourceCulture); } } - public static string Label_InnerException { + /// + /// Looks up a localized string similar to Everything looks good!. + /// + public static string Label_EverythingLooksGood { get { - return ResourceManager.GetString("Label_InnerException", resourceCulture); + return ResourceManager.GetString("Label_EverythingLooksGood", resourceCulture); } } - public static string Label_SearchEllipsis { + /// + /// Looks up a localized string similar to Extra Networks (Lora / LyCORIS). + /// + public static string Label_ExtraNetworks { get { - return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); + return ResourceManager.GetString("Label_ExtraNetworks", resourceCulture); } } - public static string Action_OK { + /// + /// Looks up a localized string similar to You may encounter errors when using a FAT32 or exFAT drive. Select a different drive for a smoother experience.. + /// + public static string Label_FatWarning { get { - return ResourceManager.GetString("Action_OK", resourceCulture); + return ResourceManager.GetString("Label_FatWarning", resourceCulture); } } - public static string Action_Retry { + /// + /// Looks up a localized string similar to Find Connected Metadata. + /// + public static string Label_FindConnectedMetadata { get { - return ResourceManager.GetString("Action_Retry", resourceCulture); + return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); } } - public static string Label_PythonVersionInfo { + /// + /// Looks up a localized string similar to Find in Model Browser. + /// + public static string Label_FindInModelBrowser { get { - return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); + return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); } } - public static string Action_Restart { + /// + /// Looks up a localized string similar to Finished importing workflow and custom nodes. + /// + public static string Label_FinishedImportingWorkflow { get { - return ResourceManager.GetString("Action_Restart", resourceCulture); + return ResourceManager.GetString("Label_FinishedImportingWorkflow", resourceCulture); } } - public static string Label_ConfirmDelete { + /// + /// Looks up a localized string similar to First Page. + /// + public static string Label_FirstPage { get { - return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); + return ResourceManager.GetString("Label_FirstPage", resourceCulture); } } - public static string Text_PackageUninstall_Details { + /// + /// Looks up a localized string similar to Folder. + /// + public static string Label_Folder { get { - return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); + return ResourceManager.GetString("Label_Folder", resourceCulture); } } - public static string Progress_UninstallingPackage { + /// + /// Looks up a localized string similar to Frames Per Second. + /// + public static string Label_Fps { get { - return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); + return ResourceManager.GetString("Label_Fps", resourceCulture); } } - public static string Label_PackageUninstalled { + /// + /// Looks up a localized string similar to Frames. + /// + public static string Label_Frames { get { - return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); + return ResourceManager.GetString("Label_Frames", resourceCulture); } } - public static string Text_SomeFilesCouldNotBeDeleted { + /// + /// Looks up a localized string similar to General. + /// + public static string Label_General { get { - return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); + return ResourceManager.GetString("Label_General", resourceCulture); } } - public static string Label_InvalidPackageType { + /// + /// Looks up a localized string similar to Height. + /// + public static string Label_Height { get { - return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); + return ResourceManager.GetString("Label_Height", resourceCulture); } } - public static string TextTemplate_UpdatingPackage { + /// + /// Looks up a localized string similar to History Size. + /// + public static string Label_HistorySize { get { - return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); + return ResourceManager.GetString("Label_HistorySize", resourceCulture); } } - public static string Progress_UpdateComplete { + /// + /// Looks up a localized string similar to The number of lines above the ones displayed in the console you can scroll back to. + /// + public static string Label_HistorySize_Description { get { - return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); + return ResourceManager.GetString("Label_HistorySize_Description", resourceCulture); } } - public static string TextTemplate_PackageUpdatedToLatest { + /// + /// Looks up a localized string similar to Holiday Mode. + /// + public static string Label_HolidayMode { get { - return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); + return ResourceManager.GetString("Label_HolidayMode", resourceCulture); } } - public static string TextTemplate_ErrorUpdatingPackage { + /// + /// Looks up a localized string similar to Hugging Face. + /// + public static string Label_HuggingFace { get { - return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); + return ResourceManager.GetString("Label_HuggingFace", resourceCulture); } } - public static string Progress_UpdateFailed { + /// + /// Looks up a localized string similar to Image to Image. + /// + public static string Label_ImageToImage { get { - return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); + return ResourceManager.GetString("Label_ImageToImage", resourceCulture); } } - public static string Action_OpenInBrowser { + /// + /// Looks up a localized string similar to Image to Video. + /// + public static string Label_ImageToVideo { get { - return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); + return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); } } - public static string Label_ErrorInstallingPackage { + /// + /// Looks up a localized string similar to Image Viewer. + /// + public static string Label_ImageViewer { get { - return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); + return ResourceManager.GetString("Label_ImageViewer", resourceCulture); } } - public static string Label_Branch { + /// + /// Looks up a localized string similar to Import with Metadata. + /// + public static string Label_ImportAsConnected { get { - return ResourceManager.GetString("Label_Branch", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); } } - public static string Label_AutoScrollToEnd { + /// + /// Looks up a localized string similar to Search for connected metadata on new local imports. + /// + public static string Label_ImportAsConnectedExplanation { get { - return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); } } - public static string Label_License { + /// + /// Looks up a localized string similar to Import Latest -. + /// + public static string Label_ImportLatest { get { - return ResourceManager.GetString("Label_License", resourceCulture); + return ResourceManager.GetString("Label_ImportLatest", resourceCulture); } } - public static string Label_SharedModelStrategyShort { + /// + /// Looks up a localized string similar to Indexing.... + /// + public static string Label_Indexing { get { - return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); + return ResourceManager.GetString("Label_Indexing", resourceCulture); } } - public static string Label_PleaseSelectDataDirectory { + /// + /// Looks up a localized string similar to Inference. + /// + public static string Label_Inference { get { - return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_Inference", resourceCulture); } } - public static string Label_DataFolderName { + /// + /// Looks up a localized string similar to Infinite Scrolling. + /// + public static string Label_InfiniteScrolling { get { - return ResourceManager.GetString("Label_DataFolderName", resourceCulture); + return ResourceManager.GetString("Label_InfiniteScrolling", resourceCulture); } } - public static string Label_CurrentDirectory { + /// + /// Looks up a localized string similar to Inner exception. + /// + public static string Label_InnerException { get { - return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); + return ResourceManager.GetString("Label_InnerException", resourceCulture); } } - public static string Text_AppWillRelaunchAfterUpdate { + /// + /// Looks up a localized string similar to Inpainting. + /// + public static string Label_Inpainting { get { - return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); + return ResourceManager.GetString("Label_Inpainting", resourceCulture); } } - public static string Action_RemindMeLater { + /// + /// Looks up a localized string similar to Input. + /// + public static string Label_Input { get { - return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); + return ResourceManager.GetString("Label_Input", resourceCulture); } } - public static string Action_InstallNow { + /// + /// Looks up a localized string similar to Input required. + /// + public static string Label_InputRequired { get { - return ResourceManager.GetString("Action_InstallNow", resourceCulture); + return ResourceManager.GetString("Label_InputRequired", resourceCulture); } } - public static string Label_ReleaseNotes { + /// + /// Looks up a localized string similar to An installation with this name already exists.. + /// + public static string Label_InstallationWithThisNameExists { get { - return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); + return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); } } - public static string Action_OpenProjectEllipsis { + /// + /// Looks up a localized string similar to Installed. + /// + public static string Label_Installed { get { - return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); + return ResourceManager.GetString("Label_Installed", resourceCulture); } } - public static string Action_SaveAsEllipsis { + /// + /// Looks up a localized string similar to Installing. + /// + public static string Label_Installing { get { - return ResourceManager.GetString("Action_SaveAsEllipsis", resourceCulture); + return ResourceManager.GetString("Label_Installing", resourceCulture); } } - public static string Action_RestoreDefaultLayout { + /// + /// Looks up a localized string similar to Integrations. + /// + public static string Label_Integrations { get { - return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); + return ResourceManager.GetString("Label_Integrations", resourceCulture); } } - public static string Label_UseSharedOutputFolder { + /// + /// Looks up a localized string similar to Invalid Package type. + /// + public static string Label_InvalidPackageType { get { - return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); + return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); } } - public static string Label_BatchIndex { + /// + /// Looks up a localized string similar to Join Discord Server. + /// + public static string Label_JoinDiscord { get { - return ResourceManager.GetString("Label_BatchIndex", resourceCulture); + return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); } } - public static string Action_Copy { + /// + /// Looks up a localized string similar to Language. + /// + public static string Label_Language { get { - return ResourceManager.GetString("Action_Copy", resourceCulture); + return ResourceManager.GetString("Label_Language", resourceCulture); } } - public static string Action_OpenInViewer { + /// + /// Looks up a localized string similar to Last Page. + /// + public static string Label_LastPage { get { - return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); + return ResourceManager.GetString("Label_LastPage", resourceCulture); } } - public static string Label_NumImagesSelected { + /// + /// Looks up a localized string similar to Let's get started. + /// + public static string Label_LetsGetStarted { get { - return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); + return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); } } - public static string Label_OutputFolder { + /// + /// Looks up a localized string similar to License. + /// + public static string Label_License { get { - return ResourceManager.GetString("Label_OutputFolder", resourceCulture); + return ResourceManager.GetString("Label_License", resourceCulture); } } - public static string Label_OutputType { + /// + /// Looks up a localized string similar to License Agreement.. + /// + public static string Label_LicenseAgreement { get { - return ResourceManager.GetString("Label_OutputType", resourceCulture); + return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); } } - public static string Action_ClearSelection { + /// + /// Looks up a localized string similar to License and Open Source Notices. + /// + public static string Label_LicenseAndOpenSourceNotices { get { - return ResourceManager.GetString("Action_ClearSelection", resourceCulture); + return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); } } - public static string Action_SelectAll { + /// + /// Looks up a localized string similar to Local Model. + /// + public static string Label_LocalModel { get { - return ResourceManager.GetString("Action_SelectAll", resourceCulture); + return ResourceManager.GetString("Label_LocalModel", resourceCulture); } } - public static string Action_SendToInference { + /// + /// Looks up a localized string similar to Logs. + /// + public static string Label_Logs { get { - return ResourceManager.GetString("Action_SendToInference", resourceCulture); + return ResourceManager.GetString("Label_Logs", resourceCulture); } } - public static string Label_TextToImage { + /// + /// Looks up a localized string similar to Lossless. + /// + public static string Label_Lossless { get { - return ResourceManager.GetString("Label_TextToImage", resourceCulture); + return ResourceManager.GetString("Label_Lossless", resourceCulture); } } - public static string Label_ImageToImage { + /// + /// Looks up a localized string similar to Min CFG. + /// + public static string Label_MinCfg { get { - return ResourceManager.GetString("Label_ImageToImage", resourceCulture); + return ResourceManager.GetString("Label_MinCfg", resourceCulture); } } - public static string Label_Inpainting { + /// + /// Looks up a localized string similar to Missing Image File. + /// + public static string Label_MissingImageFile { get { - return ResourceManager.GetString("Label_Inpainting", resourceCulture); + return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); } } - public static string Label_Upscale { + /// + /// Looks up a localized string similar to Model. + /// + public static string Label_Model { get { - return ResourceManager.GetString("Label_Upscale", resourceCulture); + return ResourceManager.GetString("Label_Model", resourceCulture); } } - public static string Label_OutputsPageTitle { + /// + /// Looks up a localized string similar to Model Browser. + /// + public static string Label_ModelBrowser { get { - return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); + return ResourceManager.GetString("Label_ModelBrowser", resourceCulture); } } - public static string Label_OneImageSelected { + /// + /// Looks up a localized string similar to Model Description. + /// + public static string Label_ModelDescription { get { - return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); + return ResourceManager.GetString("Label_ModelDescription", resourceCulture); } } - public static string Label_Preprocessor { + /// + /// Looks up a localized string similar to Search models, #tags, or @users. + /// + public static string Label_ModelSearchWatermark { get { - return ResourceManager.GetString("Label_Preprocessor", resourceCulture); + return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); } } - public static string Label_Strength { + /// + /// Looks up a localized string similar to Models Folder. + /// + public static string Label_ModelsFolder { get { - return ResourceManager.GetString("Label_Strength", resourceCulture); + return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); } } - public static string Label_ControlWeight { + /// + /// Looks up a localized string similar to Model Type. + /// + public static string Label_ModelType { get { - return ResourceManager.GetString("Label_ControlWeight", resourceCulture); + return ResourceManager.GetString("Label_ModelType", resourceCulture); } } - public static string Label_ControlSteps { + /// + /// Looks up a localized string similar to Motion Bucket ID. + /// + public static string Label_MotionBucketId { get { - return ResourceManager.GetString("Label_ControlSteps", resourceCulture); + return ResourceManager.GetString("Label_MotionBucketId", resourceCulture); } } - public static string Label_PythonPackages { + /// + /// Looks up a localized string similar to Networks (Lora / LyCORIS). + /// + public static string Label_NetworksLoraOrLycoris { get { - return ResourceManager.GetString("Label_PythonPackages", resourceCulture); + return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); } } - public static string Action_Consolidate { + /// + /// Looks up a localized string similar to A new version of Stability Matrix is available!. + /// + public static string Label_NewVersionAvailable { get { - return ResourceManager.GetString("Action_Consolidate", resourceCulture); + return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); } } - public static string Label_AreYouSure { + /// + /// Looks up a localized string similar to Next Image. + /// + public static string Label_NextImage { get { - return ResourceManager.GetString("Label_AreYouSure", resourceCulture); + return ResourceManager.GetString("Label_NextImage", resourceCulture); } } - public static string Label_ConsolidateExplanation { + /// + /// Looks up a localized string similar to Next Page. + /// + public static string Label_NextPage { get { - return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); + return ResourceManager.GetString("Label_NextPage", resourceCulture); } } - public static string Action_Refresh { + /// + /// Looks up a localized string similar to No. + /// + public static string Label_No { get { - return ResourceManager.GetString("Action_Refresh", resourceCulture); + return ResourceManager.GetString("Label_No", resourceCulture); } } - public static string Action_Upgrade { + /// + /// Looks up a localized string similar to Node Details. + /// + public static string Label_NodeDetails { get { - return ResourceManager.GetString("Action_Upgrade", resourceCulture); + return ResourceManager.GetString("Label_NodeDetails", resourceCulture); } } - public static string Action_Downgrade { + /// + /// Looks up a localized string similar to No extensions found.. + /// + public static string Label_NoExtensionsFound { get { - return ResourceManager.GetString("Action_Downgrade", resourceCulture); + return ResourceManager.GetString("Label_NoExtensionsFound", resourceCulture); } } - public static string Action_OpenGithub { + /// + /// Looks up a localized string similar to None. + /// + public static string Label_NotificationOption_None { get { - return ResourceManager.GetString("Action_OpenGithub", resourceCulture); + return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture); } } - public static string Label_Connected { + /// + /// Looks up a localized string similar to Notifications. + /// + public static string Label_Notifications { get { - return ResourceManager.GetString("Label_Connected", resourceCulture); + return ResourceManager.GetString("Label_Notifications", resourceCulture); } } - public static string Action_Disconnect { + /// + /// Looks up a localized string similar to Number Format. + /// + public static string Label_NumberFormat { get { - return ResourceManager.GetString("Action_Disconnect", resourceCulture); + return ResourceManager.GetString("Label_NumberFormat", resourceCulture); } } - public static string Label_Email { + /// + /// Looks up a localized string similar to {0} images selected. + /// + public static string Label_NumImagesSelected { get { - return ResourceManager.GetString("Label_Email", resourceCulture); + return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); } } - public static string Label_Username { + /// + /// Looks up a localized string similar to We recommend a GPU with CUDA support for the best experience. You can continue without one, but some packages may not work, and inference may be slower.. + /// + public static string Label_NvidiaGpuRecommended { get { - return ResourceManager.GetString("Label_Username", resourceCulture); + return ResourceManager.GetString("Label_NvidiaGpuRecommended", resourceCulture); } } - public static string Label_Password { + /// + /// Looks up a localized string similar to 1 image selected. + /// + public static string Label_OneImageSelected { get { - return ResourceManager.GetString("Label_Password", resourceCulture); + return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); } } - public static string Action_Login { + /// + /// Looks up a localized string similar to Only available on Windows. + /// + public static string Label_OnlyAvailableOnWindows { get { - return ResourceManager.GetString("Action_Login", resourceCulture); + return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); } } - public static string Action_Signup { + /// + /// Looks up a localized string similar to OpenArt Browser. + /// + public static string Label_OpenArtBrowser { get { - return ResourceManager.GetString("Action_Signup", resourceCulture); + return ResourceManager.GetString("Label_OpenArtBrowser", resourceCulture); } } - public static string Label_ConfirmPassword { + /// + /// Looks up a localized string similar to Output Folder. + /// + public static string Label_OutputFolder { get { - return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); + return ResourceManager.GetString("Label_OutputFolder", resourceCulture); } } - public static string Label_ApiKey { + /// + /// Looks up a localized string similar to Output Image Files. + /// + public static string Label_OutputImageFiles { get { - return ResourceManager.GetString("Label_ApiKey", resourceCulture); + return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); } } - public static string Label_Accounts { + /// + /// Looks up a localized string similar to Output Browser. + /// + public static string Label_OutputsPageTitle { get { - return ResourceManager.GetString("Label_Accounts", resourceCulture); + return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); } } - public static string Label_CivitAiLoginRequired { + /// + /// Looks up a localized string similar to Output Type. + /// + public static string Label_OutputType { get { - return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); + return ResourceManager.GetString("Label_OutputType", resourceCulture); } } - public static string Label_DownloadFailed { + /// + /// Looks up a localized string similar to Package Environment. + /// + public static string Label_PackageEnvironment { get { - return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); + return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); } } - public static string Label_AutoUpdates { + /// + /// Looks up a localized string similar to Packages. + /// + public static string Label_Packages { get { - return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); + return ResourceManager.GetString("Label_Packages", resourceCulture); } } - public static string Label_UpdatesPreviewChannelDescription { + /// + /// Looks up a localized string similar to Package Type. + /// + public static string Label_PackageType { get { - return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_PackageType", resourceCulture); } } - public static string Label_UpdatesDevChannelDescription { + /// + /// Looks up a localized string similar to Package Uninstalled. + /// + public static string Label_PackageUninstalled { get { - return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); } } - public static string Label_Updates { + /// + /// Looks up a localized string similar to Page. + /// + public static string Label_Page { get { - return ResourceManager.GetString("Label_Updates", resourceCulture); + return ResourceManager.GetString("Label_Page", resourceCulture); } } - public static string Label_YouAreUpToDate { + /// + /// Looks up a localized string similar to Password. + /// + public static string Label_Password { get { - return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); + return ResourceManager.GetString("Label_Password", resourceCulture); } } - public static string TextTemplate_LastChecked { + /// + /// Looks up a localized string similar to Please choose a different name or select a different install location.. + /// + public static string Label_PleaseChooseDifferentName { get { - return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); + return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); } } - public static string Action_CopyTriggerWords { + /// + /// Looks up a localized string similar to Please Select a Data Directory. + /// + public static string Label_PleaseSelectDataDirectory { get { - return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); + return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); } } - public static string Label_TriggerWords { + /// + /// Looks up a localized string similar to Portable Mode. + /// + public static string Label_PortableMode { get { - return ResourceManager.GetString("Label_TriggerWords", resourceCulture); + return ResourceManager.GetString("Label_PortableMode", resourceCulture); } } - public static string TeachingTip_MoreCheckpointCategories { + /// + /// Looks up a localized string similar to In Portable Mode, all data and settings will be stored in the same directory as the application. You will be able to move the application with its 'Data' folder to a different location or computer.. + /// + public static string Label_PortableModeExplanation { get { - return ResourceManager.GetString("TeachingTip_MoreCheckpointCategories", resourceCulture); + return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); } } - public static string Action_OpenOnHuggingFace { + /// + /// Looks up a localized string similar to Preprocessor. + /// + public static string Label_Preprocessor { get { - return ResourceManager.GetString("Action_OpenOnHuggingFace", resourceCulture); + return ResourceManager.GetString("Label_Preprocessor", resourceCulture); } } - public static string Action_UpdateExistingMetadata { + /// + /// Looks up a localized string similar to Previous Image. + /// + public static string Label_PreviousImage { get { - return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); + return ResourceManager.GetString("Label_PreviousImage", resourceCulture); } } - public static string Label_General { + /// + /// Looks up a localized string similar to Previous Page. + /// + public static string Label_PreviousPage { get { - return ResourceManager.GetString("Label_General", resourceCulture); + return ResourceManager.GetString("Label_PreviousPage", resourceCulture); } } - public static string Label_Inference { + /// + /// Looks up a localized string similar to Prompt. + /// + public static string Label_Prompt { get { - return ResourceManager.GetString("Label_Inference", resourceCulture); + return ResourceManager.GetString("Label_Prompt", resourceCulture); } } - public static string Label_Prompt { + /// + /// Looks up a localized string similar to Prompt Tags. + /// + public static string Label_PromptTags { get { - return ResourceManager.GetString("Label_Prompt", resourceCulture); + return ResourceManager.GetString("Label_PromptTags", resourceCulture); } } - public static string Label_OutputImageFiles { + /// + /// Looks up a localized string similar to Tags file to use for suggesting completions (Supports the a1111-sd-webui-tagcomplete .csv format). + /// + public static string Label_PromptTagsDescription { get { - return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); } } - public static string Label_ImageViewer { + /// + /// Looks up a localized string similar to Import Prompt tags. + /// + public static string Label_PromptTagsImport { get { - return ResourceManager.GetString("Label_ImageViewer", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); } } - public static string Label_AutoCompletion { + /// + /// Looks up a localized string similar to Python Packages. + /// + public static string Label_PythonPackages { get { - return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); + return ResourceManager.GetString("Label_PythonPackages", resourceCulture); } } - public static string Label_CompletionReplaceUnderscoresWithSpaces { + /// + /// Looks up a localized string similar to Python Version Info. + /// + public static string Label_PythonVersionInfo { get { - return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); + return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); } } - public static string Label_PromptTags { + /// + /// Looks up a localized string similar to PyTorch Version. + /// + public static string Label_PyTorchVersion { get { - return ResourceManager.GetString("Label_PromptTags", resourceCulture); + return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); } } - public static string Label_PromptTagsImport { + /// + /// Looks up a localized string similar to I have read and agree to the. + /// + public static string Label_ReadAndAgree { get { - return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); + return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); } } - public static string Label_PromptTagsDescription { + /// + /// Looks up a localized string similar to Recommended Models. + /// + public static string Label_RecommendedModels { get { - return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); + return ResourceManager.GetString("Label_RecommendedModels", resourceCulture); } } - public static string Label_SystemInformation { + /// + /// Looks up a localized string similar to While your package is installing, here are some models we recommend to help you get started.. + /// + public static string Label_RecommendedModelsSubText { get { - return ResourceManager.GetString("Label_SystemInformation", resourceCulture); + return ResourceManager.GetString("Label_RecommendedModelsSubText", resourceCulture); } } - public static string Label_CivitAi { + /// + /// Looks up a localized string similar to Refiner. + /// + public static string Label_Refiner { get { - return ResourceManager.GetString("Label_CivitAi", resourceCulture); + return ResourceManager.GetString("Label_Refiner", resourceCulture); } } - public static string Label_HuggingFace { + /// + /// Looks up a localized string similar to Relaunch Required. + /// + public static string Label_RelaunchRequired { get { - return ResourceManager.GetString("Label_HuggingFace", resourceCulture); + return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); } } - public static string Label_Addons { + /// + /// Looks up a localized string similar to Release Notes. + /// + public static string Label_ReleaseNotes { get { - return ResourceManager.GetString("Label_Addons", resourceCulture); + return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); } } - public static string Label_SaveIntermediateImage { + /// + /// Looks up a localized string similar to Releases. + /// + public static string Label_Releases { get { - return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); + return ResourceManager.GetString("Label_Releases", resourceCulture); } } - public static string Label_Settings { + /// + /// Looks up a localized string similar to Remove shared checkpoints directory symbolic links on shutdown. + /// + public static string Label_RemoveSymlinksOnShutdown { get { - return ResourceManager.GetString("Label_Settings", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); } } - public static string Action_SelectFile { + /// + /// Looks up a localized string similar to Select this option if you're having problems moving Stability Matrix to another drive. + /// + public static string Label_RemoveSymlinksOnShutdown_Details { get { - return ResourceManager.GetString("Action_SelectFile", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); } } - public static string Action_ReplaceContents { + /// + /// Looks up a localized string similar to Reset Checkpoints Cache. + /// + public static string Label_ResetCheckpointsCache { get { - return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); } } - public static string Label_WipFeature { + /// + /// Looks up a localized string similar to Rebuilds the installed checkpoints cache. Use if checkpoints are incorrectly labeled in the Model Browser. + /// + public static string Label_ResetCheckpointsCache_Details { get { - return ResourceManager.GetString("Label_WipFeature", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache_Details", resourceCulture); } } - public static string Label_WipFeatureDescription { + /// + /// Looks up a localized string similar to Save Intermediate Image. + /// + public static string Label_SaveIntermediateImage { get { - return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); + return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); } } - public static string Label_MissingImageFile { + /// + /// Looks up a localized string similar to Search.... + /// + public static string Label_SearchEllipsis { get { - return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); + return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); } } - public static string Label_HolidayMode { + /// + /// Looks up a localized string similar to Select Download Location:. + /// + public static string Label_SelectDownloadLocation { get { - return ResourceManager.GetString("Label_HolidayMode", resourceCulture); + return ResourceManager.GetString("Label_SelectDownloadLocation", resourceCulture); } } - public static string Label_CLIPSkip { + /// + /// Looks up a localized string similar to Select new Data Directory. + /// + public static string Label_SelectNewDataDirectory { get { - return ResourceManager.GetString("Label_CLIPSkip", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); } } - public static string Label_ImageToVideo { + /// + /// Looks up a localized string similar to Does not move existing data. + /// + public static string Label_SelectNewDataDirectory_Details { get { - return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); } } - public static string Label_Fps { + /// + /// Looks up a localized string similar to Settings. + /// + public static string Label_Settings { get { - return ResourceManager.GetString("Label_Fps", resourceCulture); + return ResourceManager.GetString("Label_Settings", resourceCulture); } } - public static string Label_MinCfg { + /// + /// Looks up a localized string similar to Shared Model Folder Strategy. + /// + public static string Label_SharedModelFolderStrategy { get { - return ResourceManager.GetString("Label_MinCfg", resourceCulture); + return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); } } - public static string Label_Lossless { + /// + /// Looks up a localized string similar to Model Sharing. + /// + public static string Label_SharedModelStrategyShort { get { - return ResourceManager.GetString("Label_Lossless", resourceCulture); + return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); } } - public static string Label_Frames { + /// + /// Looks up a localized string similar to Show Model Images. + /// + public static string Label_ShowModelImages { get { - return ResourceManager.GetString("Label_Frames", resourceCulture); + return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); } } - public static string Label_MotionBucketId { + /// + /// Looks up a localized string similar to Show NSFW Content. + /// + public static string Label_ShowNsfwContent { get { - return ResourceManager.GetString("Label_MotionBucketId", resourceCulture); + return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); } } - public static string Label_AugmentationLevel { + /// + /// Looks up a localized string similar to Show pixel grid at high zoom levels. + /// + public static string Label_ShowPixelGridAtHighZoomLevels { get { - return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); + return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); } } - public static string Label_VideoOutputMethod { + /// + /// Looks up a localized string similar to Skip first-time setup. + /// + public static string Label_SkipSetup { get { - return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); + return ResourceManager.GetString("Label_SkipSetup", resourceCulture); } } - public static string Label_VideoQuality { + /// + /// Looks up a localized string similar to Sort. + /// + public static string Label_Sort { get { - return ResourceManager.GetString("Label_VideoQuality", resourceCulture); + return ResourceManager.GetString("Label_Sort", resourceCulture); } } - public static string Label_FindInModelBrowser { + /// + /// Looks up a localized string similar to Stability Matrix. + /// + public static string Label_StabilityMatrix { get { - return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); + return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); } } - public static string Label_Installed { + /// + /// Looks up a localized string similar to Stability Matrix is already running. + /// + public static string Label_StabilityMatrixAlreadyRunning { get { - return ResourceManager.GetString("Label_Installed", resourceCulture); + return ResourceManager.GetString("Label_StabilityMatrixAlreadyRunning", resourceCulture); } } - public static string Label_NoExtensionsFound { + /// + /// Looks up a localized string similar to Steps. + /// + public static string Label_Steps { get { - return ResourceManager.GetString("Label_NoExtensionsFound", resourceCulture); + return ResourceManager.GetString("Label_Steps", resourceCulture); } } - public static string Action_Hide { + /// + /// Looks up a localized string similar to Steps - Base. + /// + public static string Label_StepsBase { get { - return ResourceManager.GetString("Action_Hide", resourceCulture); + return ResourceManager.GetString("Label_StepsBase", resourceCulture); } } - public static string Action_CopyDetails { + /// + /// Looks up a localized string similar to Steps - Refiner. + /// + public static string Label_StepsRefiner { get { - return ResourceManager.GetString("Action_CopyDetails", resourceCulture); + return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); } } - public static string Label_Notifications { + /// + /// Looks up a localized string similar to Strength. + /// + public static string Label_Strength { get { - return ResourceManager.GetString("Label_Notifications", resourceCulture); + return ResourceManager.GetString("Label_Strength", resourceCulture); } } - public static string Label_NotificationOption_None { + /// + /// Looks up a localized string similar to System. + /// + public static string Label_System { get { - return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture); + return ResourceManager.GetString("Label_System", resourceCulture); } } - public static string Action_Download { + /// + /// Looks up a localized string similar to System Information. + /// + public static string Label_SystemInformation { get { - return ResourceManager.GetString("Action_Download", resourceCulture); + return ResourceManager.GetString("Label_SystemInformation", resourceCulture); } } - public static string TeachingTip_DownloadsExplanation { + /// + /// Looks up a localized string similar to Text to Image. + /// + public static string Label_TextToImage { get { - return ResourceManager.GetString("TeachingTip_DownloadsExplanation", resourceCulture); + return ResourceManager.GetString("Label_TextToImage", resourceCulture); } } - public static string Label_RecommendedModels { + /// + /// Looks up a localized string similar to Theme. + /// + public static string Label_Theme { get { - return ResourceManager.GetString("Label_RecommendedModels", resourceCulture); + return ResourceManager.GetString("Label_Theme", resourceCulture); } } - public static string Label_RecommendedModelsSubText { + /// + /// Looks up a localized string similar to Period. + /// + public static string Label_TimePeriod { get { - return ResourceManager.GetString("Label_RecommendedModelsSubText", resourceCulture); + return ResourceManager.GetString("Label_TimePeriod", resourceCulture); } } - public static string Label_ComfyRequiredTitle { + /// + /// Looks up a localized string similar to Auto-Scroll to End. + /// + public static string Label_ToggleAutoScrolling { get { - return ResourceManager.GetString("Label_ComfyRequiredTitle", resourceCulture); + return ResourceManager.GetString("Label_ToggleAutoScrolling", resourceCulture); } } - public static string Label_ComfyRequiredDetail { + /// + /// Looks up a localized string similar to Trigger words:. + /// + public static string Label_TriggerWords { get { - return ResourceManager.GetString("Label_ComfyRequiredDetail", resourceCulture); + return ResourceManager.GetString("Label_TriggerWords", resourceCulture); } } - public static string Error_PleaseSelectDownloadLocation { + /// + /// Looks up a localized string similar to An unexpected error occurred. + /// + public static string Label_UnexpectedErrorOccurred { get { - return ResourceManager.GetString("Error_PleaseSelectDownloadLocation", resourceCulture); + return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); } } - public static string Label_SelectDownloadLocation { + /// + /// Looks up a localized string similar to Unknown Package. + /// + public static string Label_UnknownPackage { get { - return ResourceManager.GetString("Label_SelectDownloadLocation", resourceCulture); + return ResourceManager.GetString("Label_UnknownPackage", resourceCulture); } } - public static string Label_Workflows { + /// + /// Looks up a localized string similar to Update Available. + /// + public static string Label_UpdateAvailable { get { - return ResourceManager.GetString("Label_Workflows", resourceCulture); + return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); } } - public static string Label_InfiniteScrolling { + /// + /// Looks up a localized string similar to Updates. + /// + public static string Label_Updates { get { - return ResourceManager.GetString("Label_InfiniteScrolling", resourceCulture); + return ResourceManager.GetString("Label_Updates", resourceCulture); } } - public static string Label_WorkflowBrowser { + /// + /// Looks up a localized string similar to For technical users. Be the first to access our Development builds from feature branches as soon as they are available. There may be some rough edges and bugs as we experiment with new features.. + /// + public static string Label_UpdatesDevChannelDescription { get { - return ResourceManager.GetString("Label_WorkflowBrowser", resourceCulture); + return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); } } - public static string Label_Config { + /// + /// Looks up a localized string similar to For early adopters. Preview builds will be more reliable than those from the Dev channel, and will be available closer to stable releases. Your feedback will help us greatly in discovering issues and polishing design elements.. + /// + public static string Label_UpdatesPreviewChannelDescription { get { - return ResourceManager.GetString("Label_Config", resourceCulture); + return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); } } - public static string Action_OpenOnOpenArt { + /// + /// Looks up a localized string similar to Upscale. + /// + public static string Label_Upscale { get { - return ResourceManager.GetString("Action_OpenOnOpenArt", resourceCulture); + return ResourceManager.GetString("Label_Upscale", resourceCulture); } } - public static string Label_NodeDetails { + /// + /// Looks up a localized string similar to Username. + /// + public static string Label_Username { get { - return ResourceManager.GetString("Label_NodeDetails", resourceCulture); + return ResourceManager.GetString("Label_Username", resourceCulture); } } - public static string Label_WorkflowDescription { + /// + /// Looks up a localized string similar to Output Sharing. + /// + public static string Label_UseSharedOutputFolder { get { - return ResourceManager.GetString("Label_WorkflowDescription", resourceCulture); + return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); } } - public static string Label_OpenArtBrowser { + /// + /// Looks up a localized string similar to VAE. + /// + public static string Label_VAE { get { - return ResourceManager.GetString("Label_OpenArtBrowser", resourceCulture); + return ResourceManager.GetString("Label_VAE", resourceCulture); } } - public static string Action_PreviewPreprocessor { + /// + /// Looks up a localized string similar to Version. + /// + public static string Label_Version { get { - return ResourceManager.GetString("Action_PreviewPreprocessor", resourceCulture); + return ResourceManager.GetString("Label_Version", resourceCulture); } } - public static string Label_ToggleAutoScrolling { + /// + /// Looks up a localized string similar to Version Type. + /// + public static string Label_VersionType { get { - return ResourceManager.GetString("Label_ToggleAutoScrolling", resourceCulture); + return ResourceManager.GetString("Label_VersionType", resourceCulture); } } - public static string Label_ConfirmExit { + /// + /// Looks up a localized string similar to Method. + /// + public static string Label_VideoOutputMethod { get { - return ResourceManager.GetString("Label_ConfirmExit", resourceCulture); + return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); } } - public static string Label_ConfirmExitDetail { + /// + /// Looks up a localized string similar to Quality. + /// + public static string Label_VideoQuality { get { - return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture); + return ResourceManager.GetString("Label_VideoQuality", resourceCulture); } } - public static string Label_Console { + /// + /// Looks up a localized string similar to Waiting to connect.... + /// + public static string Label_WaitingToConnectEllipsis { get { - return ResourceManager.GetString("Label_Console", resourceCulture); + return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); } } + /// + /// Looks up a localized string similar to Web UI. + /// public static string Label_WebUi { get { return ResourceManager.GetString("Label_WebUi", resourceCulture); } } - public static string Label_Packages { + /// + /// Looks up a localized string similar to Width. + /// + public static string Label_Width { get { - return ResourceManager.GetString("Label_Packages", resourceCulture); + return ResourceManager.GetString("Label_Width", resourceCulture); } } - public static string Label_ActionCannotBeUndone { + /// + /// Looks up a localized string similar to Not yet available. + /// + public static string Label_WipFeature { get { - return ResourceManager.GetString("Label_ActionCannotBeUndone", resourceCulture); + return ResourceManager.GetString("Label_WipFeature", resourceCulture); } } - public static string Label_AreYouSureDeleteImages { + /// + /// Looks up a localized string similar to Feature will be available in a future update. + /// + public static string Label_WipFeatureDescription { get { - return ResourceManager.GetString("Label_AreYouSureDeleteImages", resourceCulture); + return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); } } - public static string Label_CheckingHardware { + /// + /// Looks up a localized string similar to Workflow Browser. + /// + public static string Label_WorkflowBrowser { get { - return ResourceManager.GetString("Label_CheckingHardware", resourceCulture); + return ResourceManager.GetString("Label_WorkflowBrowser", resourceCulture); } } - public static string Label_EverythingLooksGood { + /// + /// Looks up a localized string similar to Workflow Deleted. + /// + public static string Label_WorkflowDeleted { get { - return ResourceManager.GetString("Label_EverythingLooksGood", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDeleted", resourceCulture); } } - public static string Label_NvidiaGpuRecommended { + /// + /// Looks up a localized string similar to {0} deleted successfully. + /// + public static string Label_WorkflowDeletedSuccessfully { get { - return ResourceManager.GetString("Label_NvidiaGpuRecommended", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDeletedSuccessfully", resourceCulture); } } - public static string Label_Checkpoints { + /// + /// Looks up a localized string similar to Workflow Description. + /// + public static string Label_WorkflowDescription { get { - return ResourceManager.GetString("Label_Checkpoints", resourceCulture); + return ResourceManager.GetString("Label_WorkflowDescription", resourceCulture); } } - public static string Label_ModelBrowser { + /// + /// Looks up a localized string similar to The workflow and custom nodes have been imported.. + /// + public static string Label_WorkflowImportComplete { get { - return ResourceManager.GetString("Label_ModelBrowser", resourceCulture); + return ResourceManager.GetString("Label_WorkflowImportComplete", resourceCulture); } } - public static string TeachingTip_WebUiButtonMoved { + /// + /// Looks up a localized string similar to Workflow Imported. + /// + public static string Label_WorkflowImported { get { - return ResourceManager.GetString("TeachingTip_WebUiButtonMoved", resourceCulture); + return ResourceManager.GetString("Label_WorkflowImported", resourceCulture); } } - public static string Label_AnotherInstanceAlreadyRunning { + /// + /// Looks up a localized string similar to Workflows. + /// + public static string Label_Workflows { get { - return ResourceManager.GetString("Label_AnotherInstanceAlreadyRunning", resourceCulture); + return ResourceManager.GetString("Label_Workflows", resourceCulture); } } - public static string Label_StabilityMatrixAlreadyRunning { + /// + /// Looks up a localized string similar to You're up to date. + /// + public static string Label_YouAreUpToDate { get { - return ResourceManager.GetString("Label_StabilityMatrixAlreadyRunning", resourceCulture); + return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); } } - public static string Label_WorkflowDeletedSuccessfully { + /// + /// Looks up a localized string similar to Download complete. + /// + public static string Progress_DownloadComplete { get { - return ResourceManager.GetString("Label_WorkflowDeletedSuccessfully", resourceCulture); + return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); } } - public static string Label_WorkflowDeleted { + /// + /// Looks up a localized string similar to Downloading package.... + /// + public static string Progress_DownloadingPackage { get { - return ResourceManager.GetString("Label_WorkflowDeleted", resourceCulture); + return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); } } - public static string Label_ErrorRetrievingWorkflows { + /// + /// Looks up a localized string similar to Installation complete. + /// + public static string Progress_InstallationComplete { get { - return ResourceManager.GetString("Label_ErrorRetrievingWorkflows", resourceCulture); + return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); } } - public static string TabLabel_InstalledWorkflows { + /// + /// Looks up a localized string similar to Installing package requirements.... + /// + public static string Progress_InstallingPackageRequirements { get { - return ResourceManager.GetString("TabLabel_InstalledWorkflows", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); } } - public static string Label_WorkflowImported { + /// + /// Looks up a localized string similar to Installing prerequisites.... + /// + public static string Progress_InstallingPrerequisites { get { - return ResourceManager.GetString("Label_WorkflowImported", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); } } - public static string Label_FinishedImportingWorkflow { + /// + /// Looks up a localized string similar to Uninstalling package.... + /// + public static string Progress_UninstallingPackage { get { - return ResourceManager.GetString("Label_FinishedImportingWorkflow", resourceCulture); + return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); } } - public static string Label_WorkflowImportComplete { + /// + /// Looks up a localized string similar to Update complete. + /// + public static string Progress_UpdateComplete { get { - return ResourceManager.GetString("Label_WorkflowImportComplete", resourceCulture); + return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); } } - public static string TeachingTip_InferencePromptHelpButton { + /// + /// Looks up a localized string similar to Update failed. + /// + public static string Progress_UpdateFailed { get { - return ResourceManager.GetString("TeachingTip_InferencePromptHelpButton", resourceCulture); + return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); } } - public static string Label_ExtraNetworks { + /// + /// Looks up a localized string similar to Installed Workflows. + /// + public static string TabLabel_InstalledWorkflows { get { - return ResourceManager.GetString("Label_ExtraNetworks", resourceCulture); + return ResourceManager.GetString("TabLabel_InstalledWorkflows", resourceCulture); } } - public static string Label_CLIPStrength { + /// + /// Looks up a localized string similar to Add a package to get started!. + /// + public static string TeachingTip_AddPackageToGetStarted { get { - return ResourceManager.GetString("Label_CLIPStrength", resourceCulture); + return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); } } - public static string Label_NumberFormat { + /// + /// Looks up a localized string similar to Click Launch to get started!. + /// + public static string TeachingTip_ClickLaunchToGetStarted { get { - return ResourceManager.GetString("Label_NumberFormat", resourceCulture); + return ResourceManager.GetString("TeachingTip_ClickLaunchToGetStarted", resourceCulture); } } - public static string Text_DeleteFollowingItems { + /// + /// Looks up a localized string similar to Check the progress of your package installations and model downloads here.. + /// + public static string TeachingTip_DownloadsExplanation { get { - return ResourceManager.GetString("Text_DeleteFollowingItems", resourceCulture); + return ResourceManager.GetString("TeachingTip_DownloadsExplanation", resourceCulture); } } - public static string TextTemplate_DeleteFollowingCountItems { + /// + /// Looks up a localized string similar to Click here to review prompt syntax and how to include Lora / Embeddings.. + /// + public static string TeachingTip_InferencePromptHelpButton { get { - return ResourceManager.GetString("TextTemplate_DeleteFollowingCountItems", resourceCulture); + return ResourceManager.GetString("TeachingTip_InferencePromptHelpButton", resourceCulture); } } - public static string Label_DeletePermanently { + /// + /// Looks up a localized string similar to Additional folders such as IPAdapters and TextualInversions (embeddings) can be enabled here. + /// + public static string TeachingTip_MoreCheckpointCategories { get { - return ResourceManager.GetString("Label_DeletePermanently", resourceCulture); + return ResourceManager.GetString("TeachingTip_MoreCheckpointCategories", resourceCulture); } } - public static string Action_MoveToTrash { + /// + /// Looks up a localized string similar to The 'Open Web UI' button has moved to the command bar. + /// + public static string TeachingTip_WebUiButtonMoved { get { - return ResourceManager.GetString("Action_MoveToTrash", resourceCulture); + return ResourceManager.GetString("TeachingTip_WebUiButtonMoved", resourceCulture); } } - public static string Label_AreYouSureDeleteModels { + /// + /// Looks up a localized string similar to The app will relaunch after updating. + /// + public static string Text_AppWillRelaunchAfterUpdate { get { - return ResourceManager.GetString("Label_AreYouSureDeleteModels", resourceCulture); + return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); } } - public static string Label_AutoSearchOnLoad { + /// + /// Looks up a localized string similar to You are about to delete the following items:. + /// + public static string Text_DeleteFollowingItems { get { - return ResourceManager.GetString("Label_AutoSearchOnLoad", resourceCulture); + return ResourceManager.GetString("Text_DeleteFollowingItems", resourceCulture); } } - public static string Label_AutoSearchOnLoad_Description { + /// + /// Looks up a localized string similar to Choose your preferred interface to get started. + /// + public static string Text_OneClickInstaller_SubHeader { get { - return ResourceManager.GetString("Label_AutoSearchOnLoad_Description", resourceCulture); + return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); } } - public static string Action_ToggleVisibility { + /// + /// Looks up a localized string similar to This will delete the package folder and all its contents, including any generated images and files you may have added.. + /// + public static string Text_PackageUninstall_Details { get { - return ResourceManager.GetString("Action_ToggleVisibility", resourceCulture); + return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); } } - public static string Label_ClippingMask { + /// + /// Looks up a localized string similar to Proceeding to Launch page. + /// + public static string Text_ProceedingToLaunchPage { get { - return ResourceManager.GetString("Label_ClippingMask", resourceCulture); + return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); } } - public static string Label_AppFolders { + /// + /// Looks up a localized string similar to Relaunch is required for new language option to take effect. + /// + public static string Text_RelaunchRequiredToApplyLanguage { get { - return ResourceManager.GetString("Label_AppFolders", resourceCulture); + return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); } } - public static string Label_Logs { + /// + /// Looks up a localized string similar to Some files could not be deleted. Please close any open files in the package directory and try again.. + /// + public static string Text_SomeFilesCouldNotBeDeleted { get { - return ResourceManager.GetString("Label_Logs", resourceCulture); + return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); } } - public static string Label_AppData { + /// + /// Looks up a localized string similar to Welcome to Stability Matrix!. + /// + public static string Text_WelcomeToStabilityMatrix { get { - return ResourceManager.GetString("Label_AppData", resourceCulture); + return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); } } - public static string TextTemplate_PackageUpdatedToSelected { + /// + /// Looks up a localized string similar to You are about to delete the following {0} items:. + /// + public static string TextTemplate_DeleteFollowingCountItems { get { - return ResourceManager.GetString("TextTemplate_PackageUpdatedToSelected", resourceCulture); + return ResourceManager.GetString("TextTemplate_DeleteFollowingCountItems", resourceCulture); } } - public static string Action_CopyAsBitmap { + /// + /// Looks up a localized string similar to Error updating {0}. + /// + public static string TextTemplate_ErrorUpdatingPackage { get { - return ResourceManager.GetString("Action_CopyAsBitmap", resourceCulture); + return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); } } - public static string Label_DisableUpdateCheck { + /// + /// Looks up a localized string similar to Last checked: {0}. + /// + public static string TextTemplate_LastChecked { get { - return ResourceManager.GetString("Label_DisableUpdateCheck", resourceCulture); + return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); } } - public static string Warning_PleaseExtractFirst { + /// + /// Looks up a localized string similar to {0} has been updated to the latest version. + /// + public static string TextTemplate_PackageUpdatedToLatest { get { - return ResourceManager.GetString("Warning_PleaseExtractFirst", resourceCulture); + return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); } } - public static string Label_HistorySize { + /// + /// Looks up a localized string similar to {0} has been updated to the selected version. + /// + public static string TextTemplate_PackageUpdatedToSelected { get { - return ResourceManager.GetString("Label_HistorySize", resourceCulture); + return ResourceManager.GetString("TextTemplate_PackageUpdatedToSelected", resourceCulture); } } - public static string Label_HistorySize_Description { + /// + /// Looks up a localized string similar to Updating {0}. + /// + public static string TextTemplate_UpdatingPackage { get { - return ResourceManager.GetString("Label_HistorySize_Description", resourceCulture); + return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); } } - public static string Label_ConnectAccountFailed { + /// + /// Looks up a localized string similar to PLEASE EXTRACT THE APP FROM THE ZIP FILE BEFORE RUNNING STABILITY MATRIX. + /// + public static string Warning_PleaseExtractFirst { get { - return ResourceManager.GetString("Label_ConnectAccountFailed", resourceCulture); + return ResourceManager.GetString("Warning_PleaseExtractFirst", resourceCulture); } } } From 9dad1e069e0c3eb61a12330fb55e3770afddd0a1 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 10 Aug 2024 16:53:13 -0400 Subject: [PATCH 170/325] Fix some warnings for Avalonia.Gif --- Avalonia.Gif/Avalonia.Gif.csproj | 6 ++++ Avalonia.Gif/Decoding/GifDecoder.cs | 29 +++++++++++++++---- .../Decoding/InvalidGifStreamException.cs | 6 ---- .../Decoding/LzwDecompressionException.cs | 6 ---- Avalonia.Gif/GifInstance.cs | 21 +++++++++----- Avalonia.Gif/InvalidGifStreamException.cs | 6 ---- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Avalonia.Gif/Avalonia.Gif.csproj b/Avalonia.Gif/Avalonia.Gif.csproj index c62673009..44f254430 100644 --- a/Avalonia.Gif/Avalonia.Gif.csproj +++ b/Avalonia.Gif/Avalonia.Gif.csproj @@ -9,6 +9,12 @@ true true + + + + $(NoWarn);CS8765;CS8618;CS8625;CS0169 + + diff --git a/Avalonia.Gif/Decoding/GifDecoder.cs b/Avalonia.Gif/Decoding/GifDecoder.cs index adc26bb0e..da89b30ed 100644 --- a/Avalonia.Gif/Decoding/GifDecoder.cs +++ b/Avalonia.Gif/Decoding/GifDecoder.cs @@ -9,6 +9,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.CompilerServices; @@ -190,7 +191,9 @@ private void RenderFrameAt(int idx, WriteableBitmap writeableBitmap) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void DrawFrame(GifFrame curFrame, Memory frameIndexSpan) { - var activeColorTable = curFrame.IsLocalColorTableUsed ? curFrame.LocalColorTable : Header.GlobarColorTable; + var activeColorTable = curFrame.IsLocalColorTableUsed + ? curFrame.LocalColorTable + : Header.GlobarColorTable; var cX = curFrame.Dimensions.X; var cY = curFrame.Dimensions.Y; @@ -232,7 +235,11 @@ void DrawRow(int row) { var indexColor = frameIndexSpan.Span[indexOffset + i]; - if (activeColorTable == null || targetOffset >= len || indexColor > activeColorTable.Length) + if ( + activeColorTable == null + || targetOffset >= len + || indexColor > activeColorTable.Length + ) return; if (!(hT & indexColor == tC)) @@ -420,7 +427,12 @@ private void WriteBackBufToFb(IntPtr targetPointer) unsafe { fixed (void* src = &_bitmapBackBuffer[0]) - Buffer.MemoryCopy(src, targetPointer.ToPointer(), (uint)_backBufferBytes, (uint)_backBufferBytes); + Buffer.MemoryCopy( + src, + targetPointer.ToPointer(), + (uint)_backBufferBytes, + (uint)_backBufferBytes + ); _hasNewFrame = false; } } @@ -428,6 +440,7 @@ private void WriteBackBufToFb(IntPtr targetPointer) /// /// Processes GIF Header. /// + [MemberNotNull(nameof(Header))] private void ProcessHeaderData() { var str = _fileStream; @@ -549,7 +562,9 @@ private void ProcessFrameData() // Break the loop when the stream is not valid anymore. if (_fileStream.Position >= _fileStream.Length & terminate == false) - throw new InvalidProgramException("Reach the end of the filestream without trailer block."); + throw new InvalidProgramException( + "Reach the end of the filestream without trailer block." + ); } while (!terminate); ArrayPool.Shared.Return(tempBuf); @@ -581,7 +596,11 @@ private void ProcessImageDescriptor(ref int curFrame, byte[] tempBuf) currentFrame.LocalColorTableSize = (int)Math.Pow(2, (packed & 0x07) + 1); if (currentFrame.IsLocalColorTableUsed) - currentFrame.LocalColorTable = ProcessColorTable(ref str, tempBuf, currentFrame.LocalColorTableSize); + currentFrame.LocalColorTable = ProcessColorTable( + ref str, + tempBuf, + currentFrame.LocalColorTableSize + ); currentFrame.LzwMinCodeSize = str.ReadByteS(tempBuf); currentFrame.LzwStreamPosition = str.Position; diff --git a/Avalonia.Gif/Decoding/InvalidGifStreamException.cs b/Avalonia.Gif/Decoding/InvalidGifStreamException.cs index b3554bac4..28badc179 100644 --- a/Avalonia.Gif/Decoding/InvalidGifStreamException.cs +++ b/Avalonia.Gif/Decoding/InvalidGifStreamException.cs @@ -1,9 +1,6 @@ // Licensed under the MIT License. // Copyright (C) 2018 Jumar A. Macato, All Rights Reserved. -using System; -using System.Runtime.Serialization; - namespace Avalonia.Gif.Decoding { [Serializable] @@ -16,8 +13,5 @@ public InvalidGifStreamException(string message) public InvalidGifStreamException(string message, Exception innerException) : base(message, innerException) { } - - protected InvalidGifStreamException(SerializationInfo info, StreamingContext context) - : base(info, context) { } } } diff --git a/Avalonia.Gif/Decoding/LzwDecompressionException.cs b/Avalonia.Gif/Decoding/LzwDecompressionException.cs index ed25c0aad..597dc9d82 100644 --- a/Avalonia.Gif/Decoding/LzwDecompressionException.cs +++ b/Avalonia.Gif/Decoding/LzwDecompressionException.cs @@ -1,9 +1,6 @@ // Licensed under the MIT License. // Copyright (C) 2018 Jumar A. Macato, All Rights Reserved. -using System; -using System.Runtime.Serialization; - namespace Avalonia.Gif.Decoding { [Serializable] @@ -16,8 +13,5 @@ public LzwDecompressionException(string message) public LzwDecompressionException(string message, Exception innerException) : base(message, innerException) { } - - protected LzwDecompressionException(SerializationInfo info, StreamingContext context) - : base(info, context) { } } } diff --git a/Avalonia.Gif/GifInstance.cs b/Avalonia.Gif/GifInstance.cs index b97badaa5..05b6b25e6 100644 --- a/Avalonia.Gif/GifInstance.cs +++ b/Avalonia.Gif/GifInstance.cs @@ -55,16 +55,23 @@ public GifInstance(Stream currentStream) CurrentCts = new CancellationTokenSource(); _gifDecoder = new GifDecoder(currentStream, CurrentCts.Token); - var pixSize = new PixelSize(_gifDecoder.Header.Dimensions.Width, _gifDecoder.Header.Dimensions.Height); - - _targetBitmap = new WriteableBitmap(pixSize, new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Opaque); + var pixSize = new PixelSize( + _gifDecoder.Header.Dimensions.Width, + _gifDecoder.Header.Dimensions.Height + ); + + _targetBitmap = new WriteableBitmap( + pixSize, + new Vector(96, 96), + PixelFormat.Bgra8888, + AlphaFormat.Opaque + ); GifPixelSize = pixSize; _totalTime = TimeSpan.Zero; _frameTimes = _gifDecoder - .Frames - .Select(frame => + .Frames.Select(frame => { _totalTime = _totalTime.Add(frame.FrameDelay); return _totalTime; @@ -138,10 +145,10 @@ public void Dispose() internal WriteableBitmap ProcessFrameIndex(int frameIndex) { - _gifDecoder.RenderFrame(frameIndex, _targetBitmap); + _gifDecoder.RenderFrame(frameIndex, _targetBitmap!); _currentFrameIndex = frameIndex; - return _targetBitmap; + return _targetBitmap!; } } } diff --git a/Avalonia.Gif/InvalidGifStreamException.cs b/Avalonia.Gif/InvalidGifStreamException.cs index 9771d9cb9..892e041c5 100644 --- a/Avalonia.Gif/InvalidGifStreamException.cs +++ b/Avalonia.Gif/InvalidGifStreamException.cs @@ -1,6 +1,3 @@ -using System; -using System.Runtime.Serialization; - namespace Avalonia.Gif { [Serializable] @@ -13,8 +10,5 @@ public InvalidGifStreamException(string message) public InvalidGifStreamException(string message, Exception innerException) : base(message, innerException) { } - - protected InvalidGifStreamException(SerializationInfo info, StreamingContext context) - : base(info, context) { } } } From cff166ff8d13ff55a9f80ff2032f966f27e96bdf Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 10 Aug 2024 18:49:04 -0400 Subject: [PATCH 171/325] Fix args creation in RunningPackageService --- .../Services/RunningPackageService.cs | 13 +++++++----- StabilityMatrix.Core/Processes/ProcessArgs.cs | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs index d82911dbe..22e4c4ee1 100644 --- a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs +++ b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs @@ -17,6 +17,7 @@ using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Packages; +using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; @@ -129,16 +130,18 @@ await basePackage.UpdateModelFolders( } // Load user launch args from settings - var launchArgs = - installedPackage.LaunchArgs?.Select(option => option.ToArgString()).WhereNotNull().ToList() ?? []; + var launchArgStrings = (installedPackage.LaunchArgs ?? []) + .Select(option => option.ToArgString()) + .WhereNotNull() + .ToArray(); - // Join with extras, if any - launchArgs.AddRange(basePackage.ExtraLaunchArguments); + var launchProcessArgs = ProcessArgs.FromQuoted(launchArgStrings); + // Join with extras, if any await basePackage.RunPackage( packagePath, installedPackage, - new RunPackageOptions { Command = command, Arguments = launchArgs }, + new RunPackageOptions { Command = command, Arguments = launchProcessArgs.ToArray() }, console.Post, cancellationToken ); diff --git a/StabilityMatrix.Core/Processes/ProcessArgs.cs b/StabilityMatrix.Core/Processes/ProcessArgs.cs index a4122897a..dbd6706b8 100644 --- a/StabilityMatrix.Core/Processes/ProcessArgs.cs +++ b/StabilityMatrix.Core/Processes/ProcessArgs.cs @@ -13,6 +13,26 @@ namespace StabilityMatrix.Core.Processes; [CollectionBuilder(typeof(ProcessArgsCollectionBuilder), "Create")] public partial class ProcessArgs : OneOfBase, IEnumerable { + /// + /// Create a new from pre-quoted argument parts, + /// which may contain spaces or multiple arguments. + /// + /// Quoted string arguments + /// A new instance + public static ProcessArgs FromQuoted(IEnumerable inputs) + { + ProcessArgs? result = null; + + foreach (var input in inputs) + { + result = + result?.Concat(new ProcessArgs(OneOf.FromT0(input))) + ?? new ProcessArgs(OneOf.FromT0(input)); + } + + return result ?? new ProcessArgs(OneOf.FromT1([])); + } + /// public ProcessArgs(OneOf input) : base(input) { } From 82a9608ae7b3c10508a43f37bddec518f5a992d1 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 10 Aug 2024 19:11:07 -0700 Subject: [PATCH 172/325] Add toggle for hide installed models & no longer pin comfy torch & rocm6 & avalonia update & stuff --- CHANGELOG.md | 9 + Directory.Build.props | 2 +- .../StabilityMatrix.Avalonia.csproj | 8 +- .../CheckpointBrowserCardViewModel.cs | 22 +-- .../CivitAiBrowserViewModel.cs | 134 ++++++++------ .../Views/CivitAiBrowserPage.axaml | 168 ++++++++++-------- .../Models/Packages/ComfyUI.cs | 15 +- .../Models/Settings/Settings.cs | 4 +- 8 files changed, 197 insertions(+), 165 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 263c754d7..dda5402c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ 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.12.0-pre.1 +### Added +- Added "Hide Installed Models" toggle to the CivitAI Model Browser +### Changed +- ComfyUI will no longer be pinned to torch 2.1.2 for nvidia users on Windows +- Model browser download progress no longer covers the entire card for the entire duration of the download +- Updated torch index to `rocm6.0` for AMD users of ComfyUI +- (Internal) Updated to Avalonia 11.1.2 + ## v2.12.0-dev.3 ### Added - Added Settings option "Console: History Size" to adjust the number of lines stored in the console history when running packages. Defaults to 9001 lines. diff --git a/Directory.Build.props b/Directory.Build.props index d5d518c9e..85e385eb9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@  - 11.1.1 + 11.1.2 diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 60fd0db69..4469322ee 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -38,7 +38,7 @@ - + @@ -48,11 +48,11 @@ - + - - + + diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs index e28f183a1..7476cace7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs @@ -64,6 +64,9 @@ public CivitModel CivitModel [ObservableProperty] private bool isImporting; + [ObservableProperty] + private bool isLoading; + [ObservableProperty] private string updateCardText = string.Empty; @@ -271,6 +274,10 @@ private async Task ShowVersionDialog(CivitModel model) await Task.Delay(100); await DoImport(model, downloadPath, selectedVersion, selectedFile); + + Text = "Import started. Check the downloads tab for progress."; + Value = 100; + DelayedClearProgress(TimeSpan.FromMilliseconds(1000)); } private static async Task SaveCmInfo( @@ -331,6 +338,7 @@ private async Task DoImport( ) { IsImporting = true; + IsLoading = true; Text = "Downloading..."; OnDownloadStart?.Invoke(this); @@ -389,19 +397,6 @@ private async Task DoImport( } // Attach for progress updates - download.ProgressUpdate += (s, e) => - { - Value = e.Percentage; - if (e.Type == ProgressType.Hashing) - { - Text = $"Validating... {e.Percentage}%"; - } - else - { - Text = $"Downloading... {e.Percentage}%"; - } - }; - download.ProgressStateChanged += (s, e) => { if (e == ProgressState.Success) @@ -439,6 +434,7 @@ private void DelayedClearProgress(TimeSpan delay) Text = string.Empty; Value = 0; IsImporting = false; + IsLoading = false; }); } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index 8cd06b2f6..86c7b390b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -1,18 +1,19 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Net.Http; +using System.Reactive.Linq; using System.Threading.Tasks; using AsyncAwaitBestPractices; -using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Notifications; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using LiteDB; -using LiteDB.Async; +using DynamicData; +using DynamicData.Binding; using NLog; using Refit; using StabilityMatrix.Avalonia.Languages; @@ -41,10 +42,8 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScro private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly ICivitApi civitApi; private readonly ISettingsManager settingsManager; - private readonly ServiceManager dialogFactory; private readonly ILiteDbContext liteDbContext; private readonly INotificationService notificationService; - private const int MaxModelsPerPage = 20; private LRUCache< int /* model id */ @@ -52,11 +51,11 @@ private LRUCache< CheckpointBrowserCardViewModel > cache = new(150); - [ObservableProperty] - private ObservableCollection modelCards = new(); + private SourceCache modelCache = new(m => m.Id); [ObservableProperty] - private DataGridCollectionView? modelCardsView; + private IObservableCollection modelCards = + new ObservableCollectionExtended(); [ObservableProperty] private string searchQuery = string.Empty; @@ -97,6 +96,9 @@ private LRUCache< [ObservableProperty] private string? nextPageCursor; + [ObservableProperty] + private bool hideInstalledModels; + public IEnumerable AllCivitPeriods => Enum.GetValues(typeof(CivitPeriod)).Cast(); public IEnumerable AllSortModes => @@ -122,11 +124,55 @@ INotificationService notificationService { this.civitApi = civitApi; this.settingsManager = settingsManager; - this.dialogFactory = dialogFactory; this.liteDbContext = liteDbContext; this.notificationService = notificationService; EventManager.Instance.NavigateAndFindCivitModelRequested += OnNavigateAndFindCivitModelRequested; + + var filterPredicate = Observable + .FromEventPattern(this, nameof(PropertyChanged)) + .Where(x => x.EventArgs.PropertyName is nameof(HideInstalledModels) or nameof(ShowNsfw)) + .Throttle(TimeSpan.FromMilliseconds(50)) + .Select(_ => (Func)FilterModelCardsPredicate) + .AsObservable(); + + // make the filter go + OnPropertyChanged(nameof(HideInstalledModels)); + + modelCache + .Connect() + .DeferUntilLoaded() + .Transform(model => + { + var cachedViewModel = cache.Get(model.Id); + if (cachedViewModel != null) + { + if (!cachedViewModel.IsImporting) + { + cache.Remove(model.Id); + } + + return cachedViewModel; + } + + var newCard = dialogFactory.Get(vm => + { + vm.CivitModel = model; + vm.OnDownloadStart = viewModel => + { + if (cache.Get(viewModel.CivitModel.Id) != null) + return; + cache.Add(viewModel.CivitModel.Id, viewModel); + }; + + return vm; + }); + + return newCard; + }) + .Filter(filterPredicate) + .Bind(ModelCards) + .Subscribe(); } private void OnNavigateAndFindCivitModelRequested(object? sender, int e) @@ -173,6 +219,13 @@ public override void OnLoaded() settings => settings.ModelBrowserNsfwEnabled ); + settingsManager.RelayPropertyFor( + this, + model => model.HideInstalledModels, + settings => settings.HideInstalledModelsInModelBrowser, + true + ); + if (settingsManager.Settings.AutoLoadCivitModels) { SearchModelsCommand.ExecuteAsync(false); @@ -182,10 +235,14 @@ public override void OnLoaded() /// /// Filter predicate for model cards /// - private bool FilterModelCardsPredicate(object? item) + private bool FilterModelCardsPredicate(CheckpointBrowserCardViewModel? card) { - if (item is not CheckpointBrowserCardViewModel card) + if (card == null) + return false; + + if (HideInstalledModels && card.UpdateCardText == "Installed") return false; + return !card.CivitModel.Nsfw || ShowNsfw; } @@ -324,63 +381,26 @@ private void UpdateModelCards(List? models, bool addCards = false) { if (models is null) { - ModelCards?.Clear(); + modelCache.Clear(); } else { - var modelsToAdd = models - .Select(model => - { - var cachedViewModel = cache.Get(model.Id); - if (cachedViewModel != null) - { - if (!cachedViewModel.IsImporting) - { - cache.Remove(model.Id); - } - - return cachedViewModel; - } - - var newCard = dialogFactory.Get(vm => - { - vm.CivitModel = model; - vm.OnDownloadStart = viewModel => - { - if (cache.Get(viewModel.CivitModel.Id) != null) - return; - cache.Add(viewModel.CivitModel.Id, viewModel); - }; - - return vm; - }); - - return newCard; - }) - .Where(FilterModelCardsPredicate); - - if (SortMode == CivitSortMode.Installed) - { - modelsToAdd = modelsToAdd.OrderByDescending(x => x.UpdateCardText == "Update Available"); - } + var modelsToAdd = models; if (!addCards) { - ModelCards = new ObservableCollection(modelsToAdd); + modelCache.EditDiff(modelsToAdd, (a, b) => a.Id == b.Id); } else { foreach (var model in modelsToAdd) { - if ( - ModelCards.Contains( - model, - new PropertyComparer(x => x.CivitModel.Id) - ) - ) + if (modelCache.Items.Contains(model, new PropertyComparer(x => x.Id))) + { continue; + } - ModelCards.Add(model); + modelCache.AddOrUpdate(model); } } } @@ -460,6 +480,8 @@ private async Task SearchModels(bool isInfiniteScroll = false) m => m.ConnectedModelInfo != null ); + connectedModels = connectedModels.Where(x => x.HasCivitMetadata); + modelRequest.CommaSeparatedModelIds = string.Join( ",", connectedModels @@ -608,7 +630,7 @@ private async Task TrySearchAgain(bool shouldUpdatePageNumber = true) { if (!HasSearched) return; - ModelCards?.Clear(); + modelCache.Clear(); if (shouldUpdatePageNumber) { diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index 87d512390..9855d3ab0 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -29,41 +29,41 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/OAuthLoginDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/OAuthLoginDialog.axaml.cs new file mode 100644 index 000000000..c456ac07a --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/OAuthLoginDialog.axaml.cs @@ -0,0 +1,13 @@ +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Views.Dialogs; + +[Transient] +public partial class OAuthLoginDialog : UserControlBase +{ + public OAuthLoginDialog() + { + InitializeComponent(); + } +} diff --git a/StabilityMatrix.Core/Api/ILykosAuthApi.cs b/StabilityMatrix.Core/Api/ILykosAuthApi.cs index 35d507bb2..8bfeaa79b 100644 --- a/StabilityMatrix.Core/Api/ILykosAuthApi.cs +++ b/StabilityMatrix.Core/Api/ILykosAuthApi.cs @@ -1,10 +1,12 @@ -using System.Net; +using System.ComponentModel; +using System.Net; using Refit; using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Api.Lykos; namespace StabilityMatrix.Core.Api; +[Localizable(false)] [Headers("User-Agent: StabilityMatrix")] public interface ILykosAuthApi { @@ -35,6 +37,22 @@ Task PostLoginRefresh( CancellationToken cancellationToken = default ); + [Get("/api/oauth/google/callback")] + Task GetOAuthGoogleCallback( + [Query] string code, + [Query] string state, + [Query] string codeVerifier, + CancellationToken cancellationToken = default + ); + + [Get("/api/oauth/google/links/login-or-signup")] + Task GetOAuthGoogleLoginOrSignupLink( + string redirectUri, + string codeChallenge, + string codeChallengeMethod, + CancellationToken cancellationToken = default + ); + [Headers("Authorization: Bearer")] [Get("/api/oauth/patreon/redirect")] Task GetPatreonOAuthRedirect( diff --git a/StabilityMatrix.Core/Extensions/UriExtensions.cs b/StabilityMatrix.Core/Extensions/UriExtensions.cs index 396f0148c..4ee48d7aa 100644 --- a/StabilityMatrix.Core/Extensions/UriExtensions.cs +++ b/StabilityMatrix.Core/Extensions/UriExtensions.cs @@ -1,7 +1,9 @@ -using System.Web; +using System.ComponentModel; +using System.Web; namespace StabilityMatrix.Core.Extensions; +[Localizable(false)] public static class UriExtensions { public static Uri WithQuery(this Uri uri, string key, string value) @@ -22,4 +24,26 @@ public static Uri Append(this Uri uri, params string[] paths) ) ); } + + /// + /// Returns a new Uri with the query values redacted. + /// Non-empty query values are replaced with a single asterisk. + /// + public static Uri RedactQueryValues(this Uri uri) + { + var builder = new UriBuilder(uri); + + var queryCollection = HttpUtility.ParseQueryString(builder.Query); + + foreach (var key in queryCollection.AllKeys) + { + if (!string.IsNullOrEmpty(queryCollection[key])) + { + queryCollection[key] = "*"; + } + } + + builder.Query = queryCollection.ToString() ?? string.Empty; + return builder.Uri; + } } diff --git a/StabilityMatrix.Core/Models/Api/Lykos/GoogleOAuthResponse.cs b/StabilityMatrix.Core/Models/Api/Lykos/GoogleOAuthResponse.cs new file mode 100644 index 000000000..201313ecf --- /dev/null +++ b/StabilityMatrix.Core/Models/Api/Lykos/GoogleOAuthResponse.cs @@ -0,0 +1,27 @@ +using System.Web; + +namespace StabilityMatrix.Core.Models.Api.Lykos; + +public class GoogleOAuthResponse +{ + public string? Code { get; init; } + + public string? State { get; init; } + + public string? Nonce { get; init; } + + public string? Error { get; init; } + + public static GoogleOAuthResponse ParseFromQueryString(string query) + { + var queryCollection = HttpUtility.ParseQueryString(query); + + return new GoogleOAuthResponse + { + Code = queryCollection.Get("code"), + State = queryCollection.Get("state"), + Nonce = queryCollection.Get("nonce"), + Error = queryCollection.Get("error") + }; + } +} From 67c80c6d87124ad2ffc4449eda02f95230a77663 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 13:33:47 -0400 Subject: [PATCH 202/325] Improved challenge rng and check state --- .../Dialogs/OAuthGoogleLoginViewModel.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs index 539a7bfca..087137c8d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs @@ -32,6 +32,7 @@ IAccountsService accountsService { private string? challenge; private string? verifier; + private string? state; // ReSharper disable once LocalizableElement public override string ServiceName { get; set; } = "Google"; @@ -55,11 +56,18 @@ protected override async Task OnCallbackUriMatchedAsync(Uri uri) if (string.IsNullOrEmpty(response.Code) || string.IsNullOrEmpty(response.State)) { - logger.LogWarning("Invalid response: {Response}", response); + logger.LogWarning("Response missing code or state: {Uri}", uri.RedactQueryValues()); OnLoginFailed([("Invalid Response", "code and state are required")]); return; } + if (response.State != state) + { + logger.LogWarning("Response state mismatch: {Uri}", uri.RedactQueryValues()); + OnLoginFailed([("Invalid Response", "state mismatch")]); + return; + } + await accountsService.LykosLoginViaGoogleOAuthAsync(response.Code, response.State, verifier); // Success @@ -122,6 +130,10 @@ private async Task GenerateUrlAsync() codeChallengeMethod: "S256" ); + var queryCollection = HttpUtility.ParseQueryString(link.Query); + // ReSharper disable once LocalizableElement + state = queryCollection.Get("state"); + Url = link.ToString(); logger.LogInformation("Generated Google OAuth URL: {Url}", Url); @@ -129,7 +141,8 @@ private async Task GenerateUrlAsync() private static (string Challenge, string Verifier) GeneratePkceSha256ChallengePair() { - var verifier = Guid.NewGuid().ToString("N"); + var verifier = RandomNumberGenerator.GetHexString(128, true); + var hash = SHA256.HashData(Encoding.ASCII.GetBytes(verifier)); // Convert to base64url From 936ca1dcf3970b479803a43aa0b84e00abb623ea Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 13:34:39 -0400 Subject: [PATCH 203/325] Fix missing return for exception --- .../ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs index 087137c8d..1015fe2c1 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs @@ -106,6 +106,8 @@ public override async Task OnLoadedAsync() logger.LogError(e, "Failed to generate url"); OnLoginFailed([(e.GetType().Name, e.Message)]); + + return; } finally { From 14638bc06a4c8bfca5fa01157fed451f04d1a097 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 13:46:12 -0400 Subject: [PATCH 204/325] Add config settable base url for debug builds --- StabilityMatrix.Avalonia/App.axaml.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index 73709137d..ee7240d20 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -101,7 +101,13 @@ public sealed class App : Application [NotNull] public static IConfiguration? Config { get; private set; } +#if DEBUG + // ReSharper disable twice LocalizableElement + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + public static string LykosAuthApiBaseUrl => Config?["LykosAuthApiBaseUrl"] ?? "https://auth.lykos.ai"; +#else public const string LykosAuthApiBaseUrl = "https://auth.lykos.ai"; +#endif // ReSharper disable once MemberCanBePrivate.Global public IClassicDesktopStyleApplicationLifetime? DesktopLifetime => From 5b00c9d840323414ab76bd0a7b733f69f7832aff Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 14:18:44 -0400 Subject: [PATCH 205/325] Move log to not print url --- StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs index 1ebb86528..26e948dd7 100644 --- a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs +++ b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs @@ -50,10 +50,11 @@ public async ValueTask DisposeAsync() private void UriReceivedHandler(Uri receivedUri) { - logger.LogDebug("ModelDownloadLinkHandler Received URI: {Uri}", receivedUri.PathAndQuery); if (!receivedUri.Host.Equals(DownloadCivitModel, StringComparison.OrdinalIgnoreCase)) return; + logger.LogDebug("ModelDownloadLinkHandler Received URI: {Uri}", receivedUri.PathAndQuery); + var queryDict = HttpUtility.ParseQueryString(receivedUri.Query); var modelIdStr = queryDict["modelId"]; var modelVersionIdStr = queryDict["modelVersionId"]; From bd395ffd429e4bd5b2ff57e252242d6c42567825 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 14:38:04 -0400 Subject: [PATCH 206/325] Bring app to front on uri also --- .../ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs index 1015fe2c1..7635c2153 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using System.Web; +using Avalonia.Controls; using DeviceId.Encoders; using MessagePipe; using Microsoft.Extensions.Logging; @@ -46,6 +47,9 @@ protected override async Task OnCallbackUriMatchedAsync(Uri uri) try { + // Bring the app to the front + (App.TopLevel as Window)?.Activate(); + if (string.IsNullOrEmpty(verifier)) { // ReSharper disable once LocalizableElement From 5d2850869431bddfc4e667f545665e111897e850 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 23:37:51 -0400 Subject: [PATCH 207/325] chagenlog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a109906e8..e8198d300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Show NSFW Images" toggle to the Checkpoints page - Added "Model Loader" option to Inference, for loading UNet/GGUF/NF4 models (e.g. Flux) - Added type-to-search for the Inference model selectors. Start typing while the dropdown is open to navigate the list. +- Added "Sign in with Google" option for connecting your Lykos Account on the Account Settings page ### Changed - Merged the "Flux Text to Image" workflow back into the main Text to Image workflow ### Fixed From 460426589820df3ae35cde4bf9989d6a011098f9 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 19 Aug 2024 23:43:00 -0400 Subject: [PATCH 208/325] Show error if callback has it --- .../ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs index 7635c2153..b33f179fa 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OAuthGoogleLoginViewModel.cs @@ -58,6 +58,13 @@ protected override async Task OnCallbackUriMatchedAsync(Uri uri) var response = GoogleOAuthResponse.ParseFromQueryString(uri.Query); + if (!string.IsNullOrEmpty(response.Error)) + { + logger.LogWarning("Response has error: {Error}", response.Error); + OnLoginFailed([("Error", response.Error)]); + return; + } + if (string.IsNullOrEmpty(response.Code) || string.IsNullOrEmpty(response.State)) { logger.LogWarning("Response missing code or state: {Uri}", uri.RedactQueryValues()); From 279b65f6db0f2d8bf4337c864cd7b14eb8d2824c Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 19 Aug 2024 23:09:00 -0700 Subject: [PATCH 209/325] chagenlog chagenlog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b0867709..269e084e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Model Loader" option to Inference, for loading UNet/GGUF/NF4 models (e.g. Flux) - Added type-to-search for the Inference model selectors. Start typing while the dropdown is open to navigate the list. - Added "Sign in with Google" option for connecting your Lykos Account on the Account Settings page +- Added unet folder links for ComfyUI thanks to jeremydk ### Changed +- Updated Brazilian Portuguese translations thanks to thiagojramos - Merged the "Flux Text to Image" workflow back into the main Text to Image workflow ### Fixed - Fixed CivitAI Model Browser sometimes incorrectly showing "No models found" before toggling "Show NSFW" or "Hide Installed" filters @@ -101,6 +103,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.11.8 ### Added - Added Flux & AuraFlow types to CivitAI Browser +- Added unet folder links for ComfyUI thanks to jeremydk ### Changed - Updated Brazilian Portuguese translations thanks to thiagojramos ### Fixed @@ -108,6 +111,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed SwarmUI settings being overwritten on launch - Fixed Forge output folder links pointing to the incorrect folder - Fixed errors when downloading models with invalid characters in the file name +### Supporters +#### Pioneers +- A big shoutout to our Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, and **Szir777**! We deeply appreciate your ongoing support! ## v2.11.7 ### Changed From cacff8d69ce093600d4544998415c5130d9ad8dc Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 19 Aug 2024 23:10:15 -0700 Subject: [PATCH 210/325] less chagenlog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 269e084e4..06271c43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added "Model Loader" option to Inference, for loading UNet/GGUF/NF4 models (e.g. Flux) - Added type-to-search for the Inference model selectors. Start typing while the dropdown is open to navigate the list. - Added "Sign in with Google" option for connecting your Lykos Account on the Account Settings page -- Added unet folder links for ComfyUI thanks to jeremydk ### Changed - Updated Brazilian Portuguese translations thanks to thiagojramos - Merged the "Flux Text to Image" workflow back into the main Text to Image workflow From 7c0c0c21dbcc41752c58d68c0f9d08765e116598 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 13:46:30 -0400 Subject: [PATCH 211/325] Add IDownloadableResource, refactors --- .../Dialogs/DownloadResourceViewModel.cs | 4 +-- StabilityMatrix.Core/Helper/RemoteModels.cs | 8 +++--- .../Models/Api/Comfy/ComfyUpscaler.cs | 2 +- .../Models/HybridModelFile.cs | 4 +-- .../Models/IDownloadableResource.cs | 25 +++++++++++++++++++ StabilityMatrix.Core/Models/RemoteResource.cs | 15 +++++++++-- 6 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 StabilityMatrix.Core/Models/IDownloadableResource.cs diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs index c2d507d41..2283b9d75 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs @@ -75,9 +75,9 @@ Resource.ContextType as SharedFolderType? sharedFolderType.GetStringValue() ); - if (Resource.RelativePath is not null) + if (Resource.RelativeDirectory is not null) { - modelsDir = modelsDir.JoinDir(Resource.RelativePath); + modelsDir = modelsDir.JoinDir(Resource.RelativeDirectory); } var download = trackedDownloadService.NewDownload( diff --git a/StabilityMatrix.Core/Helper/RemoteModels.cs b/StabilityMatrix.Core/Helper/RemoteModels.cs index 197249830..b932f368f 100644 --- a/StabilityMatrix.Core/Helper/RemoteModels.cs +++ b/StabilityMatrix.Core/Helper/RemoteModels.cs @@ -208,7 +208,7 @@ private static RemoteResource ControlNetCommon(string path, string sha256) "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" ), ContextType = SharedFolderType.Ultralytics, - RelativePath = "bbox" + RelativeDirectory = "bbox" }, new RemoteResource { @@ -221,7 +221,7 @@ private static RemoteResource ControlNetCommon(string path, string sha256) "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" ), ContextType = SharedFolderType.Ultralytics, - RelativePath = "bbox" + RelativeDirectory = "bbox" }, new RemoteResource { @@ -234,7 +234,7 @@ private static RemoteResource ControlNetCommon(string path, string sha256) "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" ), ContextType = SharedFolderType.Ultralytics, - RelativePath = "segm" + RelativeDirectory = "segm" }, new RemoteResource { @@ -247,7 +247,7 @@ private static RemoteResource ControlNetCommon(string path, string sha256) "https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md" ), ContextType = SharedFolderType.Ultralytics, - RelativePath = "segm" + RelativeDirectory = "segm" } ]; diff --git a/StabilityMatrix.Core/Models/Api/Comfy/ComfyUpscaler.cs b/StabilityMatrix.Core/Models/Api/Comfy/ComfyUpscaler.cs index 411b1474a..073700f02 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/ComfyUpscaler.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/ComfyUpscaler.cs @@ -6,7 +6,7 @@ namespace StabilityMatrix.Core.Models.Api.Comfy; -public readonly record struct ComfyUpscaler(string Name, ComfyUpscalerType Type) +public readonly record struct ComfyUpscaler(string Name, ComfyUpscalerType Type) : IDownloadableResource { public static ComfyUpscaler NearestExact { get; } = new("nearest-exact", ComfyUpscalerType.Latent); diff --git a/StabilityMatrix.Core/Models/HybridModelFile.cs b/StabilityMatrix.Core/Models/HybridModelFile.cs index fbbc03233..7491eef38 100644 --- a/StabilityMatrix.Core/Models/HybridModelFile.cs +++ b/StabilityMatrix.Core/Models/HybridModelFile.cs @@ -47,10 +47,10 @@ public record HybridModelFile : ISearchText HybridModelType.Local => Local!.RelativePathFromSharedFolder, HybridModelType.Remote => RemoteName!, HybridModelType.Downloadable - => DownloadableResource!.Value.RelativePath == null + => DownloadableResource!.Value.RelativeDirectory == null ? DownloadableResource!.Value.FileName : Path.Combine( - DownloadableResource!.Value.RelativePath, + DownloadableResource!.Value.RelativeDirectory, DownloadableResource!.Value.FileName ), HybridModelType.None => throw new InvalidOperationException(), diff --git a/StabilityMatrix.Core/Models/IDownloadableResource.cs b/StabilityMatrix.Core/Models/IDownloadableResource.cs new file mode 100644 index 000000000..cace5d632 --- /dev/null +++ b/StabilityMatrix.Core/Models/IDownloadableResource.cs @@ -0,0 +1,25 @@ +using System.Diagnostics.CodeAnalysis; + +namespace StabilityMatrix.Core.Models; + +/// +/// Interface for items that may have a downloadable resource. +/// +public interface IDownloadableResource +{ + /// + /// Downloadable resource information. + /// + RemoteResource? DownloadableResource { get; } + + [MemberNotNullWhen(true, nameof(DownloadableResource))] + bool IsDownloadable => DownloadableResource is not null; + + string DownloadFileName => + DownloadableResource?.Value.RelativePath == null + ? DownloadableResource!.Value.FileName + : Path.Combine( + DownloadableResource!.Value.RelativeDirectory, + DownloadableResource!.Value.FileName + ); +} diff --git a/StabilityMatrix.Core/Models/RemoteResource.cs b/StabilityMatrix.Core/Models/RemoteResource.cs index e855110e0..8f1c78514 100644 --- a/StabilityMatrix.Core/Models/RemoteResource.cs +++ b/StabilityMatrix.Core/Models/RemoteResource.cs @@ -13,6 +13,19 @@ public readonly record struct RemoteResource public string FileName => FileNameOverride ?? Path.GetFileName(Url.ToString()); + /// + /// Optional relative subdirectory to download the file to. + /// + public string? RelativeDirectory { get; init; } + + /// + /// Relative path to download the file to. + /// This is combined with if is not null. + /// Otherwise, it is just . + /// + public string RelativePath => + !string.IsNullOrEmpty(RelativeDirectory) ? Path.Combine(RelativeDirectory, FileName) : FileName; + public string? HashSha256 { get; init; } /// @@ -37,6 +50,4 @@ public readonly record struct RemoteResource /// Optional relative path to extract the archive to, if AutoExtractArchive is true /// public string? ExtractRelativePath { get; init; } - - public string? RelativePath { get; init; } } From 7125810b6eb4f8de3d75ac4c7a22b291c59a2d35 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 13:58:15 -0400 Subject: [PATCH 212/325] Add BetterDownloadableComboBox --- .../Controls/BetterDownloadableComboBox.cs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs diff --git a/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs new file mode 100644 index 000000000..8c7139e2e --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs @@ -0,0 +1,66 @@ +using System.Threading.Tasks; +using AsyncAwaitBestPractices; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.Input; +using FluentAvalonia.UI.Controls; +using Microsoft.Extensions.DependencyInjection; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Dialogs; +using StabilityMatrix.Core.Models; + +namespace StabilityMatrix.Avalonia.Controls; + +public partial class BetterDownloadableComboBox : BetterComboBox +{ + static BetterDownloadableComboBox() + { + SelectionChangedEvent.AddClassHandler( + (comboBox, args) => comboBox.OnSelectionChanged(args) + ); + } + + public BetterDownloadableComboBox() { } + + protected virtual void OnSelectionChanged(SelectionChangedEventArgs e) + { + // On downloadable added + if (e.AddedItems.Count > 0 && e.AddedItems[0] is IDownloadableResource { IsDownloadable: true } item) + { + // Reset the selection + e.Handled = true; + + if ( + e.RemovedItems.Count > 0 + && e.RemovedItems[0] is IDownloadableResource { IsDownloadable: false } removedItem + ) + { + SelectedItem = removedItem; + } + else + { + SelectedItem = null; + } + + // Show dialog to download the model + PromptDownloadCommand.ExecuteAsync(item).SafeFireAndForget(); + } + } + + [RelayCommand] + private static async Task PromptDownloadAsync(IDownloadableResource downloadable) + { + if (downloadable.DownloadableResource is not { } resource) + return; + + var vmFactory = App.Services.GetRequiredService>(); + var confirmDialog = vmFactory.Get(); + confirmDialog.Resource = resource; + confirmDialog.FileName = resource.FileName; + + if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) + { + confirmDialog.StartDownload(); + } + } +} From 8d38d71bfcc2945ba21406a00e74631134622cf8 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 13:58:33 -0400 Subject: [PATCH 213/325] Add IDownloadableResource for HybridModelFile --- StabilityMatrix.Core/Models/HybridModelFile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/HybridModelFile.cs b/StabilityMatrix.Core/Models/HybridModelFile.cs index 7491eef38..f17432e2d 100644 --- a/StabilityMatrix.Core/Models/HybridModelFile.cs +++ b/StabilityMatrix.Core/Models/HybridModelFile.cs @@ -10,7 +10,7 @@ namespace StabilityMatrix.Core.Models; /// Model file union that may be remote or local. /// [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] -public record HybridModelFile : ISearchText +public record HybridModelFile : ISearchText, IDownloadableResource { /// /// Singleton instance of that represents use of a default model. From 820483bdecbe78b3fc4ed913b2a2f4007277d794 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 13:58:39 -0400 Subject: [PATCH 214/325] Remove unused --- StabilityMatrix.Core/Models/IDownloadableResource.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/StabilityMatrix.Core/Models/IDownloadableResource.cs b/StabilityMatrix.Core/Models/IDownloadableResource.cs index cace5d632..cebbedf13 100644 --- a/StabilityMatrix.Core/Models/IDownloadableResource.cs +++ b/StabilityMatrix.Core/Models/IDownloadableResource.cs @@ -14,12 +14,4 @@ public interface IDownloadableResource [MemberNotNullWhen(true, nameof(DownloadableResource))] bool IsDownloadable => DownloadableResource is not null; - - string DownloadFileName => - DownloadableResource?.Value.RelativePath == null - ? DownloadableResource!.Value.FileName - : Path.Combine( - DownloadableResource!.Value.RelativeDirectory, - DownloadableResource!.Value.FileName - ); } From df66e2a4f516304de76614507fbabb1f4d869875 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 13:59:30 -0400 Subject: [PATCH 215/325] Remove empty ctor --- StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs index 8c7139e2e..229274b2f 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs @@ -20,8 +20,6 @@ static BetterDownloadableComboBox() ); } - public BetterDownloadableComboBox() { } - protected virtual void OnSelectionChanged(SelectionChangedEventArgs e) { // On downloadable added From 1253ec903f8b566a25b5250be5d3dadc554f42f4 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:00:05 -0400 Subject: [PATCH 216/325] Use BetterDownloadableComboBox in ModelCard --- StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml index 520a34ee8..e8e2e30a6 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml @@ -238,7 +238,7 @@ Text="CLIP 1" TextAlignment="Left" /> - - Date: Tue, 20 Aug 2024 14:06:51 -0400 Subject: [PATCH 217/325] Add FADownloadableComboBox --- .../Controls/FADownloadableComboBox.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs diff --git a/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs new file mode 100644 index 000000000..532b0c51f --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; +using AsyncAwaitBestPractices; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.Input; +using FluentAvalonia.UI.Controls; +using Microsoft.Extensions.DependencyInjection; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Dialogs; +using StabilityMatrix.Core.Models; + +namespace StabilityMatrix.Avalonia.Controls; + +// ReSharper disable once InconsistentNaming +public partial class FADownloadableComboBox : FAComboBox +{ + static FADownloadableComboBox() + { + SelectionChangedEvent.AddClassHandler( + (comboBox, args) => comboBox.OnSelectionChanged(args) + ); + } + + protected virtual void OnSelectionChanged(SelectionChangedEventArgs e) + { + // On downloadable added + if (e.AddedItems.Count > 0 && e.AddedItems[0] is IDownloadableResource { IsDownloadable: true } item) + { + // Reset the selection + e.Handled = true; + + if ( + e.RemovedItems.Count > 0 + && e.RemovedItems[0] is IDownloadableResource { IsDownloadable: false } removedItem + ) + { + SelectedItem = removedItem; + } + else + { + SelectedItem = null; + } + + // Show dialog to download the model + PromptDownloadCommand.ExecuteAsync(item).SafeFireAndForget(); + } + } + + [RelayCommand] + private static async Task PromptDownloadAsync(IDownloadableResource downloadable) + { + if (downloadable.DownloadableResource is not { } resource) + return; + + var vmFactory = App.Services.GetRequiredService>(); + var confirmDialog = vmFactory.Get(); + confirmDialog.Resource = resource; + confirmDialog.FileName = resource.FileName; + + if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) + { + confirmDialog.StartDownload(); + } + } +} From 1baa657da04c090e80fa7aa72d516c1e810da2d4 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:09:56 -0400 Subject: [PATCH 218/325] Add style key overrides --- .../Controls/BetterDownloadableComboBox.cs | 5 ++++- StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs index 229274b2f..5ce8c8ffa 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterDownloadableComboBox.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls; using CommunityToolkit.Mvvm.Input; @@ -13,6 +14,8 @@ namespace StabilityMatrix.Avalonia.Controls; public partial class BetterDownloadableComboBox : BetterComboBox { + protected override Type StyleKeyOverride => typeof(BetterComboBox); + static BetterDownloadableComboBox() { SelectionChangedEvent.AddClassHandler( diff --git a/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs index 532b0c51f..fd56d1b1d 100644 --- a/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs +++ b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls; using CommunityToolkit.Mvvm.Input; @@ -14,6 +15,8 @@ namespace StabilityMatrix.Avalonia.Controls; // ReSharper disable once InconsistentNaming public partial class FADownloadableComboBox : FAComboBox { + protected override Type StyleKeyOverride => typeof(FADownloadableComboBox); + static FADownloadableComboBox() { SelectionChangedEvent.AddClassHandler( From 96c38c9ae15bf69c73b08920dff6c9a97c63daea Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:11:15 -0400 Subject: [PATCH 219/325] Fix style key override --- StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs index fd56d1b1d..3294afe71 100644 --- a/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs +++ b/StabilityMatrix.Avalonia/Controls/FADownloadableComboBox.cs @@ -15,7 +15,7 @@ namespace StabilityMatrix.Avalonia.Controls; // ReSharper disable once InconsistentNaming public partial class FADownloadableComboBox : FAComboBox { - protected override Type StyleKeyOverride => typeof(FADownloadableComboBox); + protected override Type StyleKeyOverride => typeof(FAComboBox); static FADownloadableComboBox() { From b6dd3d7fadeb76d40739f76ccce7596a71b2ba82 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:12:13 -0400 Subject: [PATCH 220/325] Use FADownloadableComboBox in PromptExpansion --- .../Inference/PromptExpansionCard.axaml | 10 +--- .../Inference/PromptExpansionCard.axaml.cs | 49 +------------------ .../Inference/PromptExpansionCardViewModel.cs | 28 ++--------- 3 files changed, 7 insertions(+), 80 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml index c580af176..c0d5af108 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/PromptExpansionCard.axaml @@ -39,8 +39,7 @@ Text="{x:Static lang:Resources.Label_Model}" TextAlignment="Left" /> - - - - - @@ -78,7 +72,7 @@ - + diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml.cs index 7e2e2327e..bfbb4b1d1 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml.cs @@ -1,52 +1,7 @@ -using AsyncAwaitBestPractices; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using FluentAvalonia.UI.Controls; -using StabilityMatrix.Avalonia.ViewModels.Inference; +using Avalonia.Controls.Primitives; using StabilityMatrix.Core.Attributes; -using StabilityMatrix.Core.Models.Api.Comfy; namespace StabilityMatrix.Avalonia.Controls; [Transient] -public class UpscalerCard : TemplatedControl -{ - /// - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - - var upscalerComboBox = e.NameScope.Find("UpscalerComboBox") as FAComboBox; - upscalerComboBox!.SelectionChanged += UpscalerComboBox_OnSelectionChanged; - } - - private void UpscalerComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (e.AddedItems.Count == 0) - return; - - var item = e.AddedItems[0]; - if (item is ComfyUpscaler { IsDownloadable: true }) - { - // Reset the selection - e.Handled = true; - - if ( - e.RemovedItems.Count > 0 - && e.RemovedItems[0] is ComfyUpscaler { IsDownloadable: false } removedItem - ) - { - (sender as FAComboBox)!.SelectedItem = removedItem; - } - else - { - (sender as FAComboBox)!.SelectedItem = null; - } - - // Show dialog to download the model - (DataContext as UpscalerCardViewModel)!.RemoteDownloadCommand - .ExecuteAsync(item) - .SafeFireAndForget(); - } - } -} +public class UpscalerCard : TemplatedControl; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs index 7c800883e..932992943 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs @@ -1,13 +1,9 @@ using System.Text.Json.Nodes; -using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models.Api.Comfy; @@ -43,22 +39,6 @@ ServiceManager vmFactory ClientManager = clientManager; } - [RelayCommand] - private async Task RemoteDownload(ComfyUpscaler? upscaler) - { - if (upscaler?.DownloadableResource is not { } resource) - return; - - var confirmDialog = vmFactory.Get(); - confirmDialog.Resource = resource; - confirmDialog.FileName = upscaler.Value.Name; - - if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) - { - confirmDialog.StartDownload(); - } - } - /// public override void LoadStateFromJsonObject(JsonObject state) { From e1a3635cdbec3a214664cea05c79a99182dc1479 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:16:59 -0400 Subject: [PATCH 222/325] Use FADownloadableComboBox in ControlNetCard --- .../Controls/Inference/ControlNetCard.axaml | 9 +--- .../Inference/ControlNetCard.axaml.cs | 49 +------------------ .../Inference/ControlNetCardViewModel.cs | 18 ------- 3 files changed, 4 insertions(+), 72 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml index 14e908592..0d4a363d0 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml @@ -78,8 +78,7 @@ - - - - - @@ -117,7 +112,7 @@ - + - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - - var upscalerComboBox = e.NameScope.Find("PART_ModelComboBox") as FAComboBox; - upscalerComboBox!.SelectionChanged += UpscalerComboBox_OnSelectionChanged; - } - - private void UpscalerComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (e.AddedItems.Count == 0) - return; - - var item = e.AddedItems[0]; - if (item is HybridModelFile { IsDownloadable: true }) - { - // Reset the selection - e.Handled = true; - - if ( - e.RemovedItems.Count > 0 - && e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem - ) - { - (sender as FAComboBox)!.SelectedItem = removedItem; - } - else - { - (sender as FAComboBox)!.SelectedItem = null; - } - - // Show dialog to download the model - (DataContext as ControlNetCardViewModel)!.RemoteDownloadCommand - .ExecuteAsync(item) - .SafeFireAndForget(); - } - } -} +public class ControlNetCard : TemplatedControl; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs index 65bab36ef..ae75414fb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs @@ -5,11 +5,9 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DynamicData.Binding; -using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; @@ -87,22 +85,6 @@ ServiceManager vmFactory }); } - [RelayCommand] - private async Task RemoteDownload(HybridModelFile? modelFile) - { - if (modelFile?.DownloadableResource is not { } resource) - return; - - var confirmDialog = vmFactory.Get(); - confirmDialog.Resource = resource; - confirmDialog.FileName = modelFile.FileName; - - if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) - { - confirmDialog.StartDownload(); - } - } - [RelayCommand] private async Task PreviewPreprocessor(ComfyAuxPreprocessor? preprocessor) { From 1079ad8d22e052fb2c2817a860e65582a41faa99 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:19:18 -0400 Subject: [PATCH 223/325] Use BetterDownloadableComboBox in FaceDetailerCard --- .../Controls/Inference/FaceDetailerCard.axaml | 25 ++------- .../Inference/FaceDetailerCard.axaml.cs | 53 +------------------ .../Inference/FaceDetailerViewModel.cs | 20 ------- 3 files changed, 7 insertions(+), 91 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml index 1946cacb2..98ebeabb7 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/FaceDetailerCard.axaml @@ -22,48 +22,33 @@ - - - - + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> - - - - - + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> - - - - - + Theme="{StaticResource BetterComboBoxHybridModelTheme}"/> 0 - && e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem - ) - { - (sender as BetterComboBox)!.SelectedItem = removedItem; - } - else - { - (sender as BetterComboBox)!.SelectedItem = null; - } - - // Show dialog to download the model - (DataContext as FaceDetailerViewModel)! - .RemoteDownloadCommand.ExecuteAsync(item) - .SafeFireAndForget(); - } - } -} +public class FaceDetailerCard : TemplatedControl; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs index 6aea47c0b..fae5f1932 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FaceDetailerViewModel.cs @@ -1,13 +1,9 @@ using System.Collections.ObjectModel; using System.Text.Json.Serialization; -using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy; @@ -147,20 +143,4 @@ ServiceManager vmFactory public ObservableCollection SamMaskHintUseNegatives { get; set; } = ["False", "Small", "Outter"]; public IInferenceClientManager ClientManager { get; } - - [RelayCommand] - private async Task RemoteDownload(HybridModelFile? modelFile) - { - if (modelFile?.DownloadableResource is not { } resource) - return; - - var confirmDialog = vmFactory.Get(); - confirmDialog.Resource = resource; - confirmDialog.FileName = modelFile.FileName; - - if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) - { - confirmDialog.StartDownload(); - } - } } From 6aba103aece45f835f5cba8ba402c08dd51bf014 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 14:21:15 -0400 Subject: [PATCH 224/325] Use BetterDownloadableComboBox in UnetModelCard --- .../Controls/Inference/UnetModelCard.axaml | 6 +-- .../Controls/Inference/UnetModelCard.axaml.cs | 50 +------------------ .../Inference/UnetModelCardViewModel.cs | 27 ++-------- 3 files changed, 8 insertions(+), 75 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml index 25dc61405..e8e036a68 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/UnetModelCard.axaml @@ -86,10 +86,9 @@ Text="CLIP 1" TextAlignment="Left" /> - - 0 - && e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem - ) - { - (sender as BetterComboBox)!.SelectedItem = removedItem; - } - else - { - (sender as BetterComboBox)!.SelectedItem = null; - } - - // Show dialog to download the model - (DataContext as UnetModelCardViewModel)! - .RemoteDownloadCommand.ExecuteAsync(item) - .SafeFireAndForget(); - } - } -} +public class UnetModelCard : TemplatedControl; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs index b54025494..22f280fd1 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/UnetModelCardViewModel.cs @@ -5,14 +5,11 @@ using System.Text.Json.Nodes; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; @@ -23,10 +20,10 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference; [View(typeof(UnetModelCard))] [ManagedService] [Transient] -public partial class UnetModelCardViewModel( - IInferenceClientManager clientManager, - ServiceManager vmFactory -) : LoadableViewModelBase, IParametersLoadableState, IComfyStep +public partial class UnetModelCardViewModel(IInferenceClientManager clientManager) + : LoadableViewModelBase, + IParametersLoadableState, + IComfyStep { [ObservableProperty] private HybridModelFile? selectedModel; @@ -47,22 +44,6 @@ ServiceManager vmFactory public IInferenceClientManager ClientManager { get; } = clientManager; - [RelayCommand] - private async Task RemoteDownload(HybridModelFile? modelFile) - { - if (modelFile?.DownloadableResource is not { } resource) - return; - - var confirmDialog = vmFactory.Get(); - confirmDialog.Resource = resource; - confirmDialog.FileName = modelFile.FileName; - - if (await confirmDialog.GetDialog().ShowAsync() == ContentDialogResult.Primary) - { - confirmDialog.StartDownload(); - } - } - public async Task ValidateModel() { if (SelectedModel != null) From a620d0b61c1ad7ae2350afb5fa0b359c2659a11a Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 16:17:43 -0400 Subject: [PATCH 225/325] Move InstalledPackage migration stuff to region --- .../Models/InstalledPackage.cs | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/StabilityMatrix.Core/Models/InstalledPackage.cs b/StabilityMatrix.Core/Models/InstalledPackage.cs index c9eb29132..ffab033df 100644 --- a/StabilityMatrix.Core/Models/InstalledPackage.cs +++ b/StabilityMatrix.Core/Models/InstalledPackage.cs @@ -18,14 +18,6 @@ public class InstalledPackage : IJsonOnDeserialized public string? PackageName { get; set; } // Package version - [Obsolete("Use Version instead. (Kept for migration)")] - public string? PackageVersion { get; set; } - - [Obsolete("Use Version instead. (Kept for migration)")] - public string? InstalledBranch { get; set; } - - [Obsolete("Use Version instead. (Kept for migration)")] - public string? DisplayVersion { get; set; } public InstalledPackageVersion? Version { get; set; } // Old type absolute path @@ -105,6 +97,39 @@ public class InstalledPackage : IJsonOnDeserialized return isSubPath ? relativePath : null; } + public static IEqualityComparer Comparer { get; } = + new PropertyComparer(p => p.Id); + + protected bool Equals(InstalledPackage other) + { + return Id.Equals(other.Id); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == this.GetType() && Equals((InstalledPackage)obj); + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + #region Migration / Obsolete + + [Obsolete("Use Version instead. (Kept for migration)")] + public string? PackageVersion { get; set; } + + [Obsolete("Use Version instead. (Kept for migration)")] + public string? InstalledBranch { get; set; } + + [Obsolete("Use Version instead. (Kept for migration)")] + public string? DisplayVersion { get; set; } + /// /// Migrates the old Path to the new LibraryPath. /// If libraryDirectory is null, GlobalConfig.LibraryDir is used. @@ -210,35 +235,13 @@ public async Task MigratePath(string? libraryDirectory = null) LibraryPath = System.IO.Path.Combine("Packages", packageFolderName); } - public static IEqualityComparer Comparer { get; } = - new PropertyComparer(p => p.Id); - - protected bool Equals(InstalledPackage other) - { - return Id.Equals(other.Id); - } - - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - return obj.GetType() == this.GetType() && Equals((InstalledPackage)obj); - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } - -#pragma warning disable CS0618 // Type or member is obsolete public void OnDeserialized() { // Handle version migration if (Version != null) return; +#pragma warning disable CS0618 // Type or member is obsolete if (string.IsNullOrWhiteSpace(InstalledBranch) && !string.IsNullOrWhiteSpace(PackageVersion)) { // release mode @@ -257,6 +260,8 @@ public void OnDeserialized() IsPrerelease = false }; } - } #pragma warning restore CS0618 // Type or member is obsolete + } + + #endregion } From 9d79fd0728caac3ede07e40ea9c940a71011b909 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 20 Aug 2024 16:20:00 -0400 Subject: [PATCH 226/325] Move more migration properties --- StabilityMatrix.Core/Models/InstalledPackage.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/StabilityMatrix.Core/Models/InstalledPackage.cs b/StabilityMatrix.Core/Models/InstalledPackage.cs index ffab033df..ca8e232a0 100644 --- a/StabilityMatrix.Core/Models/InstalledPackage.cs +++ b/StabilityMatrix.Core/Models/InstalledPackage.cs @@ -20,10 +20,6 @@ public class InstalledPackage : IJsonOnDeserialized // Package version public InstalledPackageVersion? Version { get; set; } - // Old type absolute path - [Obsolete("Use LibraryPath instead. (Kept for migration)")] - public string? Path { get; set; } - /// /// Relative path from the library root. /// @@ -121,6 +117,11 @@ public override int GetHashCode() #region Migration / Obsolete + // Old type absolute path + [Obsolete("Use LibraryPath instead. (Kept for migration)")] + public string? Path { get; set; } + + // Old type versions [Obsolete("Use Version instead. (Kept for migration)")] public string? PackageVersion { get; set; } From 2519ab416f93b522afb14063d052b1b5cba531e4 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 20 Aug 2024 18:48:48 -0700 Subject: [PATCH 227/325] Fix RuinedFooocus requirements parsing & add CLIP link for forge/a1111 --- CHANGELOG.md | 6 ++++-- StabilityMatrix.Core/Models/Packages/A3WebUI.cs | 3 ++- StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs | 7 ++----- StabilityMatrix.Core/Python/PipInstallArgs.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db424716a..de54570af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,15 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ### Added - Added Flux & AuraFlow types to CivitAI Browser - Added unet folder links for ComfyUI thanks to jeremydk +- Added CLIP folder links for Forge ### Changed - Updated Brazilian Portuguese translations thanks to thiagojramos ### Fixed -- Fixed CivitAI model browser not loading search results +- Fixed [#840](https://github.com/LykosAI/StabilityMatrix/issues/840) - CivitAI model browser not loading search results - Fixed SwarmUI settings being overwritten on launch -- Fixed Forge output folder links pointing to the incorrect folder +- Fixed [#832](https://github.com/LykosAI/StabilityMatrix/issues/832) [#847](https://github.com/LykosAI/StabilityMatrix/issues/847) - Forge output folder links pointing to the incorrect folder - Fixed errors when downloading models with invalid characters in the file name +- Fixed error when installing RuinedFooocus on nvidia GPUs ### Supporters #### Pioneers - A big shoutout to our Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, and **Szir777**! We deeply appreciate your ongoing support! diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 6e1a83a23..6c24b0818 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -67,7 +67,8 @@ IPrerequisiteHelper prerequisiteHelper [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" }, [SharedFolderType.InvokeIpAdapters15] = new[] { "models/controlnet/DiffusersIpAdapters" }, [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/controlnet/DiffusersIpAdaptersXL" }, - [SharedFolderType.SVD] = new[] { "models/svd" } + [SharedFolderType.SVD] = new[] { "models/svd" }, + [SharedFolderType.CLIP] = new[] { "models/text_encoder" } }; public override Dictionary>? SharedOutputFolders => diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index f6def17b4..3b3e0d0bb 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -125,14 +125,11 @@ public override async Task InstallPackage( await venvRunner .PipInstall( new PipInstallArgs() - .WithTorch("==2.1.2") - .WithTorchVision("==0.16.2") - .WithXFormers("==0.0.23.post1") - .WithTorchExtraIndex("cu121") .WithParsedFromRequirementsTxt( await requirements.ReadAllTextAsync().ConfigureAwait(false), excludePattern: "torch" - ), + ) + .WithTorchExtraIndex("cu121"), onConsoleOutput ) .ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Python/PipInstallArgs.cs b/StabilityMatrix.Core/Python/PipInstallArgs.cs index 6f2d22151..086c029b4 100644 --- a/StabilityMatrix.Core/Python/PipInstallArgs.cs +++ b/StabilityMatrix.Core/Python/PipInstallArgs.cs @@ -33,7 +33,7 @@ public PipInstallArgs WithParsedFromRequirementsTxt( { var requirementsEntries = requirements .SplitLines(StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) - .Where(s => !s.StartsWith('#')) + .Where(s => !s.StartsWith('#') && !s.StartsWith("--")) .Select(s => s.Contains('#') ? s.Substring(0, s.IndexOf('#')) : s) .Where(s => !string.IsNullOrWhiteSpace(s)); From 4cdc506454a4fb1579e8162fce22e9374663adcb Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 20 Aug 2024 18:58:08 -0700 Subject: [PATCH 228/325] yolo --- StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs | 9 +++------ StabilityMatrix.Core/Python/PipInstallArgs.cs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index 3b3e0d0bb..086b4e41d 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -124,12 +124,9 @@ public override async Task InstallPackage( await venvRunner .PipInstall( - new PipInstallArgs() - .WithParsedFromRequirementsTxt( - await requirements.ReadAllTextAsync().ConfigureAwait(false), - excludePattern: "torch" - ) - .WithTorchExtraIndex("cu121"), + new PipInstallArgs().WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false) + ), onConsoleOutput ) .ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Python/PipInstallArgs.cs b/StabilityMatrix.Core/Python/PipInstallArgs.cs index 086c029b4..6f2d22151 100644 --- a/StabilityMatrix.Core/Python/PipInstallArgs.cs +++ b/StabilityMatrix.Core/Python/PipInstallArgs.cs @@ -33,7 +33,7 @@ public PipInstallArgs WithParsedFromRequirementsTxt( { var requirementsEntries = requirements .SplitLines(StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) - .Where(s => !s.StartsWith('#') && !s.StartsWith("--")) + .Where(s => !s.StartsWith('#')) .Select(s => s.Contains('#') ? s.Substring(0, s.IndexOf('#')) : s) .Where(s => !string.IsNullOrWhiteSpace(s)); From a9398889afc7a6a47248bafc0b4ebfc344ee790a Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 23 Aug 2024 15:01:19 -0400 Subject: [PATCH 229/325] Fix civit scroll load model order --- CHANGELOG.md | 4 ++++ .../ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db2280bca..3914ebbe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.12.0-pre.3 +### Fixed +- Fixed CivitAI Browser page scroll refresh not ordering models correctly + ## v2.12.0-pre.2 ### Added - Added "Show NSFW Images" toggle to the Checkpoints page diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index b55cb9715..243704aa2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -357,7 +357,9 @@ private void UpdateModelCards(List? models, bool addCards = false) return; } - var modelsToAdd = models.Select((m, i) => new OrderedValue(i, m)); + var startIndex = modelCache.Count; + + var modelsToAdd = models.Select((m, i) => new OrderedValue(startIndex + i, m)); if (addCards) { From e139c86a2eca3e1adbd2ff8d63f1925c8d94671b Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 25 Aug 2024 10:12:05 -0700 Subject: [PATCH 230/325] Add UI for overriding pip package installs during package installs --- StabilityMatrix.Avalonia/App.axaml.cs | 9 ++ .../DesignData/DesignData.cs | 4 +- .../Dialogs/NewOneClickInstallViewModel.cs | 4 +- .../Dialogs/OneClickInstallViewModel.cs | 4 +- .../Dialogs/PackageImportViewModel.cs | 2 +- .../PackageInstallDetailViewModel.cs | 43 ++++- .../Views/Dialogs/OneClickInstallDialog.axaml | 4 +- .../PackageInstallBrowserView.axaml | 4 +- .../PackageInstallDetailView.axaml | 149 ++++++++++++++---- StabilityMatrix.Core/Api/IPyPiApi.cs | 11 ++ .../Database/ILiteDbContext.cs | 3 + .../Database/LiteDbContext.cs | 13 ++ .../Helper/Cache/IPyPiCache.cs | 8 + .../Helper/Cache/PyPiCache.cs | 54 +++++++ StabilityMatrix.Core/Helper/FileTransfers.cs | 25 +-- .../Models/Api/Pypi/PyPiReleaseFile.cs | 3 + .../Models/Api/Pypi/PyPiResponse.cs | 6 + StabilityMatrix.Core/Models/CustomVersion.cs | 73 +++++++++ .../Models/Database/PyPiCacheEntry.cs | 11 ++ .../Models/InstalledPackage.cs | 7 +- .../Models/Packages/A3WebUI.cs | 30 ++-- .../Models/Packages/BasePackage.cs | 36 ++--- .../Models/Packages/ComfyUI.cs | 27 ++-- .../Models/Packages/DankDiffusion.cs | 2 +- .../Models/Packages/Fooocus.cs | 28 ++-- .../Models/Packages/FooocusMre.cs | 52 +++--- .../Models/Packages/InvokeAI.cs | 73 ++++----- .../Models/Packages/KohyaSs.cs | 12 +- .../Models/Packages/OneTrainer.cs | 20 ++- .../Packages/Options/InstallPackageOptions.cs | 2 + .../Packages/Options/PythonPackageOptions.cs | 6 +- .../Packages/Options/UpdatePackageOptions.cs | 7 +- .../Models/Packages/RuinedFooocus.cs | 24 +-- .../Models/Packages/SDWebForge.cs | 28 ++-- StabilityMatrix.Core/Models/Packages/Sdfx.cs | 23 ++- .../Packages/StableDiffusionDirectMl.cs | 46 +++--- .../Models/Packages/StableDiffusionUx.cs | 59 +++---- .../Models/Packages/StableSwarm.cs | 118 +++++++------- .../Models/Packages/UnknownPackage.cs | 4 +- .../Models/Packages/VladAutomatic.cs | 33 ++-- .../Models/Packages/VoltaML.cs | 14 +- .../Models/{TorchVersion.cs => TorchIndex.cs} | 2 +- .../Processes/ProcessArgsBuilder.cs | 35 +++- StabilityMatrix.Core/Python/PipInstallArgs.cs | 27 ++++ .../Python/PipPackageSpecifier.cs | 8 +- 45 files changed, 775 insertions(+), 378 deletions(-) create mode 100644 StabilityMatrix.Core/Api/IPyPiApi.cs create mode 100644 StabilityMatrix.Core/Helper/Cache/IPyPiCache.cs create mode 100644 StabilityMatrix.Core/Helper/Cache/PyPiCache.cs create mode 100644 StabilityMatrix.Core/Models/Api/Pypi/PyPiReleaseFile.cs create mode 100644 StabilityMatrix.Core/Models/Api/Pypi/PyPiResponse.cs create mode 100644 StabilityMatrix.Core/Models/CustomVersion.cs create mode 100644 StabilityMatrix.Core/Models/Database/PyPiCacheEntry.cs rename StabilityMatrix.Core/Models/{TorchVersion.cs => TorchIndex.cs} (83%) diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index ee7240d20..be722b505 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -686,6 +686,15 @@ internal static IServiceCollection ConfigureServices() }) .AddPolicyHandler(retryPolicyLonger); + services + .AddRefitClient(defaultRefitSettings) + .ConfigureHttpClient(c => + { + c.BaseAddress = new Uri("https://pypi.org"); + c.Timeout = TimeSpan.FromHours(1); + }) + .AddPolicyHandler(retryPolicyLonger); + services .AddRefitClient(defaultRefitSettings) .ConfigureHttpClient(c => diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index f280f0800..8348f5f60 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -153,7 +153,9 @@ public static void Initialize() .AddSingleton(_ => null!) .AddSingleton(_ => null!) .AddSingleton(_ => null!) - .AddSingleton(_ => null!); + .AddSingleton(_ => null!) + .AddSingleton(_ => null!) + .AddSingleton(_ => null!); // Override Launch page with mock services.Remove(ServiceDescriptor.Singleton()); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs index 9d21d3103..ceb235dd1 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs @@ -152,7 +152,7 @@ private void InstallPackage(BasePackage selectedPackage) Version = installedVersion, LaunchCommand = selectedPackage.LaunchCommand, LastUpdateCheck = DateTimeOffset.Now, - PreferredTorchVersion = torchVersion, + PreferredTorchIndex = torchVersion, PreferredSharedFolderMethod = recommendedSharedFolderMethod }; @@ -176,7 +176,7 @@ private void InstallPackage(BasePackage selectedPackage) { SharedFolderMethod = recommendedSharedFolderMethod, VersionOptions = downloadVersion, - PythonOptions = { TorchVersion = torchVersion } + PythonOptions = { TorchIndex = torchVersion } } ); steps.Add(installStep); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs index cdb0f73ff..974a0d8a7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs @@ -172,7 +172,7 @@ private async Task DoInstall() Version = installedVersion, LaunchCommand = SelectedPackage.LaunchCommand, LastUpdateCheck = DateTimeOffset.Now, - PreferredTorchVersion = torchVersion, + PreferredTorchIndex = torchVersion, PreferredSharedFolderMethod = recommendedSharedFolderMethod }; @@ -184,7 +184,7 @@ private async Task DoInstall() { SharedFolderMethod = recommendedSharedFolderMethod, VersionOptions = downloadVersion, - PythonOptions = { TorchVersion = torchVersion } + PythonOptions = { TorchIndex = torchVersion } } ); steps.Add(installStep); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs index a88a6c625..d069067ae 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs @@ -263,7 +263,7 @@ public async Task AddPackageWithCurrentInputs() Version = version, LaunchCommand = SelectedBasePackage.LaunchCommand, LastUpdateCheck = DateTimeOffset.Now, - PreferredTorchVersion = torchVersion, + PreferredTorchIndex = torchVersion, PreferredSharedFolderMethod = sharedFolderRecommendation }; diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index 662ba2aab..9c703ac13 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; using AsyncAwaitBestPractices; +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Notifications; using CommunityToolkit.Mvvm.ComponentModel; @@ -20,6 +22,7 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Helper.Factory; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Database; @@ -54,7 +57,7 @@ IPackageFactory packageFactory public string ReleaseLabelText => IsReleaseMode ? Resources.Label_Version : Resources.Label_Branch; - public bool ShowTorchVersionOptions => SelectedTorchVersion != TorchVersion.None; + public bool ShowTorchIndexOptions => SelectedTorchIndex != TorchIndex.None; [ObservableProperty] [NotifyPropertyChangedFor(nameof(FullInstallPath))] @@ -77,8 +80,8 @@ IPackageFactory packageFactory private SharedFolderMethod selectedSharedFolderMethod; [ObservableProperty] - [NotifyPropertyChangedFor(nameof(ShowTorchVersionOptions))] - private TorchVersion selectedTorchVersion; + [NotifyPropertyChangedFor(nameof(ShowTorchIndexOptions))] + private TorchIndex selectedTorchIndex; [ObservableProperty] private ObservableCollection? availableCommits; @@ -92,6 +95,12 @@ IPackageFactory packageFactory [ObservableProperty] private bool canInstall; + [ObservableProperty, NotifyPropertyChangedFor(nameof(PipOverridesView))] + private ObservableCollection pipOverrides = new(); + + public DataGridCollectionView PipOverridesView => new(PipOverrides); + public List ConstraintOptions => ["==", ">=", "<=", ">", "<"]; + private PackageVersionOptions? allOptions; public override async Task OnLoadedAsync() @@ -103,7 +112,7 @@ public override async Task OnLoadedAsync() CanInstall = false; - SelectedTorchVersion = SelectedPackage.GetRecommendedTorchVersion(); + SelectedTorchIndex = SelectedPackage.GetRecommendedTorchVersion(); SelectedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod; allOptions = await SelectedPackage.GetAllVersionOptions(); @@ -220,9 +229,10 @@ private async Task Install() Version = installedVersion, LaunchCommand = SelectedPackage.LaunchCommand, LastUpdateCheck = DateTimeOffset.Now, - PreferredTorchVersion = SelectedTorchVersion, + PreferredTorchIndex = SelectedTorchIndex, PreferredSharedFolderMethod = SelectedSharedFolderMethod, - UseSharedOutputFolder = IsOutputSharingEnabled + UseSharedOutputFolder = IsOutputSharingEnabled, + PipOverrides = PipOverrides.Count > 0 ? PipOverrides.ToList() : null }; var steps = new List @@ -243,7 +253,7 @@ private async Task Install() { SharedFolderMethod = SelectedSharedFolderMethod, VersionOptions = downloadOptions, - PythonOptions = { TorchVersion = SelectedTorchVersion } + PythonOptions = { TorchIndex = SelectedTorchIndex } } ), new SetupModelFoldersStep(SelectedPackage, SelectedSharedFolderMethod, installLocation) @@ -285,6 +295,25 @@ private async Task Install() } } + [RelayCommand] + private void AddRow() + { + PipOverrides.Add(new PipPackageSpecifier { Constraint = "==" }); + } + + [RelayCommand] + private void RemoveSelectedRow(int selectedIndex) + { + try + { + PipOverrides.RemoveAt(selectedIndex); + } + catch (ArgumentOutOfRangeException) + { + Debug.WriteLine($"RemoveSelectedRow: Index {selectedIndex} out of range"); + } + } + private void UpdateVersions() { CanInstall = false; diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml index ae31079d4..25e3e0ba3 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml @@ -79,12 +79,12 @@ Foreground="OrangeRed" IsVisible="{Binding SelectedPackage.Disclaimer, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/> + ItemsSource="{Binding SelectedPackage.AvailableTorchIndices}"> - + + ItemsSource="{Binding AvailableTorchIndices}"> - + - - + - - + + @@ -618,46 +650,54 @@ - - - - + + + + - - - + + + - + @@ -665,16 +705,19 @@ - + - - - @@ -559,53 +594,57 @@ - + - - - - + + + + + + + + - + - - - - - - + + + + + + + dragTimers = new(); @@ -32,6 +32,16 @@ public CheckpointsPage() AddHandler(DragDrop.DragOverEvent, OnDragOver); } + protected override Action OnResizeFactorChanged => + () => + { + ImageRepeater.InvalidateMeasure(); + ImageRepeater.InvalidateArrange(); + }; + + protected override double MinResizeFactor => 0.6d; + protected override double MaxResizeFactor => 1.5d; + private void OnDragOver(object? sender, DragEventArgs e) { if (e.Data.Get(DataFormats.Files) is not IEnumerable files) diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index 9855d3ab0..1b691a798 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -5,18 +5,15 @@ xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" xmlns:checkpointBrowser="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" + xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:designData="clr-namespace:StabilityMatrix.Avalonia.DesignData" + xmlns:helpers="clr-namespace:StabilityMatrix.Avalonia.Helpers" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:viewModels="clr-namespace:StabilityMatrix.Avalonia.ViewModels" - xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointManager" - xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" - xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" - xmlns:helpers="clr-namespace:StabilityMatrix.Avalonia.Helpers" - xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls" + xmlns:scroll="clr-namespace:StabilityMatrix.Avalonia.Controls.Scroll" xmlns:system="clr-namespace:System;assembly=System.Runtime" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs" d:DataContext="{x:Static designData:DesignData.CivitAiBrowserViewModel}" d:DesignHeight="700" @@ -36,8 +33,7 @@ + + + + @@ -78,15 +81,14 @@ - + @@ -95,38 +97,42 @@ - + - + + ZIndex="100" /> - + + + + + + + + - + - + - + + Watermark="{x:Static lang:Resources.Action_Search}"> - @@ -99,19 +114,20 @@ - + + IconSource="Delete" + IsEnabled="{Binding NumItemsSelected}" /> - + + + + + + + + + + + + + + @@ -156,102 +204,106 @@ - - - + + + - - - - - - - - - - - + + + + + + + + IconSource="Copy" + Text="{x:Static lang:Resources.Action_Copy}" /> + IconSource="Folder" + Text="{x:Static lang:Resources.Action_OpenInExplorer}" /> - - - - + IconSource="Image" + IsVisible="{Binding !!$parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).NumItemsSelected}" + Text="{x:Static lang:Resources.Action_OpenInViewer}" /> - - - - + IconSource="Delete" + Text="{x:Static lang:Resources.Action_Delete}" /> + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs index b489897bd..aa6624659 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs @@ -1,44 +1,25 @@ -using Avalonia.Input; +using System; +using Avalonia.Input; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Core.Attributes; -using StabilityMatrix.Core.Models.Settings; namespace StabilityMatrix.Avalonia.Views; [Singleton] -public partial class OutputsPage : UserControlBase +public partial class OutputsPage : ResizableUserControlBase { public OutputsPage() { InitializeComponent(); } - private void ScrollViewer_MouseWheelChanged(object? sender, PointerWheelEventArgs e) - { - if (e.KeyModifiers != KeyModifiers.Control) - return; - if (DataContext is not OutputsPageViewModel vm) - return; - - if (e.Delta.Y > 0) - { - if (vm.ImageSize.Height >= 500) - return; - vm.ImageSize += new Size(10, 10); - } - else + protected override Action OnResizeFactorChanged => + () => { - if (vm.ImageSize.Height <= 200) - return; - vm.ImageSize -= new Size(10, 10); - } - - ImageRepeater.InvalidateArrange(); - ImageRepeater.InvalidateMeasure(); - - e.Handled = true; - } + ImageRepeater.InvalidateMeasure(); + ImageRepeater.InvalidateArrange(); + }; private void InputElement_OnKeyDown(object? sender, KeyEventArgs e) { diff --git a/StabilityMatrix.Core/Models/Api/CivitModel.cs b/StabilityMatrix.Core/Models/Api/CivitModel.cs index 9921c3440..5739d2619 100644 --- a/StabilityMatrix.Core/Models/Api/CivitModel.cs +++ b/StabilityMatrix.Core/Models/Api/CivitModel.cs @@ -70,5 +70,5 @@ public FileSizeType FullFilesSize ModelVersions is { Count: > 0 } ? ModelVersions[0].PublishedAt ?? DateTimeOffset.MinValue : DateTimeOffset.MinValue - ).ToString("d"); + ).ToString("M/d/yy"); } diff --git a/StabilityMatrix.Core/Models/InstalledPackage.cs b/StabilityMatrix.Core/Models/InstalledPackage.cs index 2eebe5300..74987a5b8 100644 --- a/StabilityMatrix.Core/Models/InstalledPackage.cs +++ b/StabilityMatrix.Core/Models/InstalledPackage.cs @@ -245,6 +245,7 @@ public async Task MigratePath(string? libraryDirectory = null) public void OnDeserialized() { +#pragma warning disable CS0618 // Type or member is obsolete // handle TorchIndex migration PreferredTorchIndex ??= PreferredTorchVersion; @@ -252,7 +253,6 @@ public void OnDeserialized() if (Version != null) return; -#pragma warning disable CS0618 // Type or member is obsolete if (string.IsNullOrWhiteSpace(InstalledBranch) && !string.IsNullOrWhiteSpace(PackageVersion)) { // release mode diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index 1e8bacf0a..c54b4333f 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -175,6 +175,8 @@ public IReadOnlyDictionary EnvironmentVariables .ToList(); public Size InferenceImageSize { get; set; } = new(150, 190); + + [Obsolete("Use OutputsPageResizeFactor instead")] public Size OutputsImageSize { get; set; } = new(300, 300); public HolidayMode HolidayModeSetting { get; set; } = HolidayMode.Automatic; public bool IsWorkflowInfiniteScrollEnabled { get; set; } = true; @@ -204,6 +206,12 @@ public IReadOnlyDictionary EnvironmentVariables public AnalyticsSettings Analytics { get; set; } = new(); + public double CheckpointsPageResizeFactor { get; set; } = 1.0d; + + public double OutputsPageResizeFactor { get; set; } = 1.0d; + + public double CivitBrowserResizeFactor { get; set; } = 1.0d; + [JsonIgnore] public bool IsHolidayModeActive => HolidayModeSetting == HolidayMode.Automatic From 4b40ba3fd8746053cea580aba92273689f476e7f Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 15 Sep 2024 16:48:56 -0700 Subject: [PATCH 298/325] update korean translation --- .../Languages/Resources.ko-KR.resx | 97 ++++++++++++++++--- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx b/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx index da88b315e..bdd545ed0 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx @@ -166,7 +166,7 @@ 브랜치 - 가져올 체크포인트를 여기에 끌어서 놓기 + 불러올 체크포인트를 여기에 끌어서 놓으세요 강조 @@ -177,6 +177,9 @@ 임베딩 / Textual Inversion + + 신경망 (Lora / LyCORIS) + 댓글 @@ -240,6 +243,9 @@ 설치 + + 초기 설정 건너뛰기 + 알 수 없는 오류가 발생했습니다 @@ -271,7 +277,7 @@ 완료되면 모달 닫기 - Data 디렉토리 + 데이터 디렉토리 애플리케이션 데이터(모델 체크포인트, Web UI 등)가 설치되는 위치입니다. @@ -300,11 +306,14 @@ Stability Matrix의 새로운 버전이 출시되었습니다! + + 최신 버전 가져오기 - + 모든 버전 - 검색 (모델, #태그, @유저) + 모델이나 #태그, @유저를 검색하세요 검색 @@ -366,6 +375,9 @@ 폴더 + + 불러올 파일을 여기에 끌어서 놓으세요 + 메타데이터를 포함해서 가져오기 @@ -492,6 +504,9 @@ 필수 입력입니다 + + 확인했나요? + @@ -592,7 +607,7 @@ 패키지 제거 중... - 패키지가 제거되었습니다 + 패키지 제거됨 일부 파일을 삭제할 수 없습니다. 패키지 디렉토리에서 열려 있는 모든 파일을 닫고 다시 시도하세요. @@ -600,9 +615,18 @@ 잘못된 패키지 유형 + + {0} 을(를) 업데이트하는 중입니다 + 업데이트 완료 + + {0} 을(를) 최신 버전으로 업데이트했습니다 + + + {0} 업데이트 오류 + 업데이트 실패 @@ -667,7 +691,7 @@ 이미지 뷰어로 열기 - {0}개의 이미지 선택됨 + {0}개의 이미지 선택함 출력 폴더 @@ -681,6 +705,9 @@ 모두 선택 + + 추론으로 보내기 + Text to Image @@ -697,11 +724,20 @@ 출력 브라우저 - 1개의 이미지 선택됨 + 1개의 이미지 선택함 Python 패키지 + + 병합하기 + + + 확실한가요? + + + 선택한 패키지에서 생성된 모든 이미지가 공유 출력 폴더의 Consolidated 디렉토리로 이동합니다. 이 작업은 되돌릴 수 없습니다. + 새로고침 @@ -777,6 +813,18 @@ 최신입니다 + + 마지막 확인: {0} + + + 트리거 단어 복사 + + + 트리거 단어: + + + 여기에서 IPAdapters 와 Textual Inversions(임베딩) 같은 추가 폴더를 활성화할 수 있습니다 + Hugging Face에서 열기 @@ -805,7 +853,7 @@ 자동완성 - 완성을 삽입할 때 밑줄을 공백으로 바꾸세요 + 추가할 때 밑줄을 공백으로 치환 프롬프트 태그 @@ -830,12 +878,19 @@ 애드온 Inference Sampler Addons + + 중간 이미지 저장 + Inference module step to save an intermediate image + 설정 파일 선택 + + 내용 덮어쓰기 + 아직 사용할 수 없습니다 @@ -845,6 +900,9 @@ 이미지 파일 누락 + + 축제 모드 + CLIP 스킵 @@ -863,6 +921,15 @@ 프레임 + + Motion Bucket ID + + + 증강 수준 + + + 방식 + 품질 @@ -990,7 +1057,7 @@ {0} 을(를) 성공적으로 삭제했습니다 - 워크플로우를 삭제했습니다 + 워크플로우 삭제됨 워크플로를 가져오는 중에 오류가 발생했습니다 @@ -999,13 +1066,19 @@ 설치된 워크플로우 - 워크플로를 가져왔습니다 + 워크플로우 가져옴 - 워크플로와 사용자 정의 노드를 가져왔습니다 + 워크플로우와 사용자 정의 노드 가져오기 완료 - 워크플로와 사용자 정의 노드를 가져왔습니다. + 워크플로우와 사용자 정의 노드를 가져왔습니다. + + + 여기를 클릭하여 프롬프트 구문과 Lora/임베딩을 추가하는 방법을 검토하세요. + + + 추가 신경망 (Lora / LyCORIS) CLIP 강도 @@ -1050,7 +1123,7 @@ 앱 데이터 - {0}을(를) 선택한 버전으로 업데이트했습니다 + {0} 을(를) 선택한 버전으로 업데이트했습니다 비트맵으로 복사 From ddae100817316a1d5c1c33bb8fcc6eb36ececac9 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 15 Sep 2024 20:15:21 -0400 Subject: [PATCH 299/325] Add ResizeBehavior --- .../Behaviors/ResizeBehavior.cs | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs diff --git a/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs new file mode 100644 index 000000000..c3529e54b --- /dev/null +++ b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs @@ -0,0 +1,127 @@ +using System; +using System.Diagnostics; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Input; +using Avalonia.Media; +using Avalonia.Xaml.Interactivity; +using FluentAvalonia.UI.Controls; + +namespace StabilityMatrix.Avalonia.Behaviors; + +public class ResizeBehavior : Behavior +{ + public static readonly StyledProperty MinResizeFactorProperty = AvaloniaProperty.Register< + ResizeBehavior, + double + >(nameof(MinResizeFactor), 0.5); + + public double MinResizeFactor + { + get => GetValue(MinResizeFactorProperty); + set => SetValue(MinResizeFactorProperty, value); + } + + public static readonly StyledProperty MaxResizeFactorProperty = AvaloniaProperty.Register< + ResizeBehavior, + double + >(nameof(MaxResizeFactor), 1.5); + + public double MaxResizeFactor + { + get => GetValue(MaxResizeFactorProperty); + set => SetValue(MaxResizeFactorProperty, value); + } + + public static readonly StyledProperty ResizeFactorProperty = AvaloniaProperty.Register< + ResizeBehavior, + double + >(nameof(ResizeFactor), 1, defaultBindingMode: BindingMode.TwoWay, coerce: CoerceResizeFactor); + + public double ResizeFactor + { + get => GetValue(ResizeFactorProperty); + set => SetValue(ResizeFactorProperty, value); + } + + private static double CoerceResizeFactor(AvaloniaObject sender, double value) + { + return ValidateDouble(value) + ? Math.Clamp( + value, + sender.GetValue(MinResizeFactorProperty), + sender.GetValue(MaxResizeFactorProperty) + ) + : sender.GetValue(ResizeFactorProperty); + } + + public static readonly StyledProperty UseMouseWheelResizeProperty = AvaloniaProperty.Register< + ResizeBehavior, + bool + >(nameof(UseMouseWheelResize), true); + + public bool UseMouseWheelResize + { + get => GetValue(UseMouseWheelResizeProperty); + set => SetValue(UseMouseWheelResizeProperty, value); + } + + protected override void OnAttached() + { + base.OnAttached(); + + if (AssociatedObject is null) + return; + + AssociatedObject.PointerWheelChanged += OnPointerWheelChanged; + } + + protected override void OnDetaching() + { + base.OnDetaching(); + + if (AssociatedObject is null) + return; + + AssociatedObject.PointerWheelChanged -= OnPointerWheelChanged; + } + + private void OnPointerWheelChanged(object? sender, PointerWheelEventArgs e) + { + if (e.KeyModifiers != KeyModifiers.Control) + return; + + if (!UseMouseWheelResize) + return; + + if (e.Delta.Y > 0 && ResizeFactor < MaxResizeFactor) + { + ResizeFactor += 0.05; + } + else if (e.Delta.Y < 0 && ResizeFactor > MinResizeFactor) + { + ResizeFactor -= 0.05; + } + + e.Handled = true; + + AssociatedObject?.InvalidateMeasure(); + AssociatedObject?.InvalidateArrange(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == ResizeFactorProperty) + { + CoerceValue(ResizeFactorProperty); + } + } + + private static bool ValidateDouble(double value) + { + return !double.IsInfinity(value) && !double.IsNaN(value); + } +} From d186f2884462edcf4eaba8407b3e0f1a3305c244 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 15 Sep 2024 20:17:35 -0400 Subject: [PATCH 300/325] Use ResizeBehavior --- .../Controls/ResizableUserControlBase.cs | 60 ------------------- StabilityMatrix.Avalonia/Models/IResizable.cs | 6 -- .../CivitAiBrowserViewModel.cs | 2 +- .../ViewModels/CheckpointsPageViewModel.cs | 2 +- .../ViewModels/OutputsPageViewModel.cs | 2 +- .../Views/CheckpointsPage.axaml | 8 ++- .../Views/CheckpointsPage.axaml.cs | 12 +--- .../Views/CivitAiBrowserPage.axaml | 8 ++- .../Views/CivitAiBrowserPage.axaml.cs | 13 +--- .../Views/OutputsPage.axaml | 8 ++- .../Views/OutputsPage.axaml.cs | 12 +--- 11 files changed, 28 insertions(+), 105 deletions(-) delete mode 100644 StabilityMatrix.Avalonia/Controls/ResizableUserControlBase.cs delete mode 100644 StabilityMatrix.Avalonia/Models/IResizable.cs diff --git a/StabilityMatrix.Avalonia/Controls/ResizableUserControlBase.cs b/StabilityMatrix.Avalonia/Controls/ResizableUserControlBase.cs deleted file mode 100644 index 43715748d..000000000 --- a/StabilityMatrix.Avalonia/Controls/ResizableUserControlBase.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.ComponentModel; -using System.Reactive.Linq; -using System.Threading; -using Avalonia.Input; -using Avalonia.Interactivity; -using StabilityMatrix.Avalonia.Models; - -namespace StabilityMatrix.Avalonia.Controls; - -public class ResizableUserControlBase : UserControlBase -{ - protected virtual Action? OnResizeFactorChanged => null; - protected virtual double MaxResizeFactor => 2.0d; - protected virtual double MinResizeFactor => 0.5d; - - protected override void OnLoaded(RoutedEventArgs e) - { - base.OnLoaded(e); - - if (DataContext is not IResizable viewModel) - return; - - Observable - .FromEventPattern(viewModel, nameof(PropertyChanged)) - .Where(x => x.EventArgs.PropertyName == nameof(viewModel.ResizeFactor)) - .Throttle(TimeSpan.FromMilliseconds(5)) - .ObserveOn(SynchronizationContext.Current!) - .Subscribe(_ => - { - OnResizeFactorChanged?.Invoke(); - }); - } - - protected override void OnPointerWheelChanged(PointerWheelEventArgs e) - { - if (e.KeyModifiers != KeyModifiers.Control) - return; - - if (DataContext is not IResizable resizable) - return; - - if (e.Delta.Y > 0) - { - if (resizable.ResizeFactor >= MaxResizeFactor) - return; - resizable.ResizeFactor += 0.05d; - } - else - { - if (resizable.ResizeFactor <= MinResizeFactor) - return; - resizable.ResizeFactor -= 0.05d; - } - - OnResizeFactorChanged?.Invoke(); - - e.Handled = true; - } -} diff --git a/StabilityMatrix.Avalonia/Models/IResizable.cs b/StabilityMatrix.Avalonia/Models/IResizable.cs deleted file mode 100644 index 956fe9236..000000000 --- a/StabilityMatrix.Avalonia/Models/IResizable.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace StabilityMatrix.Avalonia.Models; - -public interface IResizable -{ - public double ResizeFactor { get; set; } -} diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index 6bbfbccb7..52895efbb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -35,7 +35,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser; [View(typeof(CivitAiBrowserPage))] [Singleton] -public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScroll, IResizable +public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScroll { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly ICivitApi civitApi; diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 38aa3cb8a..f9ce925a7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -58,7 +58,7 @@ public partial class CheckpointsPageViewModel( IMetadataImportService metadataImportService, IModelImportService modelImportService, ServiceManager dialogFactory -) : PageViewModelBase, IResizable +) : PageViewModelBase { public override string Title => Resources.Label_CheckpointManager; diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs index 237037b47..c35b94984 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs @@ -47,7 +47,7 @@ namespace StabilityMatrix.Avalonia.ViewModels; [View(typeof(Views.OutputsPage))] [Singleton] -public partial class OutputsPageViewModel : PageViewModelBase, IResizable +public partial class OutputsPageViewModel : PageViewModelBase { private readonly ISettingsManager settingsManager; private readonly IPackageFactory packageFactory; diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 00fd0ce1e..72d57867b 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -2,6 +2,7 @@ x:Class="StabilityMatrix.Avalonia.Views.CheckpointsPage" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:behaviors="clr-namespace:StabilityMatrix.Avalonia.Behaviors" xmlns:checkpointManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointManager" xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=System.ComponentModel.TypeConverter" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" @@ -399,10 +400,15 @@ Padding="0,0,4,0" DragDrop.AllowDrop="True"> + + + diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs index 9fce4225d..4f3d79abd 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml.cs @@ -18,7 +18,7 @@ namespace StabilityMatrix.Avalonia.Views; [Singleton] -public partial class CheckpointsPage : ResizableUserControlBase +public partial class CheckpointsPage : UserControlBase { private Dictionary dragTimers = new(); @@ -32,16 +32,6 @@ public CheckpointsPage() AddHandler(DragDrop.DragOverEvent, OnDragOver); } - protected override Action OnResizeFactorChanged => - () => - { - ImageRepeater.InvalidateMeasure(); - ImageRepeater.InvalidateArrange(); - }; - - protected override double MinResizeFactor => 0.6d; - protected override double MaxResizeFactor => 1.5d; - private void OnDragOver(object? sender, DragEventArgs e) { if (e.Data.Get(DataFormats.Files) is not IEnumerable files) diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index 1b691a798..a66c79b1e 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -3,6 +3,7 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" + xmlns:behaviors="clr-namespace:StabilityMatrix.Avalonia.Behaviors" xmlns:checkpointBrowser="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" @@ -547,10 +548,15 @@ + + + diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs index 86173aa74..75e5500dd 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs @@ -2,7 +2,6 @@ using AsyncAwaitBestPractices; using Avalonia.Controls; using Avalonia.Input; -using Avalonia.Markup.Xaml; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Core.Attributes; @@ -11,23 +10,13 @@ namespace StabilityMatrix.Avalonia.Views; [Singleton] -public partial class CivitAiBrowserPage : ResizableUserControlBase +public partial class CivitAiBrowserPage : UserControlBase { public CivitAiBrowserPage() { InitializeComponent(); } - protected override Action OnResizeFactorChanged => - () => - { - ImageRepeater.InvalidateMeasure(); - ImageRepeater.InvalidateArrange(); - }; - - protected override double MinResizeFactor => 0.6d; - protected override double MaxResizeFactor => 1.5d; - private void ScrollViewer_OnScrollChanged(object? sender, ScrollChangedEventArgs e) { if (sender is not ScrollViewer scrollViewer) diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml index 6c11babf2..05b890a37 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml @@ -2,6 +2,7 @@ x:Class="StabilityMatrix.Avalonia.Views.OutputsPage" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:behaviors="clr-namespace:StabilityMatrix.Avalonia.Behaviors" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -217,10 +218,15 @@ + + + diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs index aa6624659..023eae702 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml.cs @@ -1,5 +1,4 @@ -using System; -using Avalonia.Input; +using Avalonia.Input; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Core.Attributes; @@ -7,20 +6,13 @@ namespace StabilityMatrix.Avalonia.Views; [Singleton] -public partial class OutputsPage : ResizableUserControlBase +public partial class OutputsPage : UserControlBase { public OutputsPage() { InitializeComponent(); } - protected override Action OnResizeFactorChanged => - () => - { - ImageRepeater.InvalidateMeasure(); - ImageRepeater.InvalidateArrange(); - }; - private void InputElement_OnKeyDown(object? sender, KeyEventArgs e) { if (e.Key == Key.Escape && DataContext is OutputsPageViewModel viewModel) From 31c539d63ad853d8601d906878ae9dc5869dfb26 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 15 Sep 2024 20:21:15 -0400 Subject: [PATCH 301/325] add smallchange --- .../Behaviors/ResizeBehavior.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs index c3529e54b..89d9f312c 100644 --- a/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs +++ b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs @@ -56,6 +56,17 @@ private static double CoerceResizeFactor(AvaloniaObject sender, double value) : sender.GetValue(ResizeFactorProperty); } + public static readonly StyledProperty SmallChangeProperty = AvaloniaProperty.Register< + ResizeBehavior, + double + >(nameof(SmallChange), 0.05); + + public double SmallChange + { + get => GetValue(SmallChangeProperty); + set => SetValue(SmallChangeProperty, value); + } + public static readonly StyledProperty UseMouseWheelResizeProperty = AvaloniaProperty.Register< ResizeBehavior, bool @@ -97,11 +108,11 @@ private void OnPointerWheelChanged(object? sender, PointerWheelEventArgs e) if (e.Delta.Y > 0 && ResizeFactor < MaxResizeFactor) { - ResizeFactor += 0.05; + ResizeFactor += SmallChange; } else if (e.Delta.Y < 0 && ResizeFactor > MinResizeFactor) { - ResizeFactor -= 0.05; + ResizeFactor -= SmallChange; } e.Handled = true; From c326297b9ab175369a9bf373ce89218ccecce323 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 15 Sep 2024 20:30:08 -0400 Subject: [PATCH 302/325] Move behavior to scrollviewer to work on blank spaces --- StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml | 12 ++++++------ .../Views/CivitAiBrowserPage.axaml | 12 ++++++------ StabilityMatrix.Avalonia/Views/OutputsPage.axaml | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 72d57867b..e6cc714c5 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -399,16 +399,16 @@ Grid.Column="1" Padding="0,0,4,0" DragDrop.AllowDrop="True"> + + + - - - diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index a66c79b1e..34c98dd2c 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -547,16 +547,16 @@ + + + - - - diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml index 05b890a37..93ffeb85c 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml @@ -217,16 +217,16 @@ IsVisible="{Binding IsChangingCategory}" /> + + + - - - From 6f181850c8fbb8ba6bc035f8206c05fc48876044 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sun, 15 Sep 2024 21:08:14 -0400 Subject: [PATCH 303/325] Add PointerWheelTargetObject & fix scroll arrange --- .../Behaviors/ResizeBehavior.cs | 17 +++++++++++++---- .../Views/CheckpointsPage.axaml | 14 ++++++++------ .../Views/CivitAiBrowserPage.axaml | 18 +++++++++++------- .../Views/OutputsPage.axaml | 18 +++++++++++------- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs index 89d9f312c..be5a02381 100644 --- a/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs +++ b/StabilityMatrix.Avalonia/Behaviors/ResizeBehavior.cs @@ -12,6 +12,15 @@ namespace StabilityMatrix.Avalonia.Behaviors; public class ResizeBehavior : Behavior { + public static readonly StyledProperty PointerWheelTargetObjectProperty = + AvaloniaProperty.Register(nameof(PointerWheelTargetObject)); + + public Control? PointerWheelTargetObject + { + get => GetValue(PointerWheelTargetObjectProperty); + set => SetValue(PointerWheelTargetObjectProperty, value); + } + public static readonly StyledProperty MinResizeFactorProperty = AvaloniaProperty.Register< ResizeBehavior, double @@ -82,20 +91,20 @@ protected override void OnAttached() { base.OnAttached(); - if (AssociatedObject is null) + if (PointerWheelTargetObject is null) return; - AssociatedObject.PointerWheelChanged += OnPointerWheelChanged; + PointerWheelTargetObject.PointerWheelChanged += OnPointerWheelChanged; } protected override void OnDetaching() { base.OnDetaching(); - if (AssociatedObject is null) + if (PointerWheelTargetObject is null) return; - AssociatedObject.PointerWheelChanged -= OnPointerWheelChanged; + PointerWheelTargetObject.PointerWheelChanged -= OnPointerWheelChanged; } private void OnPointerWheelChanged(object? sender, PointerWheelEventArgs e) diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index e6cc714c5..68cda6471 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -395,20 +395,22 @@ - - - + + + diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index 34c98dd2c..e0c50eaed 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -546,17 +546,21 @@ - - - - + + + + diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml index 93ffeb85c..a8d3822f6 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml @@ -216,17 +216,21 @@ IsIndeterminate="True" IsVisible="{Binding IsChangingCategory}" /> - - - - + + + + From 0b5cc9ff6f0403413482e7a6007c40de3e852a17 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 15 Sep 2024 19:40:45 -0700 Subject: [PATCH 304/325] Add toggle to hide early access models in civitai browser & fix checkpoints page zoom scaling --- CHANGELOG.md | 1 + .../Converters/MultiplyConverter.cs | 20 + .../CheckpointBrowserCardViewModel.cs | 10 +- .../CivitAiBrowserViewModel.cs | 25 +- .../Views/CheckpointsPage.axaml | 201 ++++----- .../Views/CivitAiBrowserPage.axaml | 24 +- .../Dialogs/SelectModelVersionDialog.axaml | 398 ++++++++++-------- .../Views/OutputsPage.axaml | 34 +- .../Models/Api/CivitModelVersion.cs | 7 + .../Models/Settings/Settings.cs | 2 + 10 files changed, 432 insertions(+), 290 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Converters/MultiplyConverter.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 21dd1b832..e81f7541c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.12.0 ### Added - Added zoom sliders for Outputs, Checkpoints, and Model Browser pages +- Added toggle to hide "Early Access" models in the CivitAI Model Browser ## v2.12.0-pre.3 ### Added diff --git a/StabilityMatrix.Avalonia/Converters/MultiplyConverter.cs b/StabilityMatrix.Avalonia/Converters/MultiplyConverter.cs new file mode 100644 index 000000000..a81f2fe7b --- /dev/null +++ b/StabilityMatrix.Avalonia/Converters/MultiplyConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; + +namespace StabilityMatrix.Avalonia.Converters; + +public class MultiplyConverter : IValueConverter +{ + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + var factor = System.Convert.ToDouble(value); + var multiplier = System.Convert.ToDouble(parameter, CultureInfo.InvariantCulture); + return factor * multiplier; + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs index 591b98758..0189e72ee 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs @@ -105,6 +105,10 @@ IModelImportService modelImportService settingsManager.RegisterPropertyChangedHandler( s => s.ModelBrowserNsfwEnabled, _ => Dispatcher.UIThread.Post(UpdateImage) + ), + settingsManager.RegisterPropertyChangedHandler( + s => s.HideEarlyAccessModels, + _ => Dispatcher.UIThread.Post(UpdateImage) ) ); @@ -165,7 +169,10 @@ private void CheckIfInstalled() private void UpdateImage() { var nsfwEnabled = settingsManager.Settings.ModelBrowserNsfwEnabled; - var version = CivitModel.ModelVersions?.FirstOrDefault(); + var hideEarlyAccessModels = settingsManager.Settings.HideEarlyAccessModels; + var version = CivitModel.ModelVersions?.FirstOrDefault( + v => !hideEarlyAccessModels || !v.IsEarlyAccess + ); var images = version?.Images; // Try to find a valid image @@ -240,6 +247,7 @@ private async Task ShowVersionDialog(CivitModel model) viewModel.Description = prunedDescription; viewModel.CivitModel = model; viewModel.Versions = versions + .Where(v => !settingsManager.Settings.HideEarlyAccessModels || !v.IsEarlyAccess) .Select(version => new ModelVersionViewModel(modelIndexService, version)) .ToImmutableArray(); viewModel.SelectedVersionViewModel = viewModel.Versions[0]; diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index 52895efbb..a7cf3aa86 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -91,6 +91,9 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit [ObservableProperty] private bool hideInstalledModels; + [ObservableProperty] + private bool hideEarlyAccessModels; + [ObservableProperty] [NotifyPropertyChangedFor(nameof(StatsResizeFactor))] private double resizeFactor; @@ -129,7 +132,13 @@ INotificationService notificationService var filterPredicate = Observable .FromEventPattern(this, nameof(PropertyChanged)) - .Where(x => x.EventArgs.PropertyName is nameof(HideInstalledModels) or nameof(ShowNsfw)) + .Where( + x => + x.EventArgs.PropertyName + is nameof(HideInstalledModels) + or nameof(ShowNsfw) + or nameof(HideEarlyAccessModels) + ) .Throttle(TimeSpan.FromMilliseconds(50)) .Select(_ => (Func)FilterModelCardsPredicate) .StartWith(FilterModelCardsPredicate) @@ -176,6 +185,13 @@ INotificationService notificationService settings => settings.CivitBrowserResizeFactor, true ); + + settingsManager.RelayPropertyFor( + this, + model => model.HideEarlyAccessModels, + settings => settings.HideEarlyAccessModels, + true + ); } private void OnNavigateAndFindCivitModelRequested(object? sender, int e) @@ -228,6 +244,13 @@ private bool FilterModelCardsPredicate(CheckpointBrowserCardViewModel card) if (HideInstalledModels && card.UpdateCardText == "Installed") return false; + if ( + HideEarlyAccessModels + && card.CivitModel.ModelVersions != null + && card.CivitModel.ModelVersions.All(x => x.Availability == "EarlyAccess") + ) + return false; + return !card.CivitModel.Nsfw || ShowNsfw; } diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 68cda6471..e1cfde541 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -30,6 +30,7 @@ + False True @@ -193,6 +194,32 @@ + + + + + + + + + + + - - - - - @@ -497,8 +505,7 @@ Text="{x:Static lang:Resources.Action_Delete}" /> - - + - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -613,6 +621,7 @@ Padding="8" CornerRadius="0,0,8,8" IsHitTestVisible="False"> + - + - - @@ -504,10 +504,10 @@ VerticalAlignment="Bottom" DefaultLabelPosition="Right"> - + + + + @@ -522,7 +522,7 @@ SmallChange="0.05" Value="{Binding ResizeFactor, Mode=TwoWay}" /> @@ -530,14 +530,22 @@ + - + + + + + + + + - + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml index 3dfefe730..317a3a1ea 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml @@ -1,38 +1,44 @@ - - + + - + MinHeight="450" + Margin="8" + ColumnDefinitions="*,Auto,*" + RowDefinitions="Auto, Auto, *, Auto"> + - + - - + + @@ -48,76 +54,106 @@ - + - - - - - + + + + + - - - - - - + + - - - - + + + + + + + + + @@ -130,18 +166,22 @@ - - + + @@ -151,31 +191,39 @@ - + - - + - @@ -189,79 +237,89 @@ - - - - - - - - + - - + + - + - - + + + + diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ExtraNetworkCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ExtraNetworkCardViewModel.cs index a52b113fb..349769168 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ExtraNetworkCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ExtraNetworkCardViewModel.cs @@ -4,6 +4,7 @@ using System.Text.Json.Nodes; using System.Text.Json.Serialization; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; @@ -86,6 +87,15 @@ public override void LoadStateFromJsonObject(JsonObject state) ClipWeight = model.ClipWeight; } + [RelayCommand] + private void CopyTriggerWords() + { + if (!ShowTriggerWords) + return; + + App.Clipboard.SetTextAsync(TriggerWords); + } + internal class ExtraNetworkCardModel { public string? SelectedModelName { get; init; } From c5302a67e9e53683a1f969137199d2301b2be1e6 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 16 Sep 2024 02:35:02 -0400 Subject: [PATCH 308/325] Fix property grid --- .../PropertyGrid/BetterPropertyGrid.cs | 135 +++++++++++++----- .../Views/Dialogs/PropertyGridDialog.axaml | 6 +- 2 files changed, 102 insertions(+), 39 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs b/StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs index a03243fb8..4d27cddaa 100644 --- a/StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs +++ b/StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Avalonia; using Avalonia.PropertyGrid.Services; using JetBrains.Annotations; @@ -15,10 +16,8 @@ public class BetterPropertyGrid : global::Avalonia.PropertyGrid.Controls.Propert { protected override Type StyleKeyOverride => typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid); - public static readonly StyledProperty> ExcludedCategoriesProperty = AvaloniaProperty.Register< - BetterPropertyGrid, - IEnumerable - >("ExcludedCategories"); + public static readonly StyledProperty> ExcludedCategoriesProperty = + AvaloniaProperty.Register>("ExcludedCategories"); public IEnumerable ExcludedCategories { @@ -26,10 +25,8 @@ public IEnumerable ExcludedCategories set => SetValue(ExcludedCategoriesProperty, value); } - public static readonly StyledProperty> IncludedCategoriesProperty = AvaloniaProperty.Register< - BetterPropertyGrid, - IEnumerable - >("IncludedCategories"); + public static readonly StyledProperty> IncludedCategoriesProperty = + AvaloniaProperty.Register>("IncludedCategories"); public IEnumerable IncludedCategories { @@ -45,37 +42,49 @@ static BetterPropertyGrid() // Initialize localization and name resolver LocalizationService.Default.AddExtraService(new PropertyGridLocalizationService()); - ExcludedCategoriesProperty - .Changed - .AddClassHandler( - (grid, args) => + ExcludedCategoriesProperty.Changed.AddClassHandler( + (grid, args) => + { + if (args.NewValue is IEnumerable excludedCategories) { - if (args.NewValue is IEnumerable excludedCategories) - { - grid.FilterExcludeCategories(excludedCategories); - } + grid.FilterExcludeCategories(excludedCategories); } - ); + } + ); - IncludedCategoriesProperty - .Changed - .AddClassHandler( - (grid, args) => + IncludedCategoriesProperty.Changed.AddClassHandler( + (grid, args) => + { + if (args.NewValue is IEnumerable includedCategories) { - if (args.NewValue is IEnumerable includedCategories) - { - grid.FilterIncludeCategories(includedCategories); - } + grid.FilterIncludeCategories(includedCategories); } - ); + } + ); } - public void FilterExcludeCategories(IEnumerable excludedCategories) + protected override void OnDataContextChanged(EventArgs e) { - // Get internal property `ViewModel` of internal type `PropertyGridViewModel` - var gridVm = this.GetProtectedProperty("ViewModel")!; - // Get public property `CategoryFilter` - var categoryFilter = gridVm.GetProtectedProperty("CategoryFilter")!; + base.OnDataContextChanged(e); + + if (DataContext is null) + return; + + SetViewModelContext(DataContext); + + // Apply filters again + FilterExcludeCategories(ExcludedCategories); + FilterIncludeCategories(IncludedCategories); + } + + public void FilterExcludeCategories(IEnumerable? excludedCategories) + { + excludedCategories ??= []; + + if (DataContext is null) + return; + + var categoryFilter = GetCategoryFilter(); categoryFilter.BeginUpdate(); @@ -96,12 +105,14 @@ public void FilterExcludeCategories(IEnumerable excludedCategories) categoryFilter.EndUpdate(); } - public void FilterIncludeCategories(IEnumerable includeCategories) + public void FilterIncludeCategories(IEnumerable? includeCategories) { - // Get internal property `ViewModel` of internal type `PropertyGridViewModel` - var gridVm = this.GetProtectedProperty("ViewModel")!; - // Get public property `CategoryFilter` - var categoryFilter = gridVm.GetProtectedProperty("CategoryFilter")!; + includeCategories ??= []; + + if (DataContext is null) + return; + + var categoryFilter = GetCategoryFilter(); categoryFilter.BeginUpdate(); @@ -121,4 +132,56 @@ public void FilterIncludeCategories(IEnumerable includeCategories) categoryFilter.EndUpdate(); } + + private void SetViewModelContext(object? context) + { + // Get internal property `ViewModel` of internal type `PropertyGridViewModel` + var propertyGridViewModelType = + typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid).Assembly.GetType( + "Avalonia.PropertyGrid.ViewModels.PropertyGridViewModel", + true + )!; + + var gridVm = this.GetProtectedProperty("ViewModel").Unwrap(); + + // Set `Context` public property + var contextProperty = propertyGridViewModelType + .GetProperty("Context", BindingFlags.Instance | BindingFlags.Public) + .Unwrap(); + contextProperty.SetValue(gridVm, context); + + // Trigger update that builds some stuff from `Context` and maybe initializes `Context` and `CategoryFilter` + var buildPropertiesViewMethod = typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid) + .GetMethod("BuildPropertiesView", BindingFlags.Instance | BindingFlags.NonPublic) + .Unwrap(); + buildPropertiesViewMethod.Invoke(this, [DataContext, ShowStyle]); + + // Call this to ensure `CategoryFilter` is initialized + var method = propertyGridViewModelType + .GetMethod("RefreshProperties", BindingFlags.Instance | BindingFlags.Public) + .Unwrap(); + method.Invoke(gridVm, null); + } + + private CheckedMaskModel GetCategoryFilter() + { + // Get internal property `ViewModel` of internal type `PropertyGridViewModel` + var propertyGridViewModelType = + typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid).Assembly.GetType( + "Avalonia.PropertyGrid.ViewModels.PropertyGridViewModel", + true + )!; + + var gridVm = this.GetProtectedProperty("ViewModel").Unwrap(); + + // Call this to ensure `CategoryFilter` is initialized + var method = propertyGridViewModelType + .GetMethod("RefreshProperties", BindingFlags.Instance | BindingFlags.Public) + .Unwrap(); + + method.Invoke(gridVm, null); + + // Get public property `CategoryFilter` + return gridVm.GetProtectedProperty("CategoryFilter").Unwrap(); + } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml index af365d1c4..7883fd5a2 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml @@ -14,15 +14,15 @@ x:DataType="vmDialogs:PropertyGridViewModel" mc:Ignorable="d"> - + From c4919dac119f7c082d46f5a6143218c7d88aa6b1 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 16 Sep 2024 18:09:38 -0700 Subject: [PATCH 309/325] Fix kohya git long paths issue & add to git dropdown menu in settings --- CHANGELOG.md | 8 +++ .../Helpers/UnixPrerequisiteHelper.cs | 7 +++ .../Helpers/WindowsPrerequisiteHelper.cs | 21 ++++++++ .../Settings/MainSettingsViewModel.cs | 22 ++++++++ .../Views/Settings/MainSettingsPage.axaml | 54 ++++++++++--------- .../Helper/IPrerequisiteHelper.cs | 2 + .../Models/Packages/KohyaSs.cs | 3 ++ 7 files changed, 91 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1fcdd23a..eee20de6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Added zoom sliders for Outputs, Checkpoints, and Model Browser pages - Added toggle to hide "Early Access" models in the CivitAI Model Browser - Added trigger words to the Inference Extra Networks (Lora/Lyco) selector for quick copy & paste +- Added "Enable Long Paths" option for Git to the Settings page +### Fixed +- Fixed [#888](https://github.com/LykosAI/StabilityMatrix/issues/888) - error updating kohya_ss due to long paths### Supporters +### Supporters +#### Visionaries +- A heartfelt thank you to our Visionary-tier patron, **Waterclouds**! We greatly appreciate your continued support! +### Pioneers +- A special shoutout to our Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, and **Szir777**! Your unwavering support means a great deal! ## v2.12.0-pre.3 ### Added diff --git a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs index 22c8fdcd1..a2a053f8f 100644 --- a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs @@ -482,4 +482,11 @@ public Task InstallVcRedistIfNecessary(IProgress? progress = nul { throw new PlatformNotSupportedException(); } + + [UnsupportedOSPlatform("Linux")] + [UnsupportedOSPlatform("macOS")] + public Task FixGitLongPaths() + { + throw new PlatformNotSupportedException(); + } } diff --git a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs index 36998ae3c..c3c9dd725 100644 --- a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs @@ -403,6 +403,27 @@ await downloadService.DownloadToFileAsync( } await UnzipGit(progress); + + await FixGitLongPaths(); + } + + [SupportedOSPlatform("windows")] + public async Task FixGitLongPaths() + { + if (!Compat.IsWindows) + return false; + + try + { + await RunGit(["config", "--system", "core.longpaths", "true"]); + return true; + } + catch (Exception e) + { + Logger.Error(e, "Failed to set git longpaths"); + } + + return false; } [SupportedOSPlatform("windows")] diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs index f230788b2..6bf94c1e6 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs @@ -538,6 +538,28 @@ await DialogHelper.GetTextEntryDialogResultAsync( ConsoleProcessRunner.RunProcessStepAsync(step).SafeFireAndForget(); } + [RelayCommand] + private async Task FixGitLongPaths() + { + var result = await prerequisiteHelper.FixGitLongPaths(); + if (result) + { + notificationService.Show( + "Long Paths Enabled", + "Git long paths have been enabled.", + NotificationType.Success + ); + } + else + { + notificationService.Show( + "Long Paths Not Enabled", + "Could not enable Git long paths.", + NotificationType.Error + ); + } + } + #endregion #region Directory Shortcuts diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index 6230e4454..4977e68d6 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -109,7 +109,7 @@ - + - + -