From b4fd64e7fc9592b60ba9dd2c6fa3887a1986080e Mon Sep 17 00:00:00 2001 From: jt Date: Sat, 18 Nov 2023 00:14:22 -0800 Subject: [PATCH 001/276] macos fixes & remove mac label for volta --- .../StabilityMatrix.Avalonia.Diagnostics.csproj | 1 + StabilityMatrix.Avalonia/App.axaml | 1 + StabilityMatrix.Avalonia/Helpers/UriHandler.cs | 2 +- StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj | 9 +++++++++ StabilityMatrix.Core/Models/Packages/BasePackage.cs | 5 +++++ StabilityMatrix.Core/Models/Packages/VoltaML.cs | 2 +- StabilityMatrix.Core/Processes/ProcessRunner.cs | 2 +- StabilityMatrix.Core/StabilityMatrix.Core.csproj | 1 + StabilityMatrix.Tests/StabilityMatrix.Tests.csproj | 1 + StabilityMatrix.UITests/StabilityMatrix.UITests.csproj | 1 + 10 files changed, 22 insertions(+), 3 deletions(-) diff --git a/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj b/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj index eb84e3f36..84e8c3f97 100644 --- a/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj +++ b/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj @@ -21,6 +21,7 @@ + diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index c2821641a..2e08109c8 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -4,6 +4,7 @@ xmlns:local="using:StabilityMatrix.Avalonia" xmlns:idcr="using:Dock.Avalonia.Controls.Recycling" xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia" + Name="Stability Matrix" RequestedThemeVariant="Dark"> diff --git a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs index e500a1e49..a6f04b3db 100644 --- a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs +++ b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs @@ -64,7 +64,7 @@ public void RegisterUriScheme() { RegisterUriSchemeWin(); } - else + else if (Compat.IsLinux) { RegisterUriSchemeUnix(); } diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index fb16d35f8..d3111ecd6 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -1,5 +1,6 @@  + Stability Matrix WinExe net8.0 win-x64;linux-x64;osx-x64;osx-arm64 @@ -14,6 +15,13 @@ true + + + StabilityMatrix.URL + stabilitymatrix;stabilitymatrix:// + + + @@ -37,6 +45,7 @@ + diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 29ff06b98..f704b0f07 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -133,6 +133,11 @@ public virtual TorchVersion GetRecommendedTorchVersion() return TorchVersion.DirectMl; } + if (Compat.IsMacOS && Compat.IsArm && AvailableTorchVersions.Contains(TorchVersion.Mps)) + { + return TorchVersion.Mps; + } + return TorchVersion.Cpu; } diff --git a/StabilityMatrix.Core/Models/Packages/VoltaML.cs b/StabilityMatrix.Core/Models/Packages/VoltaML.cs index eeef1ce3a..933e4fb30 100644 --- a/StabilityMatrix.Core/Models/Packages/VoltaML.cs +++ b/StabilityMatrix.Core/Models/Packages/VoltaML.cs @@ -62,7 +62,7 @@ IPrerequisiteHelper prerequisiteHelper public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink; public override IEnumerable AvailableTorchVersions => - new[] { TorchVersion.Cpu, TorchVersion.Cuda, TorchVersion.DirectMl, TorchVersion.Mps }; + new[] { TorchVersion.Cpu, TorchVersion.Cuda, TorchVersion.DirectMl }; public override IEnumerable AvailableSharedFolderMethods => new[] { SharedFolderMethod.Symlink, SharedFolderMethod.None }; diff --git a/StabilityMatrix.Core/Processes/ProcessRunner.cs b/StabilityMatrix.Core/Processes/ProcessRunner.cs index 3a20cc60b..8adde5ebf 100644 --- a/StabilityMatrix.Core/Processes/ProcessRunner.cs +++ b/StabilityMatrix.Core/Processes/ProcessRunner.cs @@ -92,7 +92,7 @@ public static async Task OpenFileBrowser(string filePath) else if (Compat.IsMacOS) { using var process = new Process(); - process.StartInfo.FileName = "explorer"; + process.StartInfo.FileName = "open"; process.StartInfo.Arguments = $"-R {Quote(filePath)}"; process.Start(); await process.WaitForExitAsync().ConfigureAwait(false); diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj index 254f8efe3..f62ba22af 100644 --- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj +++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj @@ -23,6 +23,7 @@ + diff --git a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj index 874234751..a0acdc339 100644 --- a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj +++ b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj index 8062d3bd4..961598f07 100644 --- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj +++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj @@ -11,6 +11,7 @@ + From e389085ec11104f51ac5b10c4e7edab3dc3f9f42 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 28 Nov 2023 23:03:51 -0800 Subject: [PATCH 002/276] Added image to video in inference (mostly) --- StabilityMatrix.Avalonia/App.axaml | 3 +- .../Controls/ModelCard.axaml | 2 + .../VideoGenerationSettingsCard.axaml | 122 +++++++++ .../VideoGenerationSettingsCard.axaml.cs | 7 + .../Controls/VideoOutputSettingsCard.axaml | 86 +++++++ .../Controls/VideoOutputSettingsCard.axaml.cs | 7 + .../DesignData/DesignData.cs | 14 + .../Models/Inference/VideoOutputMethod.cs | 8 + .../Models/InferenceProjectDocument.cs | 1 + .../Models/InferenceProjectType.cs | 4 +- .../StabilityMatrix.Avalonia.csproj | 12 + .../Base/InferenceGenerationViewModelBase.cs | 37 ++- .../InferenceImageToVideoViewModel.cs | 243 ++++++++++++++++++ .../Inference/ModelCardViewModel.cs | 5 +- .../Video/ImgToVidModelCardViewModel.cs | 37 +++ .../Video/SvdImgToVidConditioningViewModel.cs | 90 +++++++ .../Video/VideoOutputSettingsCardViewModel.cs | 80 ++++++ .../Inference/InferenceImageToVideoView.axaml | 221 ++++++++++++++++ .../InferenceImageToVideoView.axaml.cs | 13 + .../Views/InferencePage.axaml | 10 + .../Views/InferencePage.axaml.cs | 7 + .../Api/Comfy/NodeTypes/NodeConnections.cs | 2 + .../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 41 +++ 23 files changed, 1038 insertions(+), 14 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Controls/VideoGenerationSettingsCard.axaml create mode 100644 StabilityMatrix.Avalonia/Controls/VideoGenerationSettingsCard.axaml.cs create mode 100644 StabilityMatrix.Avalonia/Controls/VideoOutputSettingsCard.axaml create mode 100644 StabilityMatrix.Avalonia/Controls/VideoOutputSettingsCard.axaml.cs create mode 100644 StabilityMatrix.Avalonia/Models/Inference/VideoOutputMethod.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Video/ImgToVidModelCardViewModel.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Video/SvdImgToVidConditioningViewModel.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Video/VideoOutputSettingsCardViewModel.cs create mode 100644 StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml create mode 100644 StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml.cs diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index 93486dab1..4e02cb075 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -74,7 +74,8 @@ - + + diff --git a/StabilityMatrix.Avalonia/Controls/ModelCard.axaml b/StabilityMatrix.Avalonia/Controls/ModelCard.axaml index e0fc6a1c0..ce990ac96 100644 --- a/StabilityMatrix.Avalonia/Controls/ModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/ModelCard.axaml @@ -12,6 +12,7 @@ + @@ -135,6 +136,7 @@ + + @@ -190,6 +192,31 @@ IsVisible="{Binding IsVaeSelectionEnabled}" ItemsSource="{Binding ClientManager.VaeModels}" SelectedItem="{Binding SelectedVae}" /> + + + + + From d82f3d4843b3ec4200fa95893c946f71ea8f1d17 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:57:23 -0500 Subject: [PATCH 009/276] Fix Value access --- .../Inference/Modules/ControlNetModule.cs | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs index 4f4e71915..26bf78970 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; -using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; @@ -42,9 +40,8 @@ protected override void OnApplyStep(ModuleApplyStepEventArgs e) { Name = e.Nodes.GetUniqueName("ControlNet_LoadImage"), Image = - card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached( - "Inference" - ) ?? throw new ValidationException("No ImageSource") + card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference") + ?? throw new ValidationException("No ImageSource") } ); @@ -52,9 +49,7 @@ protected override void OnApplyStep(ModuleApplyStepEventArgs e) new ComfyNodeBuilder.ControlNetLoader { Name = e.Nodes.GetUniqueName("ControlNetLoader"), - ControlNetName = - card.SelectedModel?.FileName - ?? throw new ValidationException("No SelectedModel"), + ControlNetName = card.SelectedModel?.FileName ?? throw new ValidationException("No SelectedModel"), } ); @@ -64,10 +59,8 @@ protected override void OnApplyStep(ModuleApplyStepEventArgs e) Name = e.Nodes.GetUniqueName("ControlNetApply"), Image = imageLoad.Output1, ControlNet = controlNetLoader.Output, - Positive = - e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"), - Negative = - e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"), + Positive = e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"), + Negative = e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"), Strength = card.Strength, StartPercent = card.StartPercent, EndPercent = card.EndPercent, @@ -85,18 +78,15 @@ protected override void OnApplyStep(ModuleApplyStepEventArgs e) Name = e.Nodes.GetUniqueName("Refiner_ControlNetApply"), Image = imageLoad.Output1, ControlNet = controlNetLoader.Output, - Positive = e.Temp.RefinerConditioning.Value.Positive, - Negative = e.Temp.RefinerConditioning.Value.Negative, + Positive = e.Temp.RefinerConditioning.Positive, + Negative = e.Temp.RefinerConditioning.Negative, Strength = card.Strength, StartPercent = card.StartPercent, EndPercent = card.EndPercent, } ); - e.Temp.RefinerConditioning = ( - controlNetRefinerApply.Output1, - controlNetRefinerApply.Output2 - ); + e.Temp.RefinerConditioning = (controlNetRefinerApply.Output1, controlNetRefinerApply.Output2); } } } From 1c37e9b4e400e0639be005dc30f5d89647ccd04c Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:58:28 -0500 Subject: [PATCH 010/276] Version bump --- 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 446a24766..2113c78c6 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -9,7 +9,7 @@ app.manifest true ./Assets/Icon.ico - 2.7.0-pre.999 + 2.8.0-dev.999 $(Version) true true From ed4f78a57ece8bcbc9c548f118b3b1e4bdf4ada4 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 17:02:21 -0500 Subject: [PATCH 011/276] Add clip skip default value --- .../ViewModels/Inference/ModelCardViewModel.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs index 38e13bb28..b8a1d94bb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs @@ -9,9 +9,7 @@ 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.NodeTypes; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; namespace StabilityMatrix.Avalonia.ViewModels.Inference; @@ -208,7 +206,7 @@ internal class ModelCardModel public string? SelectedModelName { get; init; } public string? SelectedRefinerName { get; init; } public string? SelectedVaeName { get; init; } - public int ClipSkip { get; init; } + public int ClipSkip { get; init; } = 1; public bool IsVaeSelectionEnabled { get; init; } public bool IsRefinerSelectionEnabled { get; init; } From a6c87a2be3f28c9143617266ace9b51841846006 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 21:11:56 -0500 Subject: [PATCH 012/276] Add BetterComboBox --- StabilityMatrix.Avalonia/App.axaml | 1 + .../Controls/BetterComboBox.cs | 41 ++++ .../ControlThemes/BetterComboBoxStyles.axaml | 202 ++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 StabilityMatrix.Avalonia/Controls/BetterComboBox.cs create mode 100644 StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index f54dc933c..afeea8697 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -24,6 +24,7 @@ + diff --git a/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs new file mode 100644 index 000000000..7209879cc --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs @@ -0,0 +1,41 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; + +namespace StabilityMatrix.Avalonia.Controls; + +public class BetterComboBox : ComboBox +{ + // protected override Type StyleKeyOverride { get; } = typeof(CheckBox); + + public static readonly DirectProperty SelectionBoxItemTemplateProperty = + AvaloniaProperty.RegisterDirect( + nameof(SelectionBoxItemTemplate), + v => v.SelectionBoxItemTemplate, + (x, v) => x.SelectionBoxItemTemplate = v + ); + + private IDataTemplate? _selectionBoxItemTemplate; + + public IDataTemplate? SelectionBoxItemTemplate + { + get => _selectionBoxItemTemplate; + private set => SetAndRaise(SelectionBoxItemTemplateProperty, ref _selectionBoxItemTemplate, value); + } + + /// + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + if (e.NameScope.Find("ContentPresenter") is { } contentPresenter) + { + if (SelectionBoxItemTemplate is { } template) + { + contentPresenter.ContentTemplate = template; + } + } + } +} diff --git a/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml new file mode 100644 index 000000000..887299ca6 --- /dev/null +++ b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1afe3e6347a48a5d7a22dd4507ccfadfaf99db13 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 21:12:59 -0500 Subject: [PATCH 013/276] Add improved model card combo box styles --- .../Controls/Inference/ModelCard.axaml | 117 ++---------------- .../DesignData/DesignData.cs | 38 ++++++ .../Models/Database/LocalModelFile.cs | 17 ++- 3 files changed, 67 insertions(+), 105 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml index 7bf995a87..4e5a3ed24 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml @@ -30,112 +30,21 @@ VerticalAlignment="Center" Text="{x:Static lang:Resources.Label_Model}" TextAlignment="Left" /> - - - - - - - - - - - - - - - - - + SelectedItem="{Binding SelectedModel}"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs new file mode 100644 index 000000000..53ba4b810 --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs @@ -0,0 +1,13 @@ +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Views.Dialogs; + +[Singleton] +public partial class NewInstallerDialog : UserControlBase +{ + public NewInstallerDialog() + { + InitializeComponent(); + } +} diff --git a/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml new file mode 100644 index 000000000..f2f8f007a --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml @@ -0,0 +1,49 @@ + + + + + + 24 + 17 + 6,3 + Medium + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs new file mode 100644 index 000000000..a503d34a0 --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs @@ -0,0 +1,99 @@ +using System; +using System.ComponentModel; +using System.Linq; +using Avalonia.Interactivity; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using FluentAvalonia.UI.Media.Animation; +using FluentAvalonia.UI.Navigation; +using Microsoft.Extensions.DependencyInjection; +using StabilityMatrix.Avalonia.Animations; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Models; +using StabilityMatrix.Avalonia.Services; +using StabilityMatrix.Avalonia.ViewModels; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models; + +namespace StabilityMatrix.Avalonia.Views; + +[Singleton] +public partial class NewPackageManagerPage : UserControlBase, IHandleNavigation +{ + private readonly INavigationService packageNavigationService; + + private bool hasLoaded; + + private NewPackageManagerViewModel ViewModel => (NewPackageManagerViewModel)DataContext!; + + [DesignOnly(true)] + [Obsolete("For XAML use only", true)] + public NewPackageManagerPage() + : this(App.Services.GetRequiredService>()) { } + + public NewPackageManagerPage(INavigationService packageNavigationService) + { + this.packageNavigationService = packageNavigationService; + + InitializeComponent(); + + packageNavigationService.SetFrame(FrameView); + packageNavigationService.TypedNavigation += NavigationService_OnTypedNavigation; + FrameView.Navigated += FrameView_Navigated; + BreadcrumbBar.ItemClicked += BreadcrumbBar_ItemClicked; + } + + /// + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + if (!hasLoaded) + { + // Initial load, navigate to first page + Dispatcher.UIThread.Post( + () => + packageNavigationService.NavigateTo( + ViewModel.SubPages[0], + new SuppressNavigationTransitionInfo() + ) + ); + + hasLoaded = true; + } + } + + private void NavigationService_OnTypedNavigation(object? sender, TypedNavigationEventArgs e) + { + ViewModel.CurrentPage = + ViewModel.SubPages.FirstOrDefault(x => x.GetType() == e.ViewModelType) + ?? e.ViewModel as PageViewModelBase; + } + + private void FrameView_Navigated(object? sender, NavigationEventArgs args) + { + if (args.Content is not PageViewModelBase vm) + { + return; + } + + ViewModel.CurrentPage = vm; + } + + private void BreadcrumbBar_ItemClicked(BreadcrumbBar sender, BreadcrumbBarItemClickedEventArgs args) + { + // Skip if already on same page + if (args.Item is not PageViewModelBase viewModel || viewModel == ViewModel.CurrentPage) + { + return; + } + + packageNavigationService.NavigateTo(viewModel, BetterSlideNavigationTransition.PageSlideFromLeft); + } + + public bool GoBack() + { + return packageNavigationService.GoBack(); + } +} diff --git a/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml b/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml new file mode 100644 index 000000000..9a8265299 --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + @@ -225,9 +240,9 @@ - - - - - + + + + + diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs index 5282b8857..e017decf3 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs @@ -33,9 +33,9 @@ private void OnNavigatedTo(object? sender, NavigationEventArgs args) if (args.Parameter is PackageManagerNavigationOptions { OpenInstallerDialog: true } options) { var vm = (PackageManagerViewModel)DataContext!; - Dispatcher.UIThread.InvokeAsync(async () => + Dispatcher.UIThread.Invoke(() => { - await vm.ShowInstallDialog(options.InstallerSelectedPackage); + vm.ShowInstallDialog(options.InstallerSelectedPackage); }); } } diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs index 1f646d067..8da91d960 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs @@ -28,7 +28,8 @@ IPrerequisiteHelper prerequisiteHelper public override string DisplayName { get; set; } = "Stable Diffusion Web UI-UX"; public override string Author => "anapnoe"; public override string LicenseType => "AGPL-3.0"; - public override string LicenseUrl => "https://github.com/anapnoe/stable-diffusion-webui-ux/blob/master/LICENSE.txt"; + public override string LicenseUrl => + "https://github.com/anapnoe/stable-diffusion-webui-ux/blob/master/LICENSE.txt"; public override string Blurb => "A pixel perfect design, mobile friendly, customizable interface that adds accessibility, " + "ease of use and extended functionallity to the stable diffusion web ui."; @@ -38,7 +39,7 @@ IPrerequisiteHelper prerequisiteHelper public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink; - public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Simple; + public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Advanced; public override Dictionary> SharedFolders => new() From 82004934aa22d576ce864b4774af2bb58001cc04 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 2 Jan 2024 19:31:00 -0800 Subject: [PATCH 106/276] default to recommended torch version & show disclaimers --- .../PackageInstallDetailViewModel.cs | 2 + .../Views/Dialogs/NewInstallerDialog.axaml | 43 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs index c2c7b25de..72a155ab3 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs @@ -107,6 +107,8 @@ public override async Task OnLoadedAsync() UpdateVersions(); await UpdateCommits(SelectedPackage.MainBranch); } + + SelectedTorchVersion = SelectedPackage.GetRecommendedTorchVersion(); } [RelayCommand] diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml index 9fd960943..bd98a96cd 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml @@ -30,43 +30,40 @@ CommandParameter="{Binding }"> - + - + - - + + - @@ -187,10 +184,10 @@ + + - Date: Tue, 2 Jan 2024 20:03:22 -0800 Subject: [PATCH 107/276] also set RecommendedSharedFolderMethod --- .../ViewModels/PackageInstallDetailViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs index 72a155ab3..bbb8cff0c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs @@ -109,6 +109,7 @@ public override async Task OnLoadedAsync() } SelectedTorchVersion = SelectedPackage.GetRecommendedTorchVersion(); + SelectedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod; } [RelayCommand] From f582bf4d76ebe772f3e62c0d852ad374037ea2ce Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 2 Jan 2024 20:31:43 -0800 Subject: [PATCH 108/276] ionite killed comfy manager & I added search to new packages page --- .../Dialogs/NewInstallerDialogViewModel.cs | 21 +++++- .../Views/Dialogs/NewInstallerDialog.axaml | 74 ++++++++++++++++--- .../Views/Dialogs/NewInstallerDialog.axaml.cs | 12 ++- .../Models/Packages/BasePackage.cs | 4 - .../Models/Packages/ComfyUI.cs | 3 - .../Packages/Extensions/ComfyManager.cs | 28 ------- 6 files changed, 93 insertions(+), 49 deletions(-) delete mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/ComfyManager.cs diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs index b2c9d879e..d041e4c12 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs @@ -38,6 +38,9 @@ public partial class NewInstallerDialogViewModel : PageViewModelBase [ObservableProperty] private bool showIncompatiblePackages = false; + [ObservableProperty] + private string searchFilter = string.Empty; + private SourceCache packageSource = new(p => p.GithubUrl); public IObservableCollection InferencePackages { get; } = @@ -63,13 +66,23 @@ IPrerequisiteHelper prerequisiteHelper this.pyRunner = pyRunner; this.prerequisiteHelper = prerequisiteHelper; - var searchPredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages) + var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages) .Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages)) .AsObservable(); + var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchFilter) + .Select( + _ => + new Func( + p => p.DisplayName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) + ) + ) + .AsObservable(); + packageSource .Connect() .DeferUntilLoaded() + .Filter(incompatiblePredicate) .Filter(searchPredicate) .Where(p => p is { PackageType: PackageType.SdInference }) .Sort( @@ -83,6 +96,7 @@ IPrerequisiteHelper prerequisiteHelper packageSource .Connect() .DeferUntilLoaded() + .Filter(incompatiblePredicate) .Filter(searchPredicate) .Where(p => p is { PackageType: PackageType.SdTraining }) .Sort( @@ -124,4 +138,9 @@ public void OnPackageSelected(BaseGitPackage package) DispatcherPriority.Send ); } + + public void ClearSearchQuery() + { + SearchFilter = string.Empty; + } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml index bd98a96cd..00ae0cb42 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml @@ -203,12 +203,37 @@ - + + + + + + + + + + + @@ -223,12 +248,37 @@ - + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs index 53ba4b810..3fbb23018 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml.cs @@ -1,4 +1,6 @@ -using StabilityMatrix.Avalonia.Controls; +using Avalonia.Input; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Core.Attributes; namespace StabilityMatrix.Avalonia.Views.Dialogs; @@ -10,4 +12,12 @@ public NewInstallerDialog() { InitializeComponent(); } + + private void InputElement_OnKeyDown(object? sender, KeyEventArgs e) + { + if (e.Key == Key.Escape && DataContext is NewInstallerDialogViewModel vm) + { + vm.ClearSearchQuery(); + } + } } diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 8cbdb81dc..68fd939a5 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -50,10 +50,6 @@ public abstract class BasePackage public virtual PackageType PackageType => PackageType.SdInference; - public virtual IEnumerable AvailableExtensions => Enumerable.Empty(); - - public virtual string ExtensionsFolderName => string.Empty; - public abstract Task DownloadPackage( string installLocation, DownloadPackageVersionOptions versionOptions, diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 5c833a530..5ac92976d 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -168,9 +168,6 @@ IPrerequisiteHelper prerequisiteHelper public override string MainBranch => "master"; - public override IEnumerable AvailableExtensions => [new ComfyManager(PrerequisiteHelper)]; - public override string ExtensionsFolderName => "custom_nodes"; - public override IEnumerable AvailableTorchVersions => new[] { diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/ComfyManager.cs b/StabilityMatrix.Core/Models/Packages/Extensions/ComfyManager.cs deleted file mode 100644 index 7bbaec887..000000000 --- a/StabilityMatrix.Core/Models/Packages/Extensions/ComfyManager.cs +++ /dev/null @@ -1,28 +0,0 @@ -using StabilityMatrix.Core.Helper; -using StabilityMatrix.Core.Models.FileInterfaces; - -namespace StabilityMatrix.Core.Models.Packages.Extensions; - -public class ComfyManager(IPrerequisiteHelper prerequisiteHelper) : ExtensionBase -{ - public override string RepoName => "ComfyUI-Manager"; - public override string DisplayName { get; set; } = "ComfyUI Manager"; - public override string Author => "ltdrdata"; - - public override string Blurb => - "ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custom nodes of ComfyUI."; - - public override IEnumerable CompatibleWith => [nameof(ComfyUI)]; - public override string MainBranch => "main"; - - public override Task InstallExtensionAsync( - DirectoryPath installDirectory, - string branch, - CancellationToken cancellationToken = default - ) - { - return Directory.Exists(Path.Combine(installDirectory, RepoName)) - ? Task.CompletedTask - : prerequisiteHelper.RunGit(new[] { "clone", GithubUrl }, installDirectory); - } -} From 3a2223cddadf8e5e49064f295a01841da74e5d53 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 2 Jan 2024 20:33:15 -0800 Subject: [PATCH 109/276] extensions ded --- .../PackageInstallDetailViewModel.cs | 27 ++----------------- .../Views/PackageInstallDetailView.axaml | 18 ------------- 2 files changed, 2 insertions(+), 43 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs index bbb8cff0c..cae6f84cd 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs @@ -50,7 +50,6 @@ INavigationService packageNavigationService public string ReleaseLabelText => IsReleaseMode ? Resources.Label_Version : Resources.Label_Branch; public bool ShowTorchVersionOptions => SelectedTorchVersion != TorchVersion.None; - public bool ShowExtensions => SelectedPackage.AvailableExtensions.Any(); [ObservableProperty] [NotifyPropertyChangedFor(nameof(FullInstallPath))] @@ -82,9 +81,6 @@ INavigationService packageNavigationService [ObservableProperty] private GitCommit? selectedCommit; - [ObservableProperty] - private ObservableCollection availableExtensions = []; - private PackageVersionOptions? allOptions; public override async Task OnLoadedAsync() @@ -93,9 +89,6 @@ public override async Task OnLoadedAsync() return; OnInstallNameChanged(InstallName); - AvailableExtensions = new ObservableCollection( - SelectedPackage.AvailableExtensions.Select(p => new ExtensionViewModel { Extension = p }) - ); allOptions = await SelectedPackage.GetAllVersionOptions(); if (ShowReleaseMode) @@ -171,16 +164,6 @@ private async Task Install() downloadOptions, installLocation ); - var installExtensionSteps = AvailableExtensions - .Where(e => e.IsSelected) - .Select( - e => - new InstallExtensionStep( - e.Extension, - Path.Combine(installLocation, SelectedPackage.ExtensionsFolderName) - ) - ) - .ToList(); var setupModelFoldersStep = new SetupModelFoldersStep( SelectedPackage, @@ -209,16 +192,10 @@ private async Task Install() prereqStep, downloadStep, installStep, + setupModelFoldersStep, + addInstalledPackageStep }; - if (installExtensionSteps.Count > 0) - { - steps.AddRange(installExtensionSteps); - } - - steps.Add(setupModelFoldersStep); - steps.Add(addInstalledPackageStep); - var runner = new PackageModificationRunner { ShowDialogOnStart = true }; EventManager.Instance.OnPackageInstallProgressAdded(runner); await runner.ExecuteSteps(steps.ToList()); diff --git a/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml b/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml index 9a8265299..713d7e2e4 100644 --- a/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml @@ -97,24 +97,6 @@ - - - - - - - - - - - - - Date: Thu, 4 Jan 2024 09:58:47 +0800 Subject: [PATCH 110/276] Organize namespaces --- StabilityMatrix.Avalonia/DesignData/DesignData.cs | 9 +++------ .../StabilityMatrix.Avalonia.csproj | 6 +++++- .../ViewModels/NewPackageManagerViewModel.cs | 3 ++- .../PackageInstallBrowserViewModel.cs} | 13 +++++-------- .../PackageInstallDetailViewModel.cs | 4 ++-- .../ViewModels/PackageManagerViewModel.cs | 2 +- .../PackageInstallBrowserView.axaml} | 5 +++-- .../PackageInstallBrowserView.axaml.cs} | 10 +++++----- .../PackageInstallDetailView.axaml | 5 +++-- .../PackageInstallDetailView.axaml.cs | 2 +- 10 files changed, 30 insertions(+), 29 deletions(-) rename StabilityMatrix.Avalonia/ViewModels/{Dialogs/NewInstallerDialogViewModel.cs => PackageManager/PackageInstallBrowserViewModel.cs} (93%) rename StabilityMatrix.Avalonia/ViewModels/{ => PackageManager}/PackageInstallDetailViewModel.cs (98%) rename StabilityMatrix.Avalonia/Views/{Dialogs/NewInstallerDialog.axaml => PackageManager/PackageInstallBrowserView.axaml} (98%) rename StabilityMatrix.Avalonia/Views/{Dialogs/NewInstallerDialog.axaml.cs => PackageManager/PackageInstallBrowserView.axaml.cs} (50%) rename StabilityMatrix.Avalonia/Views/{ => PackageManager}/PackageInstallDetailView.axaml (97%) rename StabilityMatrix.Avalonia/Views/{ => PackageManager}/PackageInstallDetailView.axaml.cs (81%) diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index b112c6f67..9688f93d0 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -8,13 +8,10 @@ using System.Net.Http; using System.Text; using AvaloniaEdit.Utils; -using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using DynamicData.Binding; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; -using NSubstitute.ReturnsExtensions; using Semver; using StabilityMatrix.Avalonia.Controls.CodeCompletion; using StabilityMatrix.Avalonia.Models; @@ -26,9 +23,9 @@ using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Avalonia.ViewModels.Inference; -using StabilityMatrix.Avalonia.ViewModels.Inference.Modules; using StabilityMatrix.Avalonia.ViewModels.Inference.Video; using StabilityMatrix.Avalonia.ViewModels.OutputsPage; +using StabilityMatrix.Avalonia.ViewModels.PackageManager; using StabilityMatrix.Avalonia.ViewModels.Progress; using StabilityMatrix.Avalonia.ViewModels.Settings; using StabilityMatrix.Core.Api; @@ -178,7 +175,7 @@ public static void Initialize() }; LaunchOptionsViewModel.UpdateFilterCards(); - NewInstallerDialogViewModel = Services.GetRequiredService(); + NewInstallerDialogViewModel = Services.GetRequiredService(); // NewInstallerDialogViewModel.InferencePackages = new ObservableCollectionExtended( // packageFactory.GetPackagesByType(PackageType.SdInference).OrderBy(p => p.InstallerSortOrder) // ); @@ -418,7 +415,7 @@ public static void Initialize() } [NotNull] - public static NewInstallerDialogViewModel? NewInstallerDialogViewModel { get; private set; } + public static PackageInstallBrowserViewModel? NewInstallerDialogViewModel { get; private set; } [NotNull] public static PackageInstallDetailViewModel? PackageInstallDetailViewModel { get; private set; } diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 145a821a3..51fd37cc9 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -177,10 +177,14 @@ NewPackageManagerPage.axaml Code - + PackageInstallDetailView.axaml Code + + NewInstallerDialog.axaml + Code + diff --git a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs index ed751c8ec..0cd0e6897 100644 --- a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs @@ -6,6 +6,7 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Dialogs; +using StabilityMatrix.Avalonia.ViewModels.PackageManager; using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; using Symbol = FluentIcons.Common.Symbol; @@ -33,7 +34,7 @@ public NewPackageManagerViewModel(ServiceManager vmFactory) SubPages = new PageViewModelBase[] { vmFactory.Get(), - vmFactory.Get(), + vmFactory.Get(), }; CurrentPagePath.AddRange(SubPages); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs similarity index 93% rename from StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs rename to StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs index d041e4c12..44ce5d4c7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewInstallerDialogViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; using System.Reactive.Linq; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -13,7 +10,7 @@ using StabilityMatrix.Avalonia.Animations; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.Views.Dialogs; +using StabilityMatrix.Avalonia.Views.PackageManager; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Factory; @@ -22,11 +19,11 @@ using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; -namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; +namespace StabilityMatrix.Avalonia.ViewModels.PackageManager; -[View(typeof(NewInstallerDialog))] +[View(typeof(PackageInstallBrowserView))] [Transient, ManagedService] -public partial class NewInstallerDialogViewModel : PageViewModelBase +public partial class PackageInstallBrowserViewModel : PageViewModelBase { private readonly INavigationService packageNavigationService; private readonly ISettingsManager settingsManager; @@ -49,7 +46,7 @@ public partial class NewInstallerDialogViewModel : PageViewModelBase public IObservableCollection TrainingPackages { get; } = new ObservableCollectionExtended(); - public NewInstallerDialogViewModel( + public PackageInstallBrowserViewModel( IPackageFactory packageFactory, INavigationService packageNavigationService, ISettingsManager settingsManager, diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs similarity index 98% rename from StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs rename to StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index cae6f84cd..f6022e1ba 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -15,7 +15,6 @@ using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; -using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; @@ -25,9 +24,10 @@ using StabilityMatrix.Core.Models.Packages; using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; +using PackageInstallDetailView = StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallDetailView; using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; -namespace StabilityMatrix.Avalonia.ViewModels; +namespace StabilityMatrix.Avalonia.ViewModels.PackageManager; [View(typeof(PackageInstallDetailView))] public partial class PackageInstallDetailViewModel( diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs index 950abf1f6..3fc0b95e4 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs @@ -138,7 +138,7 @@ public override void OnUnloaded() public void ShowInstallDialog(BasePackage? selectedPackage = null) { - NavigateToSubPage(typeof(NewInstallerDialogViewModel)); + NavigateToSubPage(typeof(PackageInstallBrowserViewModel)); } private async Task CheckPackagesForUpdates() diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml similarity index 98% rename from StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml rename to StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml index 00ae0cb42..dc8ba2ca4 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/NewInstallerDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml @@ -10,10 +10,11 @@ xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" + xmlns:packageManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.PackageManager" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:DataType="dialogs:NewInstallerDialogViewModel" + x:DataType="packageManager:PackageInstallBrowserViewModel" d:DataContext="{x:Static mocks:DesignData.NewInstallerDialogViewModel}" - x:Class="StabilityMatrix.Avalonia.Views.Dialogs.NewInstallerDialog"> + x:Class="StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallBrowserView"> + x:Class="StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallDetailView"> diff --git a/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml.cs b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml.cs similarity index 81% rename from StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml.cs rename to StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml.cs index 0973e8144..606bef95a 100644 --- a/StabilityMatrix.Avalonia/Views/PackageInstallDetailView.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml.cs @@ -1,7 +1,7 @@ using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Core.Attributes; -namespace StabilityMatrix.Avalonia.Views; +namespace StabilityMatrix.Avalonia.Views.PackageManager; [Transient] public partial class PackageInstallDetailView : UserControlBase From bc463dfbbff977b435439c54c2ef4105e11902fa Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 4 Jan 2024 09:58:59 +0800 Subject: [PATCH 111/276] Fix exit freeze on macos --- StabilityMatrix.Avalonia/App.axaml.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index 25a2d0e27..d4bba2018 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -590,6 +590,11 @@ public static void Shutdown(int exitCode = 0) { var result = lifetime.TryShutdown(exitCode); Debug.WriteLine($"Shutdown: {result}"); + + if (result) + { + Environment.Exit(exitCode); + } } catch (InvalidOperationException) { From bd128a09367c0726b170493ec2f6a5a1e9015e07 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 4 Jan 2024 10:01:19 +0800 Subject: [PATCH 112/276] cleanup --- .../PackageManager/PackageInstallBrowserViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs index 44ce5d4c7..34d78439a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs @@ -33,7 +33,7 @@ public partial class PackageInstallBrowserViewModel : PageViewModelBase private readonly IPrerequisiteHelper prerequisiteHelper; [ObservableProperty] - private bool showIncompatiblePackages = false; + private bool showIncompatiblePackages; [ObservableProperty] private string searchFilter = string.Empty; @@ -113,7 +113,7 @@ IPrerequisiteHelper prerequisiteHelper public override string Title => "Add Package"; public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Add }; - public void OnPackageSelected(BaseGitPackage package) + public void OnPackageSelected(BaseGitPackage? package) { if (package is null) { From ae9a9d3f61a0aca632618650dde32fd7342d8fc8 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 4 Jan 2024 11:17:33 +0800 Subject: [PATCH 113/276] Fix ConnectionHelp navigation to installer --- .../Models/PackageManagerNavigationOptions.cs | 10 +++++++ .../InferenceConnectionHelpViewModel.cs | 17 +++++------ .../PackageInstallBrowserViewModel.cs | 2 +- .../PackageInstallDetailViewModel.cs | 4 +-- .../Views/NewPackageManagerPage.axaml.cs | 28 +++++++++++++++++++ .../Views/PackageManagerPage.axaml.cs | 8 +----- 6 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Models/PackageManagerNavigationOptions.cs diff --git a/StabilityMatrix.Avalonia/Models/PackageManagerNavigationOptions.cs b/StabilityMatrix.Avalonia/Models/PackageManagerNavigationOptions.cs new file mode 100644 index 000000000..18982f9ad --- /dev/null +++ b/StabilityMatrix.Avalonia/Models/PackageManagerNavigationOptions.cs @@ -0,0 +1,10 @@ +using StabilityMatrix.Core.Models.Packages; + +namespace StabilityMatrix.Avalonia.Models; + +public record PackageManagerNavigationOptions +{ + public bool OpenInstallerDialog { get; init; } + + public BasePackage? InstallerSelectedPackage { get; init; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/InferenceConnectionHelpViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/InferenceConnectionHelpViewModel.cs index aad4cc87c..fafd12065 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/InferenceConnectionHelpViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/InferenceConnectionHelpViewModel.cs @@ -8,6 +8,7 @@ using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Languages; +using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.Views; @@ -65,8 +66,9 @@ IPackageFactory packageFactory this.packageFactory = packageFactory; // Get comfy type installed packages - var comfyPackages = this.settingsManager.Settings.InstalledPackages - .Where(p => p.PackageName == "ComfyUI") + var comfyPackages = this.settingsManager.Settings.InstalledPackages.Where( + p => p.PackageName == "ComfyUI" + ) .ToImmutableArray(); InstalledPackages = comfyPackages; @@ -103,13 +105,14 @@ private void NavigateToInstall() { Dispatcher.UIThread.Post(() => { - navigationService.NavigateTo( - param: new PackageManagerPage.PackageManagerNavigationOptions + navigationService.NavigateTo( + param: new PackageManagerNavigationOptions { OpenInstallerDialog = true, InstallerSelectedPackage = packageFactory .GetAllAvailablePackages() - .First(p => p is ComfyUI) + .OfType() + .First() } ); }); @@ -138,9 +141,7 @@ public BetterContentDialog CreateDialog() var dialog = new BetterContentDialog { Content = new InferenceConnectionHelpDialog { DataContext = this }, - PrimaryButtonCommand = IsInstallMode - ? NavigateToInstallCommand - : LaunchSelectedPackageCommand, + PrimaryButtonCommand = IsInstallMode ? NavigateToInstallCommand : LaunchSelectedPackageCommand, PrimaryButtonText = IsInstallMode ? Resources.Action_Install : Resources.Action_Launch, CloseButtonText = Resources.Action_Close, DefaultButton = ContentDialogButton.Primary diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs index 34d78439a..e38770ace 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs @@ -113,7 +113,7 @@ IPrerequisiteHelper prerequisiteHelper public override string Title => "Add Package"; public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Add }; - public void OnPackageSelected(BaseGitPackage? package) + public void OnPackageSelected(BasePackage? package) { if (package is null) { diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index f6022e1ba..3c940d25a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -31,7 +31,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.PackageManager; [View(typeof(PackageInstallDetailView))] public partial class PackageInstallDetailViewModel( - BaseGitPackage package, + BasePackage package, ISettingsManager settingsManager, INotificationService notificationService, ILogger logger, @@ -40,7 +40,7 @@ public partial class PackageInstallDetailViewModel( INavigationService packageNavigationService ) : PageViewModelBase { - public BaseGitPackage SelectedPackage { get; } = package; + public BasePackage SelectedPackage { get; } = package; public override string Title { get; } = package.DisplayName; public override IconSource IconSource => new SymbolIconSource(); diff --git a/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs index a503d34a0..6fdeb5d4a 100644 --- a/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/NewPackageManagerPage.axaml.cs @@ -13,6 +13,7 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.PackageManager; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models; @@ -38,6 +39,8 @@ public NewPackageManagerPage(INavigationService pack InitializeComponent(); + AddHandler(Frame.NavigatedToEvent, OnNavigatedTo, RoutingStrategies.Direct); + packageNavigationService.SetFrame(FrameView); packageNavigationService.TypedNavigation += NavigationService_OnTypedNavigation; FrameView.Navigated += FrameView_Navigated; @@ -64,6 +67,31 @@ protected override void OnLoaded(RoutedEventArgs e) } } + /// + /// Handle navigation events to this page + /// + private void OnNavigatedTo(object? sender, NavigationEventArgs args) + { + if (args.Parameter is PackageManagerNavigationOptions { OpenInstallerDialog: true } options) + { + var vm = (NewPackageManagerViewModel)DataContext!; + + Dispatcher.UIThread.Post( + () => + { + // Navigate to the installer page + packageNavigationService.NavigateTo(); + + // Select the package + vm.SubPages.OfType() + .First() + .OnPackageSelected(options.InstallerSelectedPackage); + }, + DispatcherPriority.Send + ); + } + } + private void NavigationService_OnTypedNavigation(object? sender, TypedNavigationEventArgs e) { ViewModel.CurrentPage = diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs index e017decf3..cca1d38a1 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs @@ -4,6 +4,7 @@ using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Navigation; using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Models.Packages; @@ -39,11 +40,4 @@ private void OnNavigatedTo(object? sender, NavigationEventArgs args) }); } } - - public record PackageManagerNavigationOptions - { - public bool OpenInstallerDialog { get; init; } - - public BasePackage? InstallerSelectedPackage { get; init; } - } } From 871a0cda5cab79fba0046cd9f8559b5fe26a393f Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 3 Jan 2024 21:50:02 -0800 Subject: [PATCH 114/276] - Added `--use-directml` launch argument for SDWebUI DirectML fork - Changed default Period to "AllTime" in the Model Browser - Fixed SDTurboScheduler's missing denoise parameter --- .../CivitAiBrowserViewModel.cs | 57 +++++++++++++++---- .../InferenceTextToImageViewModel.cs | 8 +++ .../Inference/SamplerCardViewModel.cs | 18 ++++-- .../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 45 ++++++++++++--- .../Packages/StableDiffusionDirectMl.cs | 28 +++++++-- 5 files changed, 128 insertions(+), 28 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index 2d9cef4bf..2911dc6be 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -72,7 +72,7 @@ private LRUCache< private bool showMainLoadingSpinner; [ObservableProperty] - private CivitPeriod selectedPeriod = CivitPeriod.Month; + private CivitPeriod selectedPeriod = CivitPeriod.AllTime; [ObservableProperty] private CivitSortMode sortMode = CivitSortMode.HighestRated; @@ -118,8 +118,10 @@ private LRUCache< private List allModelCards = new(); - public IEnumerable AllCivitPeriods => Enum.GetValues(typeof(CivitPeriod)).Cast(); - public IEnumerable AllSortModes => Enum.GetValues(typeof(CivitSortMode)).Cast(); + public IEnumerable AllCivitPeriods => + Enum.GetValues(typeof(CivitPeriod)).Cast(); + public IEnumerable AllSortModes => + Enum.GetValues(typeof(CivitSortMode)).Cast(); public IEnumerable AllModelTypes => Enum.GetValues(typeof(CivitModelType)) @@ -128,7 +130,17 @@ private LRUCache< .OrderBy(t => t.ToString()); public List BaseModelOptions => - ["All", "SD 1.5", "SD 1.5 LCM", "SD 2.1", "SDXL 0.9", "SDXL 1.0", "SDXL 1.0 LCM", "SDXL Turbo", "Other"]; + [ + "All", + "SD 1.5", + "SD 1.5 LCM", + "SD 2.1", + "SDXL 0.9", + "SDXL 1.0", + "SDXL 1.0 LCM", + "SDXL Turbo", + "Other" + ]; public CivitAiBrowserViewModel( ICivitApi civitApi, @@ -189,7 +201,11 @@ public override void OnLoaded() ShowNsfw = settingsManager.Settings.ModelBrowserNsfwEnabled; - settingsManager.RelayPropertyFor(this, model => model.ShowNsfw, settings => settings.ModelBrowserNsfwEnabled); + settingsManager.RelayPropertyFor( + this, + model => model.ShowNsfw, + settings => settings.ModelBrowserNsfwEnabled + ); } /// @@ -238,7 +254,10 @@ private async Task CivitModelQuery(CivitModelsRequest request) } // Filter out unknown model types and archived/taken-down models - models = models.Where(m => m.Type.ConvertTo() > 0).Where(m => m.Mode == null).ToList(); + models = models + .Where(m => m.Type.ConvertTo() > 0) + .Where(m => m.Mode == null) + .ToList(); // Database update calls will invoke `OnModelsUpdated` // Add to database @@ -451,8 +470,7 @@ private async Task SearchModels() try { cachedQuery = await liteDbContext - .CivitModelQueryCache - .IncludeAll() + .CivitModelQueryCache.IncludeAll() .FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest)); } catch (Exception e) @@ -556,7 +574,12 @@ partial void OnSelectedPeriodChanged(CivitPeriod value) TrySearchAgain().SafeFireAndForget(); settingsManager.Transaction( s => - s.ModelSearchOptions = new ModelSearchOptions(value, SortMode, SelectedModelType, SelectedBaseModelType) + s.ModelSearchOptions = new ModelSearchOptions( + value, + SortMode, + SelectedModelType, + SelectedBaseModelType + ) ); } @@ -578,7 +601,13 @@ partial void OnSelectedModelTypeChanged(CivitModelType value) { TrySearchAgain().SafeFireAndForget(); settingsManager.Transaction( - s => s.ModelSearchOptions = new ModelSearchOptions(SelectedPeriod, SortMode, value, SelectedBaseModelType) + s => + s.ModelSearchOptions = new ModelSearchOptions( + SelectedPeriod, + SortMode, + value, + SelectedBaseModelType + ) ); } @@ -586,7 +615,13 @@ partial void OnSelectedBaseModelTypeChanged(string value) { TrySearchAgain().SafeFireAndForget(); settingsManager.Transaction( - s => s.ModelSearchOptions = new ModelSearchOptions(SelectedPeriod, SortMode, SelectedModelType, value) + s => + s.ModelSearchOptions = new ModelSearchOptions( + SelectedPeriod, + SortMode, + SelectedModelType, + value + ) ); } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 1c0caa13a..052986be9 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -114,6 +114,14 @@ IModelIndexService modelIndexService SamplerCardViewModel.IsRefinerStepsEnabled = e.Sender is { IsRefinerSelectionEnabled: true, SelectedRefiner: not null }; }); + + SamplerCardViewModel + .WhenPropertyChanged(x => x.SelectedScheduler) + .Subscribe(e => + { + e.Sender.IsDenoiseStrengthEnabled = + e.Sender.SelectedScheduler?.DisplayName.Equals("SD Turbo") ?? false; + }); } /// diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index a129696f0..96b9de362 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -88,7 +88,10 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo private int TotalSteps => Steps + RefinerSteps; - public SamplerCardViewModel(IInferenceClientManager clientManager, ServiceManager vmFactory) + public SamplerCardViewModel( + IInferenceClientManager clientManager, + ServiceManager vmFactory + ) { ClientManager = clientManager; ModulesCardViewModel = vmFactory.Get(modulesCard => @@ -102,7 +105,10 @@ public SamplerCardViewModel(IInferenceClientManager clientManager, ServiceManage public void ApplyStep(ModuleApplyStepEventArgs e) { // Resample the current primary if size does not match the selected size - if (e.Builder.Connections.PrimarySize.Width != Width || e.Builder.Connections.PrimarySize.Height != Height) + if ( + e.Builder.Connections.PrimarySize.Width != Width + || e.Builder.Connections.PrimarySize.Height != Height + ) { e.Builder.Connections.Primary = e.Builder.Group_Upscale( e.Nodes.GetUniqueName("Sampler_ScalePrimary"), @@ -170,7 +176,8 @@ private void ApplyStepsInitialSampler(ModuleApplyStepEventArgs e) { Name = "SDTurboScheduler", Model = e.Builder.Connections.Base.Model.Unwrap(), - Steps = Steps + Steps = Steps, + Denoise = DenoiseStrength } ); @@ -297,7 +304,10 @@ public void LoadStateFromParameters(GenerationParameters parameters) if ( !string.IsNullOrEmpty(parameters.Sampler) - && GenerationParametersConverter.TryGetSamplerScheduler(parameters.Sampler, out var samplerScheduler) + && GenerationParametersConverter.TryGetSamplerScheduler( + parameters.Sampler, + out var samplerScheduler + ) ) { SelectedSampler = ClientManager.Samplers.FirstOrDefault(s => s == samplerScheduler.Sampler); diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index 45f847fb1..874397ef6 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -110,6 +110,9 @@ public record SDTurboScheduler : ComfyTypedNodeBase [Range(1, 10)] public required int Steps { get; init; } + + [Range(0, 1.0)] + public required double Denoise { get; init; } } public record EmptyLatentImage : ComfyTypedNodeBase @@ -155,7 +158,11 @@ ImageNodeConnection image return new NamedComfyNode(name) { ClassType = "ImageUpscaleWithModel", - Inputs = new Dictionary { ["upscale_model"] = upscaleModel.Data, ["image"] = image.Data } + Inputs = new Dictionary + { + ["upscale_model"] = upscaleModel.Data, + ["image"] = image.Data + } }; } @@ -286,7 +293,8 @@ public record ControlNetLoader : ComfyTypedNodeBase public required string ControlNetName { get; init; } } - public record ControlNetApplyAdvanced : ComfyTypedNodeBase + public record ControlNetApplyAdvanced + : ComfyTypedNodeBase { public required ConditioningNodeConnection Positive { get; init; } public required ConditioningNodeConnection Negative { get; init; } @@ -409,7 +417,9 @@ int height .Output, image => Nodes - .AddNamedNode(ImageScale($"{name}_ImageUpscale", image, upscaleInfo.Name, height, width, false)) + .AddNamedNode( + ImageScale($"{name}_ImageUpscale", image, upscaleInfo.Name, height, width, false) + ) .Output ); } @@ -420,7 +430,11 @@ int height var samplerImage = GetPrimaryAsImage(primary, vae); // Do group upscale - var modelUpscaler = Group_UpscaleWithModel($"{name}_ModelUpscale", upscaleInfo.Name, samplerImage); + var modelUpscaler = Group_UpscaleWithModel( + $"{name}_ModelUpscale", + upscaleInfo.Name, + samplerImage + ); // Since the model upscale is fixed to model (2x/4x), scale it again to the requested size var resizedScaled = Nodes.AddNamedNode( @@ -476,7 +490,11 @@ int height ); // Do group upscale - var modelUpscaler = Group_UpscaleWithModel($"{name}_ModelUpscale", upscaleInfo.Name, samplerImage.Output); + var modelUpscaler = Group_UpscaleWithModel( + $"{name}_ModelUpscale", + upscaleInfo.Name, + samplerImage.Output + ); // Since the model upscale is fixed to model (2x/4x), scale it again to the requested size var resizedScaled = Nodes.AddNamedNode( @@ -550,7 +568,11 @@ int height ); // Do group upscale - var modelUpscaler = Group_UpscaleWithModel($"{name}_ModelUpscale", upscaleInfo.Name, samplerImage.Output); + var modelUpscaler = Group_UpscaleWithModel( + $"{name}_ModelUpscale", + upscaleInfo.Name, + samplerImage.Output + ); // Since the model upscale is fixed to model (2x/4x), scale it again to the requested size var resizedScaled = Nodes.AddNamedNode( @@ -750,7 +772,10 @@ public ImageNodeConnection GetPrimaryAsImage(VAENodeConnection vae) return Connections.Primary.AsT1; } - return GetPrimaryAsImage(Connections.Primary ?? throw new NullReferenceException("No primary connection"), vae); + return GetPrimaryAsImage( + Connections.Primary ?? throw new NullReferenceException("No primary connection"), + vae + ); } /// @@ -771,7 +796,7 @@ public class NodeBuilderConnections public ClipNodeConnection? BaseClip { get; set; } public ClipVisionNodeConnection? BaseClipVision { get; set; } - + public Dictionary Models { get; } = new() { ["Base"] = new ModelConnections("Base"), ["Refiner"] = new ModelConnections("Refiner") }; @@ -796,7 +821,9 @@ public class NodeBuilderConnections public ModelNodeConnection GetRefinerOrBaseModel() { - return Refiner.Model ?? Base.Model ?? throw new NullReferenceException("No Refiner or Base Model"); + return Refiner.Model + ?? Base.Model + ?? throw new NullReferenceException("No Refiner or Base Model"); } public ConditioningConnections GetRefinerOrBaseConditioning() diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs index 34321d044..b1687c333 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs @@ -1,10 +1,8 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; -using NLog; +using NLog; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; +using StabilityMatrix.Core.Helper.HardwareInfo; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; @@ -38,9 +36,31 @@ IPrerequisiteHelper prerequisiteHelper public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Recommended; + public override List LaunchOptions + { + get + { + var baseLaunchOptions = base.LaunchOptions; + baseLaunchOptions.Insert( + 0, + new LaunchOptionDefinition + { + Name = "Use DirectML", + Type = LaunchOptionType.Bool, + InitialValue = HardwareHelper.PreferDirectML(), + Options = ["--use-directml"] + } + ); + + return baseLaunchOptions; + } + } + public override IEnumerable AvailableTorchVersions => new[] { TorchVersion.Cpu, TorchVersion.DirectMl }; + public override TorchVersion GetRecommendedTorchVersion() => TorchVersion.DirectMl; + public override bool ShouldIgnoreReleases => true; public override async Task InstallPackage( From 04e38d2fdcae27524d964494eb8d04751d474f70 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 3 Jan 2024 21:52:27 -0800 Subject: [PATCH 115/276] chagenlog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44c7e891b..ed41a71ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.8.0-dev.4 ### Added - Auto-update support for macOS +- New package installation flow +- Added `--use-directml` launch argument for SDWebUI DirectML fork +### Changed +- Changed default Period to "AllTime" in the Model Browser +### Fixed +- Fixed SDTurboScheduler's missing denoise parameter ## v2.8.0-dev.3 ### Added From fc6ef780e74ebc771fbb3104bde0e7e0afb6f24a Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 3 Jan 2024 22:44:13 -0800 Subject: [PATCH 116/276] fix build errors --- .../Dialogs/SelectModelVersionViewModel.cs | 2 ++ .../Packages/StableDiffusionDirectMl.cs | 23 ------------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs index 2f7907613..ef7c2ddf6 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Threading.Tasks; using Avalonia.Controls.Notifications; @@ -15,6 +16,7 @@ using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs index c86db42be..341f62d0a 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs @@ -31,7 +31,6 @@ IPrerequisiteHelper prerequisiteHelper public override string LaunchCommand => "launch.py"; public override Uri PreviewImageUri => new("https://github.com/lshqqytiger/stable-diffusion-webui-directml/raw/master/screenshot.png"); - public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink; public override TorchVersion GetRecommendedTorchVersion() => TorchVersion.DirectMl; @@ -61,30 +60,8 @@ public override List LaunchOptions public override IEnumerable AvailableTorchVersions => new[] { TorchVersion.Cpu, TorchVersion.DirectMl }; - public override TorchVersion GetRecommendedTorchVersion() => TorchVersion.DirectMl; - public override bool ShouldIgnoreReleases => true; - public override List LaunchOptions - { - get - { - var baseLaunchOptions = base.LaunchOptions; - baseLaunchOptions.Insert( - 0, - new LaunchOptionDefinition - { - Name = "Use DirectML", - Type = LaunchOptionType.Bool, - InitialValue = HardwareHelper.PreferDirectML(), - Options = ["--use-directml"] - } - ); - - return baseLaunchOptions; - } - } - public override async Task InstallPackage( string installLocation, TorchVersion torchVersion, From 36848899f001d51b53e014ba1904ddc8e97e8907 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 4 Jan 2024 18:07:59 +0800 Subject: [PATCH 117/276] Add Move and Copy methods for DirectoryPath --- .../Models/FileInterfaces/DirectoryPath.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs index 088cf592c..d07f18dc5 100644 --- a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs +++ b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs @@ -125,6 +125,98 @@ public Task GetSizeAsync(bool includeSymbolicLinks) /// public Task DeleteAsync(bool recursive) => Task.Run(() => Delete(recursive)); + private void ThrowIfNotExists() + { + if (!Exists) + { + throw new DirectoryNotFoundException($"Directory not found: {FullPath}"); + } + } + + public void CopyTo(DirectoryPath destinationDir, bool recursive = true) + { + ThrowIfNotExists(); + + // Cache directories before we start copying + var dirs = EnumerateDirectories().ToList(); + + destinationDir.Create(); + + // Get the files in the source directory and copy to the destination directory + foreach (var file in EnumerateFiles()) + { + var targetFilePath = destinationDir.JoinFile(file.Name); + file.CopyTo(targetFilePath); + } + + // If recursive and copying subdirectories, recursively call this method + if (recursive) + { + foreach (var subDir in dirs) + { + var targetDirectory = destinationDir.JoinDir(subDir.Name); + subDir.CopyTo(targetDirectory); + } + } + } + + public async Task CopyToAsync(DirectoryPath destinationDir, bool recursive = true) + { + ThrowIfNotExists(); + + // Cache directories before we start copying + var dirs = EnumerateDirectories().ToList(); + + destinationDir.Create(); + + // Get the files in the source directory and copy to the destination directory + foreach (var file in EnumerateFiles()) + { + var targetFilePath = destinationDir.JoinFile(file.Name); + await file.CopyToAsync(targetFilePath).ConfigureAwait(false); + } + + // If recursive and copying subdirectories, recursively call this method + if (recursive) + { + foreach (var subDir in dirs) + { + var targetDirectory = destinationDir.JoinDir(subDir.Name); + await subDir.CopyToAsync(targetDirectory).ConfigureAwait(false); + } + } + } + + /// + /// Move the directory to a destination path. + /// + public DirectoryPath MoveTo(DirectoryPath destinationDir) + { + Info.MoveTo(destinationDir.FullPath); + // Return the new path + return destinationDir; + } + + /// + /// Move the file to a target path. + /// + public async Task MoveToAsync(DirectoryPath destinationDir) + { + await Task.Run(() => Info.MoveTo(destinationDir.FullPath)).ConfigureAwait(false); + // Return the new path + return destinationDir; + } + + /// + /// Move the directory to a destination path as a subfolder with the current name. + /// + public async Task MoveToDirectoryAsync(DirectoryPath destinationParentDir) + { + await Task.Run(() => Info.MoveTo(destinationParentDir.JoinDir(Name))).ConfigureAwait(false); + // Return the new path + return destinationParentDir.JoinDir(this); + } + /// /// Join with other paths to form a new directory path. /// From 9fe0ef8689713ba29844e0f70acef5e53d4a25c7 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 4 Jan 2024 21:43:51 +0800 Subject: [PATCH 118/276] macos update compat fixes --- StabilityMatrix.Avalonia/Program.cs | 55 +++++++++++++++---- .../ViewModels/Dialogs/UpdateViewModel.cs | 20 +++++-- .../Settings/MainSettingsViewModel.cs | 6 +- StabilityMatrix.Core/Helper/Compat.cs | 49 +++++++++++++---- .../Models/FileInterfaces/DirectoryPath.cs | 13 +++++ .../Processes/ProcessRunner.cs | 30 +++++++++- StabilityMatrix.Core/Updater/UpdateHelper.cs | 39 +++++++------ 7 files changed, 166 insertions(+), 46 deletions(-) diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 357771679..40d8531c5 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -25,6 +25,7 @@ using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Updater; namespace StabilityMatrix.Avalonia; @@ -55,8 +56,7 @@ public static void Main(string[] args) SetDebugBuild(); var parseResult = Parser - .Default - .ParseArguments(args) + .Default.ParseArguments(args) .WithNotParsed(errors => { foreach (var error in errors) @@ -147,7 +147,10 @@ public static AppBuilder BuildAvaloniaApp() if (Args.UseOpenGlRendering) { app = app.With( - new Win32PlatformOptions { RenderingMode = [Win32RenderingMode.Wgl, Win32RenderingMode.Software] } + new Win32PlatformOptions + { + RenderingMode = [Win32RenderingMode.Wgl, Win32RenderingMode.Software] + } ); } @@ -156,7 +159,10 @@ public static AppBuilder BuildAvaloniaApp() app = app.With(new Win32PlatformOptions { RenderingMode = new[] { Win32RenderingMode.Software } }) .With(new X11PlatformOptions { RenderingMode = new[] { X11RenderingMode.Software } }) .With( - new AvaloniaNativePlatformOptions { RenderingMode = new[] { AvaloniaNativeRenderingMode.Software } } + new AvaloniaNativePlatformOptions + { + RenderingMode = new[] { AvaloniaNativeRenderingMode.Software } + } ); } @@ -173,8 +179,6 @@ private static void HandleUpdateReplacement() return; // Copy our current file to the parent directory, overwriting the old app file - var currentExe = Compat.AppCurrentDir.JoinFile(Compat.GetExecutableName()); - var targetExe = parentDir.JoinFile(Compat.GetExecutableName()); var isCopied = false; @@ -188,7 +192,27 @@ var delay in Backoff.DecorrelatedJitterBackoffV2( { try { - currentExe.CopyTo(targetExe, true); + if (Compat.IsMacOS) + { + var currentApp = Compat.AppBundleCurrentPath!; + var targetApp = parentDir.JoinDir(Compat.GetAppName()); + + // Since macOS has issues with signature caching, delete the target app first + if (targetApp.Exists) + { + targetApp.Delete(true); + } + + currentApp.CopyTo(targetApp); + } + else + { + var currentExe = Compat.AppCurrentPath; + var targetExe = parentDir.JoinFile(Compat.GetExecutableName()); + + currentExe.CopyTo(targetExe, true); + } + isCopied = true; break; } @@ -204,11 +228,13 @@ var delay in Backoff.DecorrelatedJitterBackoffV2( Environment.Exit(1); } + var targetAppOrBundle = Path.Combine(parentDir, Compat.GetAppName()); + // Ensure permissions are set for unix if (Compat.IsUnix) { File.SetUnixFileMode( - targetExe, // 0755 + targetAppOrBundle, // 0755 UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute @@ -220,7 +246,10 @@ var delay in Backoff.DecorrelatedJitterBackoffV2( } // Start the new app while passing our own PID to wait for exit - Process.Start(targetExe, $"--wait-for-exit-pid {Environment.ProcessId}"); + ProcessRunner.StartApp( + targetAppOrBundle, + new[] { "--wait-for-exit-pid", $"{Environment.ProcessId}" } + ); // Shutdown the current app Environment.Exit(0); @@ -274,7 +303,8 @@ private static void ConfigureSentry() { SentrySdk.Init(o => { - o.Dsn = "https://eac7a5ea065d44cf9a8565e0f1817da2@o4505314753380352.ingest.sentry.io/4505314756067328"; + o.Dsn = + "https://eac7a5ea065d44cf9a8565e0f1817da2@o4505314753380352.ingest.sentry.io/4505314756067328"; o.StackTraceMode = StackTraceMode.Enhanced; o.TracesSampleRate = 1.0; o.IsGlobalModeEnabled = true; @@ -301,7 +331,10 @@ private static void ConfigureSentry() }); } - private static void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) + private static void TaskScheduler_UnobservedTaskException( + object? sender, + UnobservedTaskExceptionEventArgs e + ) { if (e.Exception is Exception ex) { diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs index 8a5dae665..2c67e9f5c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs @@ -18,6 +18,7 @@ using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Models.Update; +using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; using StabilityMatrix.Core.Updater; @@ -156,7 +157,7 @@ await updateHelper.DownloadUpdate( if (Compat.IsUnix) { File.SetUnixFileMode( - UpdateHelper.ExecutablePath, // 0755 + UpdateHelper.ExecutablePath.FullPath, // 0755 UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute @@ -170,7 +171,13 @@ await updateHelper.DownloadUpdate( UpdateText = "Getting a few things ready..."; await using (new MinimumDelay(500, 1000)) { - Process.Start(UpdateHelper.ExecutablePath, $"--wait-for-exit-pid {Environment.ProcessId}"); + await Task.Run(() => + { + ProcessRunner.StartApp( + UpdateHelper.ExecutablePath.FullPath, + new[] { "--wait-for-exit-pid", $"{Environment.ProcessId}" } + ); + }); } UpdateText = "Update complete. Restarting Stability Matrix in 3 seconds..."; @@ -259,7 +266,10 @@ out var version var currentVersionBlock = results.FindIndex(x => x.Version == currentVersion.WithoutMetadata()); // For mismatching build metadata, add one - if (currentVersionBlock != -1 && results[currentVersionBlock].Version?.Metadata != currentVersion.Metadata) + if ( + currentVersionBlock != -1 + && results[currentVersionBlock].Version?.Metadata != currentVersion.Metadata + ) { currentVersionBlock++; } @@ -267,7 +277,9 @@ out var version // Support for previous pre-release without changelogs if (currentVersionBlock == -1) { - currentVersionBlock = results.FindIndex(x => x.Version == currentVersion.WithoutPrereleaseOrMetadata()); + currentVersionBlock = results.FindIndex( + x => x.Version == currentVersion.WithoutPrereleaseOrMetadata() + ); // Add 1 if found to include the current release if (currentVersionBlock != -1) diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs index cfc781dba..97cad1f09 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs @@ -51,6 +51,7 @@ using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Settings; +using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; @@ -302,7 +303,10 @@ partial void OnSelectedLanguageChanged(CultureInfo? oldValue, CultureInfo newVal { if (await dialog.ShowAsync() == ContentDialogResult.Primary) { - Process.Start(Compat.AppCurrentPath); + // Start the new app while passing our own PID to wait for exit + Process.Start(Compat.AppCurrentPath, $"--wait-for-exit-pid {Environment.ProcessId}"); + + // Shutdown the current app App.Shutdown(); } }); diff --git a/StabilityMatrix.Core/Helper/Compat.cs b/StabilityMatrix.Core/Helper/Compat.cs index 9a014424a..9e4b352f0 100644 --- a/StabilityMatrix.Core/Helper/Compat.cs +++ b/StabilityMatrix.Core/Helper/Compat.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; using Semver; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models.FileInterfaces; namespace StabilityMatrix.Core.Helper; @@ -62,10 +63,21 @@ public static void SetAppDataHome(string path) public static DirectoryPath AppCurrentDir { get; } /// - /// Current path to the app. + /// Current path to the app binary. /// public static FilePath AppCurrentPath => AppCurrentDir.JoinFile(GetExecutableName()); + /// + /// Path to the .app bundle on macOS. + /// + [SupportedOSPlatform("macos")] + public static DirectoryPath? AppBundleCurrentPath { get; } + + /// + /// Either the File or directory on macOS. + /// + public static FileSystemPath AppOrBundleCurrentPath => IsMacOS ? AppBundleCurrentPath! : AppCurrentPath; + // File extensions /// /// Platform-specific executable extension. @@ -103,7 +115,14 @@ static Compat() else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { Platform = PlatformKind.MacOS | PlatformKind.Unix; - AppCurrentDir = AppContext.BaseDirectory; // TODO: check this + + // This is ./.app/Contents/MacOS + var macDir = new DirectoryPath(AppContext.BaseDirectory); + // We need to go up two directories to get the .app directory + AppBundleCurrentPath = macDir.Parent?.Parent; + // Then CurrentDir is the next parent + AppCurrentDir = AppBundleCurrentPath!.Parent!; + ExeExtension = ""; DllExtension = ".dylib"; } @@ -112,11 +131,9 @@ static Compat() Platform = PlatformKind.Linux | PlatformKind.Unix; // For AppImage builds, the path is in `$APPIMAGE` - var appPath = - Environment.GetEnvironmentVariable("APPIMAGE") ?? AppContext.BaseDirectory; + var appPath = Environment.GetEnvironmentVariable("APPIMAGE") ?? AppContext.BaseDirectory; AppCurrentDir = - Path.GetDirectoryName(appPath) - ?? throw new Exception("Could not find application directory"); + Path.GetDirectoryName(appPath) ?? throw new Exception("Could not find application directory"); ExeExtension = ""; DllExtension = ".so"; } @@ -186,12 +203,24 @@ public static string GetExecutableName() return Path.GetFileName(fullPath); } + /// + /// Get the current application executable or bundle name. + /// + public static string GetAppName() + { + // For other platforms, this is the same as the executable name + if (!IsMacOS) + { + return GetExecutableName(); + } + + // On macOS, get name of current bundle + return Path.GetFileName(AppBundleCurrentPath.Unwrap()); + } + public static string GetEnvPathWithExtensions(params string[] paths) { - var currentPath = Environment.GetEnvironmentVariable( - "PATH", - EnvironmentVariableTarget.Process - ); + var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); var newPath = string.Join(PathDelimiter, paths); if (string.IsNullOrEmpty(currentPath)) diff --git a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs index d07f18dc5..fdca61d49 100644 --- a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs +++ b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs @@ -249,6 +249,19 @@ public IEnumerable EnumerateDirectories( Info.EnumerateDirectories(searchPattern, searchOption) .Select(directory => new DirectoryPath(directory)); + /// + /// Return a new with the given file name. + /// + public DirectoryPath WithName(string directoryName) + { + if (Path.GetDirectoryName(FullPath) is { } directory && !string.IsNullOrWhiteSpace(directory)) + { + return new DirectoryPath(directory, directoryName); + } + + return new DirectoryPath(directoryName); + } + public override string ToString() => FullPath; /// diff --git a/StabilityMatrix.Core/Processes/ProcessRunner.cs b/StabilityMatrix.Core/Processes/ProcessRunner.cs index 868eb2473..ed092b932 100644 --- a/StabilityMatrix.Core/Processes/ProcessRunner.cs +++ b/StabilityMatrix.Core/Processes/ProcessRunner.cs @@ -29,6 +29,27 @@ public static void OpenUrl(Uri url) OpenUrl(url.AbsoluteUri); } + /// + /// Start an executable or .app on macOS. + /// + public static Process StartApp(string path, ProcessArgs args) + { + if (Compat.IsMacOS) + { + var startInfo = new ProcessStartInfo + { + FileName = "open", + Arguments = args.Prepend([path, "--args"]), + UseShellExecute = true + }; + + return Process.Start(startInfo) + ?? throw new NullReferenceException("Process.Start returned null"); + } + + return Process.Start(args.Prepend(path)); + } + /// /// Opens the given folder in the system file explorer. /// @@ -372,7 +393,10 @@ public static async Task RunBashCommand(string command, string wo }; } - public static Task RunBashCommand(IEnumerable commands, string workingDirectory = "") + public static Task RunBashCommand( + IEnumerable commands, + string workingDirectory = "" + ) { // Quote arguments containing spaces var args = string.Join(" ", commands.Select(Quote)); @@ -421,7 +445,9 @@ public static async Task WaitForExitConditionAsync( catch (SystemException) { } throw new ProcessException( - "Process " + (processName == null ? "" : processName + " ") + $"failed with exit-code {process.ExitCode}." + "Process " + + (processName == null ? "" : processName + " ") + + $"failed with exit-code {process.ExitCode}." ); } } diff --git a/StabilityMatrix.Core/Updater/UpdateHelper.cs b/StabilityMatrix.Core/Updater/UpdateHelper.cs index eff50ce3c..d14291824 100644 --- a/StabilityMatrix.Core/Updater/UpdateHelper.cs +++ b/StabilityMatrix.Core/Updater/UpdateHelper.cs @@ -32,7 +32,10 @@ public class UpdateHelper : IUpdateHelper public const string UpdateFolderName = ".StabilityMatrixUpdate"; public static DirectoryPath UpdateFolder => Compat.AppCurrentDir.JoinDir(UpdateFolderName); - public static FilePath ExecutablePath => UpdateFolder.JoinFile(Compat.GetExecutableName()); + public static IPathObject ExecutablePath => + Compat.IsMacOS + ? UpdateFolder.JoinDir(Compat.GetAppName()) + : UpdateFolder.JoinFile(Compat.GetAppName()); /// public event EventHandler? UpdateStatusChanged; @@ -123,7 +126,7 @@ await downloadService .EnumerateFiles("*.*", SearchOption.AllDirectories) .First(f => f.Extension.ToLowerInvariant() is ".exe" or ".appimage"); - await binaryFile.MoveToAsync(ExecutablePath).ConfigureAwait(false); + await binaryFile.MoveToAsync((FilePath)ExecutablePath).ConfigureAwait(false); } else if (downloadFile.Extension == ".dmg") { @@ -139,9 +142,10 @@ await downloadService // Extract dmg contents await ArchiveHelper.ExtractDmg(downloadFile, extractDir).ConfigureAwait(false); - // Find app and move it up to the root - var appFile = extractDir.EnumerateFiles("*.app").First(); - await appFile.MoveToAsync(ExecutablePath).ConfigureAwait(false); + // Find app dir and move it up to the root + var appBundle = extractDir.EnumerateDirectories("*.app").First(); + + await appBundle.MoveToAsync((DirectoryPath)ExecutablePath).ConfigureAwait(false); } // Otherwise just rename else @@ -210,10 +214,10 @@ var channel in Enum.GetValues(typeof(UpdateChannel)) new UpdateStatusChangedEventArgs { LatestUpdate = update, - UpdateChannels = updateManifest.Updates.ToDictionary( - kv => kv.Key, - kv => kv.Value.GetInfoForCurrentPlatform() - )! + UpdateChannels = updateManifest + .Updates.Select(kv => (kv.Key, kv.Value.GetInfoForCurrentPlatform())) + .Where(kv => kv.Item2 is not null) + .ToDictionary(kv => kv.Item1, kv => kv.Item2)! } ); return; @@ -222,15 +226,14 @@ var channel in Enum.GetValues(typeof(UpdateChannel)) logger.LogInformation("No update available"); - OnUpdateStatusChanged( - new UpdateStatusChangedEventArgs - { - UpdateChannels = updateManifest.Updates.ToDictionary( - kv => kv.Key, - kv => kv.Value.GetInfoForCurrentPlatform() - )! - } - ); + var args = new UpdateStatusChangedEventArgs + { + UpdateChannels = updateManifest + .Updates.Select(kv => (kv.Key, kv.Value.GetInfoForCurrentPlatform())) + .Where(kv => kv.Item2 is not null) + .ToDictionary(kv => kv.Item1, kv => kv.Item2)! + }; + OnUpdateStatusChanged(args); } catch (Exception e) { From 8e728be4e33f35d231bd1d5e2775fc237d1966ad Mon Sep 17 00:00:00 2001 From: ionite34 Date: Fri, 5 Jan 2024 09:19:37 +0800 Subject: [PATCH 119/276] Fix comment --- StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs index 2c67e9f5c..13d84d896 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs @@ -157,7 +157,8 @@ await updateHelper.DownloadUpdate( if (Compat.IsUnix) { File.SetUnixFileMode( - UpdateHelper.ExecutablePath.FullPath, // 0755 + UpdateHelper.ExecutablePath.FullPath, + // 0755 UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute From 5cf8b053f63a597b5b0e416eb599ce20b032e5d0 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 6 Jan 2024 14:58:19 +0800 Subject: [PATCH 120/276] Add CheckIsGitRepository, fix vlad git impl --- .../Helpers/UnixPrerequisiteHelper.cs | 21 +++------ .../Helpers/WindowsPrerequisiteHelper.cs | 44 ++++-------------- .../Helper/IPrerequisiteHelper.cs | 17 ++++--- .../Models/Packages/VladAutomatic.cs | 46 +++++++++++++++---- 4 files changed, 63 insertions(+), 65 deletions(-) diff --git a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs index e31be0da0..911248574 100644 --- a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs @@ -66,15 +66,9 @@ public async Task InstallAllIfNecessary(IProgress? progress = nu public async Task UnpackResourcesIfNecessary(IProgress? progress = null) { // Array of (asset_uri, extract_to) - var assets = new[] - { - (Assets.SevenZipExecutable, AssetsDir), - (Assets.SevenZipLicense, AssetsDir), - }; + var assets = new[] { (Assets.SevenZipExecutable, AssetsDir), (Assets.SevenZipLicense, AssetsDir), }; - progress?.Report( - new ProgressReport(0, message: "Unpacking resources", isIndeterminate: true) - ); + progress?.Report(new ProgressReport(0, message: "Unpacking resources", isIndeterminate: true)); Directory.CreateDirectory(AssetsDir); foreach (var (asset, extractDir) in assets) @@ -82,9 +76,7 @@ public async Task UnpackResourcesIfNecessary(IProgress? progress await asset.ExtractToDir(extractDir); } - progress?.Report( - new ProgressReport(1, message: "Unpacking resources", isIndeterminate: false) - ); + progress?.Report(new ProgressReport(1, message: "Unpacking resources", isIndeterminate: false)); } public async Task InstallGitIfNecessary(IProgress? progress = null) @@ -146,8 +138,7 @@ public async Task RunGit(ProcessArgs args, string? workingDirectory = null) if (result.ExitCode != 0) { Logger.Error( - "Git command [{Command}] failed with exit code " - + "{ExitCode}:\n{StdOut}\n{StdErr}", + "Git command [{Command}] failed with exit code " + "{ExitCode}:\n{StdOut}\n{StdErr}", command, result.ExitCode, result.StandardOutput, @@ -235,9 +226,9 @@ public async Task InstallPythonIfNecessary(IProgress? progress = progress?.Report(new ProgressReport(1, "Installing Python", isIndeterminate: false)); } - public Task GetGitOutput(string? workingDirectory = null, params string[] args) + public Task GetGitOutput(ProcessArgs args, string? workingDirectory = null) { - throw new NotImplementedException(); + return ProcessRunner.RunBashCommand(args.Prepend("git").ToArray(), workingDirectory ?? ""); } [UnsupportedOSPlatform("Linux")] diff --git a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs index c6d007d02..923737836 100644 --- a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs @@ -96,19 +96,17 @@ public async Task RunGit(ProcessArgs args, string? workingDirectory = null) result.EnsureSuccessExitCode(); } - public async Task GetGitOutput(string? workingDirectory = null, params string[] args) + public Task GetGitOutput(ProcessArgs args, string? workingDirectory = null) { - var process = await ProcessRunner.GetProcessOutputAsync( + return ProcessRunner.GetProcessResultAsync( GitExePath, - string.Join(" ", args), + args, workingDirectory: workingDirectory, environmentVariables: new Dictionary { { "PATH", Compat.GetEnvPathWithExtensions(GitBinPath) } } ); - - return process; } public async Task InstallAllIfNecessary(IProgress? progress = null) @@ -122,15 +120,9 @@ public async Task InstallAllIfNecessary(IProgress? progress = nu public async Task UnpackResourcesIfNecessary(IProgress? progress = null) { // Array of (asset_uri, extract_to) - var assets = new[] - { - (Assets.SevenZipExecutable, AssetsDir), - (Assets.SevenZipLicense, AssetsDir), - }; + var assets = new[] { (Assets.SevenZipExecutable, AssetsDir), (Assets.SevenZipLicense, AssetsDir), }; - progress?.Report( - new ProgressReport(0, message: "Unpacking resources", isIndeterminate: true) - ); + progress?.Report(new ProgressReport(0, message: "Unpacking resources", isIndeterminate: true)); Directory.CreateDirectory(AssetsDir); foreach (var (asset, extractDir) in assets) @@ -138,9 +130,7 @@ public async Task UnpackResourcesIfNecessary(IProgress? progress await asset.ExtractToDir(extractDir); } - progress?.Report( - new ProgressReport(1, message: "Unpacking resources", isIndeterminate: false) - ); + progress?.Report(new ProgressReport(1, message: "Unpacking resources", isIndeterminate: false)); } public async Task InstallPythonIfNecessary(IProgress? progress = null) @@ -262,11 +252,7 @@ public async Task InstallTkinterIfNecessary(IProgress? progress if (!Directory.Exists(TkinterExistsPath)) { Logger.Info("Downloading Tkinter"); - await downloadService.DownloadToFileAsync( - TkinterDownloadUrl, - TkinterZipPath, - progress: progress - ); + await downloadService.DownloadToFileAsync(TkinterDownloadUrl, TkinterZipPath, progress: progress); progress?.Report( new ProgressReport( progress: 1f, @@ -281,11 +267,7 @@ await downloadService.DownloadToFileAsync( } progress?.Report( - new ProgressReport( - progress: 1f, - message: "Tkinter install complete", - type: ProgressType.Generic - ) + new ProgressReport(progress: 1f, message: "Tkinter install complete", type: ProgressType.Generic) ); } @@ -319,10 +301,7 @@ await downloadService.DownloadToFileAsync( public async Task InstallVcRedistIfNecessary(IProgress? progress = null) { var registry = Registry.LocalMachine; - var key = registry.OpenSubKey( - @"SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64", - false - ); + var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64", false); if (key != null) { var buildId = Convert.ToUInt32(key.GetValue("Bld")); @@ -356,10 +335,7 @@ await downloadService.DownloadToFileAsync( message: "Installing prerequisites..." ) ); - var process = ProcessRunner.StartAnsiProcess( - VcRedistDownloadPath, - "/install /quiet /norestart" - ); + var process = ProcessRunner.StartAnsiProcess(VcRedistDownloadPath, "/install /quiet /norestart"); await process.WaitForExitAsync(); progress?.Report( new ProgressReport( diff --git a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs index 6c9375840..3753e4bab 100644 --- a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs +++ b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs @@ -21,17 +21,22 @@ public interface IPrerequisiteHelper /// /// Run embedded git with the given arguments. /// - Task RunGit( - ProcessArgs args, - Action? onProcessOutput, - string? workingDirectory = null - ); + Task RunGit(ProcessArgs args, Action? onProcessOutput, string? workingDirectory = null); /// /// Run embedded git with the given arguments. /// Task RunGit(ProcessArgs args, string? workingDirectory = null); - Task GetGitOutput(string? workingDirectory = null, params string[] args); + Task GetGitOutput(ProcessArgs args, string? workingDirectory = null); + + async Task CheckIsGitRepository(string directory) + { + var result = await GetGitOutput(["rev-parse", "--is-inside-work-tree"], directory) + .ConfigureAwait(false); + + return result.ExitCode == 0 && result.StandardOutput?.Trim().ToLowerInvariant() == "true"; + } + Task InstallTkinterIfNecessary(IProgress? progress = null); } diff --git a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs index 383ace118..96b65c422 100644 --- a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs +++ b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs @@ -204,7 +204,9 @@ await venvRunner break; default: // CPU - await venvRunner.CustomInstall("launch.py --debug --test", onConsoleOutput).ConfigureAwait(false); + await venvRunner + .CustomInstall("launch.py --debug --test", onConsoleOutput) + .ConfigureAwait(false); break; } @@ -314,7 +316,11 @@ public override async Task Update( ); await PrerequisiteHelper - .RunGit(new[] { "checkout", versionOptions.BranchName! }, onConsoleOutput, installedPackage.FullPath) + .RunGit( + new[] { "checkout", versionOptions.BranchName! }, + onConsoleOutput, + installedPackage.FullPath + ) .ConfigureAwait(false); var venvRunner = new PyVenvRunner(Path.Combine(installedPackage.FullPath!, "venv")); @@ -325,14 +331,17 @@ await PrerequisiteHelper try { - var output = await PrerequisiteHelper - .GetGitOutput(installedPackage.FullPath, "rev-parse", "HEAD") + var result = await PrerequisiteHelper + .GetGitOutput(["rev-parse", "HEAD"], installedPackage.FullPath) + .EnsureSuccessExitCode() .ConfigureAwait(false); return new InstalledPackageVersion { InstalledBranch = versionOptions.BranchName, - InstalledCommitSha = output.Replace(Environment.NewLine, "").Replace("\n", ""), + InstalledCommitSha = result + .StandardOutput?.Replace(Environment.NewLine, "") + .Replace("\n", ""), IsPrerelease = false }; } @@ -343,7 +352,12 @@ await PrerequisiteHelper finally { progress?.Report( - new ProgressReport(1f, message: "Update Complete", isIndeterminate: false, type: ProgressType.Update) + new ProgressReport( + 1f, + message: "Update Complete", + isIndeterminate: false, + type: ProgressType.Update + ) ); } @@ -354,7 +368,10 @@ await PrerequisiteHelper }; } - public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) + public override Task SetupModelFolders( + DirectoryPath installDirectory, + SharedFolderMethod sharedFolderMethod + ) { switch (sharedFolderMethod) { @@ -404,13 +421,19 @@ public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFol configRoot["clip_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "CLIP"); configRoot["control_net_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "ControlNet"); - var configJsonStr = JsonSerializer.Serialize(configRoot, new JsonSerializerOptions { WriteIndented = true }); + var configJsonStr = JsonSerializer.Serialize( + configRoot, + new JsonSerializerOptions { WriteIndented = true } + ); File.WriteAllText(configJsonPath, configJsonStr); return Task.CompletedTask; } - public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => + public override Task UpdateModelFolders( + DirectoryPath installDirectory, + SharedFolderMethod sharedFolderMethod + ) => sharedFolderMethod switch { SharedFolderMethod.Symlink => base.UpdateModelFolders(installDirectory, sharedFolderMethod), @@ -476,7 +499,10 @@ private Task RemoveConfigSettings(string installDirectory) configRoot.Remove("clip_models_path"); configRoot.Remove("control_net_models_path"); - var configJsonStr = JsonSerializer.Serialize(configRoot, new JsonSerializerOptions { WriteIndented = true }); + var configJsonStr = JsonSerializer.Serialize( + configRoot, + new JsonSerializerOptions { WriteIndented = true } + ); File.WriteAllText(configJsonPath, configJsonStr); return Task.CompletedTask; From 332f39725f50187a352dbb1e6f3394a751c729b4 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 6 Jan 2024 17:35:15 +0800 Subject: [PATCH 121/276] Add DownloadService.GetContentAsync --- StabilityMatrix.Core/Services/DownloadService.cs | 12 ++++++++++++ StabilityMatrix.Core/Services/IDownloadService.cs | 2 ++ 2 files changed, 14 insertions(+) diff --git a/StabilityMatrix.Core/Services/DownloadService.cs b/StabilityMatrix.Core/Services/DownloadService.cs index dffbb79c8..60adf231f 100644 --- a/StabilityMatrix.Core/Services/DownloadService.cs +++ b/StabilityMatrix.Core/Services/DownloadService.cs @@ -305,6 +305,18 @@ var delay in Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(50), } } + public async Task GetContentAsync(string url, CancellationToken cancellationToken = default) + { + using var client = httpClientFactory.CreateClient(); + client.Timeout = TimeSpan.FromSeconds(10); + client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StabilityMatrix", "2.0")); + + await AddConditionalHeaders(client, new Uri(url)).ConfigureAwait(false); + + var response = await client.GetAsync(url, cancellationToken).ConfigureAwait(false); + return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + } + /// /// Adds conditional headers to the HttpClient for the given URL /// diff --git a/StabilityMatrix.Core/Services/IDownloadService.cs b/StabilityMatrix.Core/Services/IDownloadService.cs index 883b1542a..2223c25c6 100644 --- a/StabilityMatrix.Core/Services/IDownloadService.cs +++ b/StabilityMatrix.Core/Services/IDownloadService.cs @@ -28,4 +28,6 @@ Task GetFileSizeAsync( ); Task GetImageStreamFromUrl(string url); + + Task GetContentAsync(string url, CancellationToken cancellationToken = default); } From 137eca49500382bc03c024a68e50fab96eeddd51 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sat, 6 Jan 2024 17:35:44 +0800 Subject: [PATCH 122/276] Add extension management backends --- .../ViewModels/ExtensionViewModel.cs | 2 +- .../Helper/IPrerequisiteHelper.cs | 88 ++++++++++- .../Helper/PrerequisiteHelper.cs | 33 ++-- StabilityMatrix.Core/Models/GitVersion.cs | 13 ++ .../InstallExtensionStep.cs | 19 ++- .../Models/Packages/BasePackage.cs | 14 +- .../Models/Packages/ComfyUI.cs | 36 +++++ .../Extensions/ComfyExtensionManifest.cs | 43 ++++++ .../Packages/Extensions/ExtensionBase.cs | 24 --- .../Packages/Extensions/ExtensionManifest.cs | 3 + .../Extensions/GitPackageExtensionManager.cs | 144 ++++++++++++++++++ .../Extensions/IPackageExtensionManager.cs | 37 +++++ .../Extensions/InstalledPackageExtension.cs | 21 +++ .../Packages/Extensions/PackageExtension.cs | 16 ++ .../Extensions/PackageExtensionVersion.cs | 3 + 15 files changed, 441 insertions(+), 55 deletions(-) create mode 100644 StabilityMatrix.Core/Models/GitVersion.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/ComfyExtensionManifest.cs delete mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/ExtensionBase.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/ExtensionManifest.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/IPackageExtensionManager.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/PackageExtension.cs create mode 100644 StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs diff --git a/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs index 7db834341..b03988a59 100644 --- a/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs @@ -9,5 +9,5 @@ public partial class ExtensionViewModel() : ViewModelBase [ObservableProperty] private bool isSelected; - public ExtensionBase Extension { get; init; } + public PackageExtension PackageExtension { get; init; } } diff --git a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs index 3753e4bab..d9074211c 100644 --- a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs +++ b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs @@ -1,4 +1,5 @@ using System.Runtime.Versioning; +using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; @@ -30,13 +31,96 @@ public interface IPrerequisiteHelper Task GetGitOutput(ProcessArgs args, string? workingDirectory = null); - async Task CheckIsGitRepository(string directory) + async Task CheckIsGitRepository(string repositoryPath) { - var result = await GetGitOutput(["rev-parse", "--is-inside-work-tree"], directory) + var result = await GetGitOutput(["rev-parse", "--is-inside-work-tree"], repositoryPath) .ConfigureAwait(false); return result.ExitCode == 0 && result.StandardOutput?.Trim().ToLowerInvariant() == "true"; } + async Task GetGitRepositoryVersion(string repositoryPath) + { + var version = new GitVersion(); + + // Get tag + if ( + await GetGitOutput(["describe", "--tags", "--abbrev=0"], repositoryPath).ConfigureAwait(false) is + { IsSuccessExitCode: true } tagResult + ) + { + version = version with { Tag = tagResult.StandardOutput?.Trim() }; + } + + // Get branch + if ( + await GetGitOutput(["rev-parse", "--abbrev-ref", "HEAD"], repositoryPath).ConfigureAwait(false) is + { IsSuccessExitCode: true } branchResult + ) + { + version = version with { Branch = branchResult.StandardOutput?.Trim() }; + } + + // Get commit sha + if ( + await GetGitOutput(["rev-parse", "HEAD"], repositoryPath).ConfigureAwait(false) is + { IsSuccessExitCode: true } shaResult + ) + { + version = version with { CommitSha = shaResult.StandardOutput?.Trim() }; + } + + return version; + } + + async Task CloneGitRepository(string rootDir, string repositoryUrl, GitVersion? version = null) + { + // Latest if no version is given + if (version is null) + { + await RunGit(["clone", "--depth", "1", repositoryUrl], rootDir).ConfigureAwait(false); + } + else if (version.Tag is not null) + { + await RunGit(["clone", "--depth", "1", version.Tag, repositoryUrl], rootDir) + .ConfigureAwait(false); + } + else if (version.Branch is not null && version.CommitSha is not null) + { + await RunGit(["clone", "--depth", "1", "--branch", version.Branch, repositoryUrl], rootDir) + .ConfigureAwait(false); + + await RunGit(["checkout", version.CommitSha, "--force"], rootDir).ConfigureAwait(false); + } + else + { + throw new ArgumentException("Version must have a tag or branch and commit sha.", nameof(version)); + } + } + + async Task UpdateGitRepository(string repositoryDir, string repositoryUrl, GitVersion? version = null) + { + if (version?.Tag is not null) + { + await RunGit(["init"], repositoryDir).ConfigureAwait(false); + await RunGit(["remote", "add", "origin", repositoryUrl], repositoryDir).ConfigureAwait(false); + await RunGit(["fetch", "--tags"], repositoryDir).ConfigureAwait(false); + + await RunGit(["checkout", version.Tag, "--force"], repositoryDir).ConfigureAwait(false); + } + else if (version?.Branch is not null && version.CommitSha is not null) + { + await RunGit(["init"], repositoryDir).ConfigureAwait(false); + await RunGit(["remote", "add", "origin", repositoryUrl], repositoryDir).ConfigureAwait(false); + await RunGit(["fetch", "--tags"], repositoryDir).ConfigureAwait(false); + + await RunGit(["checkout", version.CommitSha, "--force"], repositoryDir).ConfigureAwait(false); + } + else + { + throw new ArgumentException("Version must have a tag or branch and commit sha.", nameof(version)); + } + } + Task InstallTkinterIfNecessary(IProgress? progress = null); } diff --git a/StabilityMatrix.Core/Helper/PrerequisiteHelper.cs b/StabilityMatrix.Core/Helper/PrerequisiteHelper.cs index de9898aa9..3edc000c4 100644 --- a/StabilityMatrix.Core/Helper/PrerequisiteHelper.cs +++ b/StabilityMatrix.Core/Helper/PrerequisiteHelper.cs @@ -90,14 +90,16 @@ public async Task RunGit(ProcessArgs args, string? workingDirectory = null) result.EnsureSuccessExitCode(); } + /// + public Task GetGitOutput(ProcessArgs args, string? workingDirectory = null) + { + throw new NotImplementedException(); + } + public async Task GetGitOutput(string? workingDirectory = null, params string[] args) { var output = await ProcessRunner - .GetProcessOutputAsync( - GitExePath, - string.Join(" ", args), - workingDirectory: workingDirectory - ) + .GetProcessOutputAsync(GitExePath, string.Join(" ", args), workingDirectory: workingDirectory) .ConfigureAwait(false); return output; } @@ -195,11 +197,7 @@ private async Task ExtractAllEmbeddedResources( public async Task UnpackResourcesIfNecessary(IProgress? progress = null) { // Skip if all files exist - if ( - File.Exists(SevenZipPath) - && File.Exists(PythonDllPath) - && File.Exists(PythonLibraryZipPath) - ) + if (File.Exists(SevenZipPath) && File.Exists(PythonDllPath) && File.Exists(PythonLibraryZipPath)) { return; } @@ -273,10 +271,7 @@ await downloadService.DownloadToFileAsync( if (!File.Exists(SevenZipPath)) { await ExtractEmbeddedResource("StabilityMatrix.Assets.7za.exe", AssetsDir); - await ExtractEmbeddedResource( - "StabilityMatrix.Assets.7za - LICENSE.txt", - AssetsDir - ); + await ExtractEmbeddedResource("StabilityMatrix.Assets.7za - LICENSE.txt", AssetsDir); } // Delete existing python dir @@ -356,10 +351,7 @@ await downloadService.DownloadToFileAsync( public async Task InstallVcRedistIfNecessary(IProgress? progress = null) { var registry = Registry.LocalMachine; - var key = registry.OpenSubKey( - @"SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64", - false - ); + var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64", false); if (key != null) { var buildId = Convert.ToUInt32(key.GetValue("Bld")); @@ -393,10 +385,7 @@ await downloadService.DownloadToFileAsync( message: "Installing prerequisites..." ) ); - var process = ProcessRunner.StartAnsiProcess( - VcRedistDownloadPath, - "/install /quiet /norestart" - ); + var process = ProcessRunner.StartAnsiProcess(VcRedistDownloadPath, "/install /quiet /norestart"); await process.WaitForExitAsync(); progress?.Report( new ProgressReport( diff --git a/StabilityMatrix.Core/Models/GitVersion.cs b/StabilityMatrix.Core/Models/GitVersion.cs new file mode 100644 index 000000000..18ccd08aa --- /dev/null +++ b/StabilityMatrix.Core/Models/GitVersion.cs @@ -0,0 +1,13 @@ +namespace StabilityMatrix.Core.Models; + +/// +/// Union of either Tag or Branch + CommitSha. +/// +public record GitVersion +{ + public string? Tag { get; init; } + + public string? Branch { get; init; } + + public string? CommitSha { get; init; } +} diff --git a/StabilityMatrix.Core/Models/PackageModification/InstallExtensionStep.cs b/StabilityMatrix.Core/Models/PackageModification/InstallExtensionStep.cs index 686c09ee8..0e3018f72 100644 --- a/StabilityMatrix.Core/Models/PackageModification/InstallExtensionStep.cs +++ b/StabilityMatrix.Core/Models/PackageModification/InstallExtensionStep.cs @@ -1,15 +1,24 @@ -using StabilityMatrix.Core.Models.FileInterfaces; -using StabilityMatrix.Core.Models.Packages.Extensions; +using StabilityMatrix.Core.Models.Packages.Extensions; using StabilityMatrix.Core.Models.Progress; namespace StabilityMatrix.Core.Models.PackageModification; -public class InstallExtensionStep(ExtensionBase extension, DirectoryPath extensionsDir) : IPackageStep +public class InstallExtensionStep( + IPackageExtensionManager extensionManager, + InstalledPackage installedPackage, + PackageExtension packageExtension, + PackageExtensionVersion? extensionVersion = null +) : IPackageStep { public Task ExecuteAsync(IProgress? progress = null) { - return extension.InstallExtensionAsync(extensionsDir, extension.MainBranch); + return extensionManager.InstallExtensionAsync( + packageExtension, + installedPackage, + extensionVersion, + progress + ); } - public string ProgressTitle => $"Installing {extension.DisplayName}"; + public string ProgressTitle => $"Installing Extension {packageExtension.Title}"; } diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 68fd939a5..61b261bb9 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -1,4 +1,5 @@ -using Octokit; +using System.Diagnostics.CodeAnalysis; +using Octokit; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.HardwareInfo; using StabilityMatrix.Core.Models.Database; @@ -158,6 +159,17 @@ public virtual TorchVersion GetRecommendedTorchVersion() public abstract Dictionary>? SharedFolders { get; } public abstract Dictionary>? SharedOutputFolders { get; } + /// + /// If defined, this package supports extensions using this manager. + /// + public virtual IPackageExtensionManager? ExtensionManager { get; } + + /// + /// True if this package supports extensions. + /// + [MemberNotNullWhen(true)] + public virtual bool SupportsExtensions => ExtensionManager is not null; + public abstract Task GetAllVersionOptions(); public abstract Task?> GetAllCommits( string branch, diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 5ac92976d..21bed9118 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using NLog; using StabilityMatrix.Core.Attributes; @@ -462,4 +464,38 @@ private static async Task RemoveConfigSection(DirectoryPath installDirectory) await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false); } + + public override IPackageExtensionManager ExtensionManager => new ComfyExtensionManager(this); + + private class ComfyExtensionManager(ComfyUI package) + : GitPackageExtensionManager(package.PrerequisiteHelper) + { + public override string RelativeInstallDirectory => "custom_nodes"; + + protected override IEnumerable GetManifests(InstalledPackage installedPackage) => + [ + new ExtensionManifest( + new Uri("https://github.com/ltdrdata/ComfyUI-Manager/blob/main/custom-node-list.json") + ) + ]; + + public override async Task> GetManifestExtensionsAsync( + ExtensionManifest manifest, + CancellationToken cancellationToken = default + ) + { + // Get json + var content = await package + .DownloadService.GetContentAsync(manifest.Uri.ToString(), cancellationToken) + .ConfigureAwait(false); + + // Parse json + var jsonManifest = JsonSerializer.Deserialize( + content, + ComfyExtensionManifestSerializerContext.Default.Options + ); + + return jsonManifest?.GetPackageExtensions() ?? Enumerable.Empty(); + } + } } diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/ComfyExtensionManifest.cs b/StabilityMatrix.Core/Models/Packages/Extensions/ComfyExtensionManifest.cs new file mode 100644 index 000000000..d4419b46e --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/ComfyExtensionManifest.cs @@ -0,0 +1,43 @@ +using System.Text.Json.Serialization; + +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public record ComfyExtensionManifest +{ + public required IEnumerable CustomNodes { get; init; } + + public IEnumerable GetPackageExtensions() + { + return CustomNodes.Select( + x => + new PackageExtension + { + Author = x.Author, + Title = x.Title, + Reference = x.Reference, + Files = x.Files, + Description = x.Description, + InstallType = x.InstallType + } + ); + } + + public record ManifestEntry + { + public required string Author { get; init; } + + public required string Title { get; init; } + + public required Uri Reference { get; init; } + + public required IEnumerable Files { get; init; } + + public string? Description { get; init; } + + public string? InstallType { get; init; } + } +} + +[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)] +[JsonSerializable(typeof(ComfyExtensionManifest))] +internal partial class ComfyExtensionManifestSerializerContext : JsonSerializerContext; diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionBase.cs b/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionBase.cs deleted file mode 100644 index 240d39a34..000000000 --- a/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionBase.cs +++ /dev/null @@ -1,24 +0,0 @@ -using StabilityMatrix.Core.Models.FileInterfaces; - -namespace StabilityMatrix.Core.Models.Packages.Extensions; - -public abstract class ExtensionBase -{ - public string ByAuthor => $"By {Author}"; - - public abstract string RepoName { get; } - public abstract string DisplayName { get; set; } - public abstract string Author { get; } - - public abstract string Blurb { get; } - public abstract IEnumerable CompatibleWith { get; } - public abstract string MainBranch { get; } - - public abstract Task InstallExtensionAsync( - DirectoryPath installDirectory, - string branch, - CancellationToken cancellationToken = default - ); - - public string GithubUrl => $"https://github.com/{Author}/{RepoName}"; -} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionManifest.cs b/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionManifest.cs new file mode 100644 index 000000000..57afcdb45 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/ExtensionManifest.cs @@ -0,0 +1,3 @@ +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public record ExtensionManifest(Uri Uri); diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs new file mode 100644 index 000000000..bdc6c8ec4 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs @@ -0,0 +1,144 @@ +using KGySoft.CoreLibraries; +using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Models.Progress; + +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisiteHelper) + : IPackageExtensionManager +{ + public abstract string RelativeInstallDirectory { get; } + + protected virtual IEnumerable IndexRelativeDirectories => [RelativeInstallDirectory]; + + public abstract Task> GetManifestExtensionsAsync( + ExtensionManifest manifest, + CancellationToken cancellationToken = default + ); + + /// + Task> IPackageExtensionManager.GetManifestExtensionsAsync( + ExtensionManifest manifest, + CancellationToken cancellationToken + ) + { + return GetManifestExtensionsAsync(manifest, cancellationToken); + } + + protected abstract IEnumerable GetManifests(InstalledPackage installedPackage); + + /// + IEnumerable IPackageExtensionManager.GetManifests(InstalledPackage installedPackage) + { + return GetManifests(installedPackage); + } + + /// + public async Task> GetInstalledExtensionsAsync( + InstalledPackage installedPackage, + CancellationToken cancellationToken = default + ) + { + if (installedPackage.FullPath is not { } packagePath) + { + return Enumerable.Empty(); + } + + var extensions = new List(); + + // Search for installed extensions in the package's index directories. + foreach ( + var indexDirectory in IndexRelativeDirectories.Select( + path => new DirectoryPath(packagePath, path) + ) + ) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Check subdirectories of the index directory + foreach (var subDirectory in indexDirectory.EnumerateDirectories()) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Skip if not valid git repository + if (await prerequisiteHelper.CheckIsGitRepository(subDirectory).ConfigureAwait(false) != true) + continue; + + // Get git version + var version = await prerequisiteHelper + .GetGitRepositoryVersion(subDirectory) + .ConfigureAwait(false); + + extensions.Add( + new InstalledPackageExtension + { + Paths = [subDirectory], + Version = new PackageExtensionVersion + { + Tag = version.Tag, + Branch = version.Branch, + CommitSha = version.CommitSha + } + } + ); + } + } + + return extensions; + } + + /// + public async Task InstallExtensionAsync( + PackageExtension extension, + InstalledPackage installedPackage, + PackageExtensionVersion? version = null, + IProgress? progress = null, + CancellationToken cancellationToken = default + ) + { + if (installedPackage.FullPath is not { } packagePath) + throw new ArgumentException("Package must have a valid path.", nameof(installedPackage)); + + // Ensure type + if (extension.InstallType?.ToLowerInvariant() != "git-clone") + { + throw new ArgumentException( + $"Extension must have install type 'git-clone' but has '{extension.InstallType}'.", + nameof(extension) + ); + } + + // Git clone all files + var cloneRoot = new DirectoryPath(packagePath, RelativeInstallDirectory); + + foreach (var repositoryUri in extension.Files) + { + cancellationToken.ThrowIfCancellationRequested(); + + progress?.Report(new ProgressReport(0f, $"Cloning {repositoryUri}", isIndeterminate: true)); + + await prerequisiteHelper + .CloneGitRepository(cloneRoot, repositoryUri.ToString(), version) + .ConfigureAwait(false); + + progress?.Report(new ProgressReport(1f, $"Cloned {repositoryUri}")); + } + } + + /// + public async Task UninstallExtensionAsync( + InstalledPackageExtension installedExtension, + InstalledPackage installedPackage, + IProgress? progress = null, + CancellationToken cancellationToken = default + ) + { + foreach (var path in installedExtension.Paths.Where(p => p.Exists)) + { + cancellationToken.ThrowIfCancellationRequested(); + + await path.DeleteAsync().ConfigureAwait(false); + } + } +} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/IPackageExtensionManager.cs b/StabilityMatrix.Core/Models/Packages/Extensions/IPackageExtensionManager.cs new file mode 100644 index 000000000..8e2e06f03 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/IPackageExtensionManager.cs @@ -0,0 +1,37 @@ +using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Models.Progress; + +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +/// +/// Interface for a package extension manager. +/// +public interface IPackageExtensionManager +{ + IEnumerable GetManifests(InstalledPackage installedPackage); + + Task> GetManifestExtensionsAsync( + ExtensionManifest manifest, + CancellationToken cancellationToken = default + ); + + Task> GetInstalledExtensionsAsync( + InstalledPackage installedPackage, + CancellationToken cancellationToken = default + ); + + Task InstallExtensionAsync( + PackageExtension extension, + InstalledPackage installedPackage, + PackageExtensionVersion? version = null, + IProgress? progress = null, + CancellationToken cancellationToken = default + ); + + Task UninstallExtensionAsync( + InstalledPackageExtension installedExtension, + InstalledPackage installedPackage, + IProgress? progress = null, + CancellationToken cancellationToken = default + ); +} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs b/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs new file mode 100644 index 000000000..a21e9d655 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs @@ -0,0 +1,21 @@ +using StabilityMatrix.Core.Models.FileInterfaces; + +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public record InstalledPackageExtension +{ + /// + /// All folders or files of the extension. + /// + public required IEnumerable Paths { get; init; } + + /// + /// The version of the extension. + /// + public PackageExtensionVersion? Version { get; init; } + + /// + /// + /// + public PackageExtension? Definition { get; init; } +} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtension.cs b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtension.cs new file mode 100644 index 000000000..4b406bfbc --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtension.cs @@ -0,0 +1,16 @@ +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public record PackageExtension +{ + public required string Author { get; init; } + + public required string Title { get; init; } + + public required Uri Reference { get; init; } + + public required IEnumerable Files { get; init; } + + public string? Description { get; init; } + + public string? InstallType { get; init; } +} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs new file mode 100644 index 000000000..686d84354 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs @@ -0,0 +1,3 @@ +namespace StabilityMatrix.Core.Models.Packages.Extensions; + +public record PackageExtensionVersion : GitVersion; From df551668048e66fb2e0d84277358ed989f93136e Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 14:44:58 +0800 Subject: [PATCH 123/276] Fallback fonts on macos --- StabilityMatrix.Avalonia/App.axaml.cs | 60 ++++++++++++++++++- .../Views/MainWindow.axaml.cs | 51 ++-------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index d4bba2018..3ea5e0031 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -17,11 +17,13 @@ using Avalonia.Data.Core.Plugins; using Avalonia.Input.Platform; using Avalonia.Markup.Xaml; +using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Platform.Storage; using Avalonia.Styling; using Avalonia.Threading; +using FluentAvalonia.Interop; using FluentAvalonia.UI.Controls; using MessagePipe; using Microsoft.Extensions.Configuration; @@ -97,6 +99,8 @@ public sealed class App : Application public IClassicDesktopStyleApplicationLifetime? DesktopLifetime => ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; + public static new App? Current => (App?)Application.Current; + /// /// Called before is built. /// Can be used by UI tests to override services. @@ -107,6 +111,8 @@ public override void Initialize() { AvaloniaXamlLoader.Load(this); + SetFontFamily(GetPlatformDefaultFontFamily()); + // Set design theme if (Design.IsDesignMode) { @@ -182,6 +188,58 @@ public override void OnFrameworkInitializationCompleted() } } + /// + /// Set the default font family for the application. + /// + private void SetFontFamily(FontFamily fontFamily) + { + Resources["ContentControlThemeFontFamily"] = fontFamily; + } + + /// + /// Get the default font family for the current platform and language. + /// + public FontFamily GetPlatformDefaultFontFamily() + { + try + { + var fonts = new List(); + + if (Cultures.Current?.Name == "ja-JP") + { + return Resources["NotoSansJP"] as FontFamily + ?? throw new ApplicationException("Font NotoSansJP not found"); + } + + if (Compat.IsWindows) + { + fonts.Add(OSVersionHelper.IsWindows11() ? "Segoe UI Variable Text" : "Segoe UI"); + } + else if (Compat.IsMacOS) + { + // Use Segoe fonts if installed, but we can't distribute them + fonts.Add("Segoe UI Variable"); + fonts.Add("Segoe UI"); + + fonts.Add("San Francisco"); + fonts.Add("Helvetica Neue"); + fonts.Add("Helvetica"); + } + else + { + return FontFamily.Default; + } + + return new FontFamily(string.Join(",", fonts)); + } + catch (Exception e) + { + LogManager.GetCurrentClassLogger().Error(e); + + return FontFamily.Default; + } + } + /// /// Setup tasks to be run shortly before any window is shown /// @@ -220,8 +278,6 @@ private void ShowMainWindow() mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; } - mainWindow.SetDefaultFonts(); - VisualRoot = mainWindow; StorageProvider = mainWindow.StorageProvider; Clipboard = mainWindow.Clipboard ?? throw new NullReferenceException("Clipboard is null"); diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs index f512b5020..e13f38413 100644 --- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs @@ -91,6 +91,8 @@ ISettingsManager settingsManager EventManager.Instance.CultureChanged += (_, _) => SetDefaultFonts(); EventManager.Instance.UpdateAvailable += OnUpdateAvailable; + SetDefaultFonts(); + Observable .FromEventPattern(this, nameof(SizeChanged)) .Where(x => x.EventArgs.PreviousSize != x.EventArgs.NewSize) @@ -243,54 +245,11 @@ private void OnUpdateAvailable(object? sender, UpdateInfo? updateInfo) }); } - public void SetDefaultFonts() + private void SetDefaultFonts() { - var fonts = new List(); - - try - { - if (Cultures.Current?.Name == "ja-JP") - { - var customFont = (Application.Current!.Resources["NotoSansJP"] as FontFamily)!; - Resources["ContentControlThemeFontFamily"] = customFont; - FontFamily = customFont; - return; - } - - if (Compat.IsWindows) - { - if (OSVersionHelper.IsWindows11()) - { - fonts.Add("Segoe UI Variable Text"); - } - else - { - fonts.Add("Segoe UI"); - } - } - else if (Compat.IsMacOS) - { - fonts.Add("San Francisco"); - fonts.Add("Helvetica Neue"); - fonts.Add("Helvetica"); - } - else - { - Resources["ContentControlThemeFontFamily"] = FontFamily.Default; - FontFamily = FontFamily.Default; - return; - } - - var fontString = new FontFamily(string.Join(",", fonts)); - Resources["ContentControlThemeFontFamily"] = fontString; - FontFamily = fontString; - } - catch (Exception e) + if (App.Current is not null) { - LogManager.GetCurrentClassLogger().Error(e); - - Resources["ContentControlThemeFontFamily"] = FontFamily.Default; - FontFamily = FontFamily.Default; + FontFamily = App.Current.GetPlatformDefaultFontFamily(); } } From b4779cd7259cc37e1ee8e8d0979319af9e933998 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 14:45:09 +0800 Subject: [PATCH 124/276] Update font setting --- StabilityMatrix.UITests/TestBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/StabilityMatrix.UITests/TestBase.cs b/StabilityMatrix.UITests/TestBase.cs index bf4f6280e..a7f772629 100644 --- a/StabilityMatrix.UITests/TestBase.cs +++ b/StabilityMatrix.UITests/TestBase.cs @@ -50,7 +50,6 @@ internal static (AppWindow, MainWindowViewModel) GetMainWindow() var viewModel = Services.GetRequiredService(); window.DataContext = viewModel; - window.SetDefaultFonts(); window.Width = 1400; window.Height = 900; From a4c895080a0da503807892f331b408ae2b9291d5 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 14:45:23 +0800 Subject: [PATCH 125/276] Add generic SelectableItem vm --- StabilityMatrix.Core/Models/SelectableItem.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 StabilityMatrix.Core/Models/SelectableItem.cs diff --git a/StabilityMatrix.Core/Models/SelectableItem.cs b/StabilityMatrix.Core/Models/SelectableItem.cs new file mode 100644 index 000000000..906d36fef --- /dev/null +++ b/StabilityMatrix.Core/Models/SelectableItem.cs @@ -0,0 +1,46 @@ +using DynamicData.Binding; +using JetBrains.Annotations; + +namespace StabilityMatrix.Core.Models; + +[PublicAPI] +public class SelectableItem(T item) : AbstractNotifyPropertyChanged, IEquatable> +{ + public T Item { get; } = item; + + private bool _isSelected; + + public bool IsSelected + { + get => _isSelected; + set => SetAndRaise(ref _isSelected, value); + } + + /// + public bool Equals(SelectableItem? other) + { + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + return EqualityComparer.Default.Equals(Item, other.Item); + } + + /// + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != GetType()) + return false; + return Equals((SelectableItem)obj); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(GetType().GetHashCode(), Item?.GetHashCode()); + } +} From 21133b758c18315fe93b630dd2c828e2d3352c20 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 14:46:17 +0800 Subject: [PATCH 126/276] Add PackageExtensionBrowser --- .../DesignData/DesignData.cs | 16 ++ .../PackageManager/PackageCardViewModel.cs | 28 +++ .../PackageExtensionBrowserViewModel.cs | 177 ++++++++++++++ .../PackageExtensionBrowserView.axaml | 215 ++++++++++++++++++ .../PackageExtensionBrowserView.axaml.cs | 13 ++ .../Views/PackageManagerPage.axaml | 9 + .../Helper/IPrerequisiteHelper.cs | 5 + .../Models/Packages/ComfyUI.cs | 4 +- .../Extensions/GitPackageExtensionManager.cs | 18 +- .../Extensions/IPackageExtensionManager.cs | 26 ++- .../Extensions/InstalledPackageExtension.cs | 7 +- 11 files changed, 512 insertions(+), 6 deletions(-) create mode 100644 StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs create mode 100644 StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml create mode 100644 StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml.cs diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index 9688f93d0..3ac1ac7a8 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -39,6 +39,7 @@ using StabilityMatrix.Core.Models.Database; using StabilityMatrix.Core.Models.PackageModification; using StabilityMatrix.Core.Models.Packages; +using StabilityMatrix.Core.Models.Packages.Extensions; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Models.Update; using StabilityMatrix.Core.Python; @@ -482,6 +483,21 @@ public static PackageManagerViewModel PackageManagerViewModel } } + public static PackageExtensionBrowserViewModel PackageExtensionBrowserViewModel => + DialogFactory.Get(vm => + { + vm.AddExtensions( + new PackageExtension + { + Author = "123", + Title = "Cool Extension", + Description = "This is an interesting extension", + Reference = new Uri("https://github.com/LykosAI/StabilityMatrix"), + Files = [new Uri("https://github.com/LykosAI/StabilityMatrix")] + } + ); + }); + public static CheckpointsPageViewModel CheckpointsPageViewModel => Services.GetRequiredService(); diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 9ce707751..7fc396cf8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -4,11 +4,13 @@ using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Notifications; +using Avalonia.Controls.Primitives; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FluentAvalonia.UI.Controls; using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.Animations; +using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Services; @@ -375,6 +377,32 @@ public async Task OpenPythonPackagesDialog() await vm.GetDialog().ShowAsync(); } + [RelayCommand] + public async Task OpenExtensionsDialog() + { + if ( + Package is not { FullPath: not null } + || packageFactory.GetPackagePair(Package) is not { } packagePair + ) + return; + + var vm = vmFactory.Get(vm => + { + vm.PackagePair = packagePair; + }); + + var dialog = new BetterContentDialog + { + Content = vm, + CloseOnClickOutside = true, + FullSizeDesired = true, + IsFooterVisible = false, + ContentVerticalScrollBarVisibility = ScrollBarVisibility.Disabled + }; + + await dialog.ShowAsync(); + } + [RelayCommand] private void OpenOnGitHub() { diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs new file mode 100644 index 000000000..65b598a5d --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -0,0 +1,177 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using DynamicData; +using DynamicData.Binding; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.Views.PackageManager; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.PackageModification; +using StabilityMatrix.Core.Models.Packages.Extensions; + +namespace StabilityMatrix.Avalonia.ViewModels.PackageManager; + +[View(typeof(PackageExtensionBrowserView))] +[Transient] +[ManagedService] +public partial class PackageExtensionBrowserViewModel : ViewModelBase +{ + public PackagePair? PackagePair { get; set; } + + [ObservableProperty] + private string searchFilter = string.Empty; + + [ObservableProperty] + private int selectedItemsCount; + + [ObservableProperty] + private bool isLoading; + + private SourceCache availableExtensionsSource = + new(ext => ext.Author + ext.Title + ext.Reference); + + public IObservableCollection> AvailableItems { get; } = + new ObservableCollectionExtended>(); + + public IObservableCollection> AvailableItemsFiltered { get; } = + new ObservableCollectionExtended>(); + + public IObservableCollection> SelectedAvailableItems { get; } = + new ObservableCollectionExtended>(); + + private SourceCache installedExtensionsSource = + new( + ext => + ext.Paths.FirstOrDefault()?.ToString() ?? ext.GitRepositoryUrl ?? ext.GetHashCode().ToString() + ); + + public IObservableCollection InstalledExtensions { get; } = + new ObservableCollectionExtended(); + + public PackageExtensionBrowserViewModel() + { + var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchFilter) + .Select( + change => + string.IsNullOrWhiteSpace(change.Value) + ? _ => true + : new Func, bool>( + ext => ext.Item.Title.Contains(change.Value, StringComparison.OrdinalIgnoreCase) + ) + ) + .AsObservable(); + + var availableItemsChangeSet = availableExtensionsSource + .Connect() + .Transform(ext => new SelectableItem(ext)) + .Publish(); + + availableItemsChangeSet + .SortBy(x => x.Item.Title) + .Bind(AvailableItems) + .Filter(searchPredicate) + .Bind(AvailableItemsFiltered) + .Subscribe(); + + availableItemsChangeSet + .AutoRefresh(item => item.IsSelected) + .Filter(item => item.IsSelected) + .ForEachChange(OnSelectedItemsUpdate) + .Bind(SelectedAvailableItems) + .Subscribe(); + + availableItemsChangeSet.Connect(); + + SelectedAvailableItems + .WhenPropertyChanged(x => x.Count) + .Select(x => x.Value) + .Subscribe(x => SelectedItemsCount = x); + } + + public void AddExtensions(params PackageExtension[] packageExtensions) + { + availableExtensionsSource.AddOrUpdate(packageExtensions); + } + + [RelayCommand] + public async Task InstallSelectedExtensions() + { + var extensions = SelectedAvailableItems.Select(x => x.Item).ToArray(); + + if (extensions.Length == 0) + return; + + var steps = extensions + .Select( + ext => + new InstallExtensionStep( + PackagePair!.BasePackage.ExtensionManager!, + PackagePair.InstalledPackage, + ext + ) + ) + .Cast() + .ToArray(); + + var runner = new PackageModificationRunner { ShowDialogOnStart = true, HideCloseButton = true }; + EventManager.Instance.OnPackageInstallProgressAdded(runner); + await runner.ExecuteSteps(steps); + } + + [RelayCommand] + private async Task Refresh() + { + if (PackagePair is null) + return; + + if (PackagePair.BasePackage.ExtensionManager is not { } extensionManager) + { + throw new NotSupportedException( + $"The package {PackagePair.BasePackage} does not support extensions." + ); + } + + IsLoading = true; + + try + { + if (Design.IsDesignMode) + { + await Task.Delay(250); + } + else + { + // Refresh installed + var installedExtensions = await extensionManager.GetInstalledExtensionsAsync( + PackagePair.InstalledPackage + ); + + installedExtensionsSource.EditDiff(installedExtensions); + + // Refresh available + var extensions = await extensionManager.GetManifestExtensionsAsync( + extensionManager.GetManifests(PackagePair.InstalledPackage) + ); + + availableExtensionsSource.EditDiff(extensions); + } + } + finally + { + IsLoading = false; + } + } + + private void OnSelectedItemsUpdate(Change, string> change) + { + Debug.WriteLine($"{change}"); + } +} diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml new file mode 100644 index 000000000..a9f70383f --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + public interface IPackageExtensionManager { - IEnumerable GetManifests(InstalledPackage installedPackage); + IEnumerable DefaultManifests { get; } + + IEnumerable GetManifests(InstalledPackage installedPackage) + { + return DefaultManifests; + } Task> GetManifestExtensionsAsync( ExtensionManifest manifest, CancellationToken cancellationToken = default ); + async Task> GetManifestExtensionsAsync( + IEnumerable manifests, + CancellationToken cancellationToken = default + ) + { + var extensions = Enumerable.Empty(); + + foreach (var manifest in manifests) + { + cancellationToken.ThrowIfCancellationRequested(); + + extensions = extensions.Concat( + await GetManifestExtensionsAsync(manifest, cancellationToken).ConfigureAwait(false) + ); + } + + return extensions; + } + Task> GetInstalledExtensionsAsync( InstalledPackage installedPackage, CancellationToken cancellationToken = default diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs b/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs index a21e9d655..803792327 100644 --- a/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs +++ b/StabilityMatrix.Core/Models/Packages/Extensions/InstalledPackageExtension.cs @@ -15,7 +15,12 @@ public record InstalledPackageExtension public PackageExtensionVersion? Version { get; init; } /// - /// + /// Remote git repository url, if the extension is a git repository. + /// + public string? GitRepositoryUrl { get; init; } + + /// + /// The PackageExtension definition, if available. /// public PackageExtension? Definition { get; init; } } From 7cc88e806b750c5a8fe53c05d9e673bb6c46c613 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 15:05:42 +0800 Subject: [PATCH 127/276] Fix BetterContentDialog CloseOnClickOutside for other vm types --- .../Controls/BetterContentDialog.cs | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs index 4a27f4677..7a6b6d23f 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs @@ -122,8 +122,10 @@ public ScrollBarVisibility ContentVerticalScrollBarVisibility set => SetValue(ContentVerticalScrollBarVisibilityProperty, value); } - public static readonly StyledProperty MinDialogWidthProperty = - AvaloniaProperty.Register("MinDialogWidth"); + public static readonly StyledProperty MinDialogWidthProperty = AvaloniaProperty.Register< + BetterContentDialog, + double + >("MinDialogWidth"); public double MinDialogWidth { @@ -131,8 +133,10 @@ public double MinDialogWidth set => SetValue(MinDialogWidthProperty, value); } - public static readonly StyledProperty MaxDialogWidthProperty = - AvaloniaProperty.Register("MaxDialogWidth"); + public static readonly StyledProperty MaxDialogWidthProperty = AvaloniaProperty.Register< + BetterContentDialog, + double + >("MaxDialogWidth"); public double MaxDialogWidth { @@ -140,8 +144,10 @@ public double MaxDialogWidth set => SetValue(MaxDialogWidthProperty, value); } - public static readonly StyledProperty MaxDialogHeightProperty = - AvaloniaProperty.Register("MaxDialogHeight"); + public static readonly StyledProperty MaxDialogHeightProperty = AvaloniaProperty.Register< + BetterContentDialog, + double + >("MaxDialogHeight"); public double MaxDialogHeight { @@ -149,8 +155,10 @@ public double MaxDialogHeight set => SetValue(MaxDialogHeightProperty, value); } - public static readonly StyledProperty ContentMarginProperty = - AvaloniaProperty.Register("ContentMargin"); + public static readonly StyledProperty ContentMarginProperty = AvaloniaProperty.Register< + BetterContentDialog, + Thickness + >("ContentMargin"); public Thickness ContentMargin { @@ -158,8 +166,10 @@ public Thickness ContentMargin set => SetValue(ContentMarginProperty, value); } - public static readonly StyledProperty CloseOnClickOutsideProperty = - AvaloniaProperty.Register("CloseOnClickOutside"); + public static readonly StyledProperty CloseOnClickOutsideProperty = AvaloniaProperty.Register< + BetterContentDialog, + bool + >("CloseOnClickOutside"); /// /// Whether to close the dialog when clicking outside of it (on the blurred background) @@ -187,12 +197,17 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) var point = e.GetPosition(this); - if ( - !backgroundPart.Bounds.Contains(point) - && (Content as Control)?.DataContext is ContentDialogViewModelBase vm - ) + if (!backgroundPart.Bounds.Contains(point)) { - vm.OnCloseButtonClick(); + // Use vm if available + if ((Content as Control)?.DataContext is ContentDialogViewModelBase vm) + { + vm.OnCloseButtonClick(); + } + else + { + Hide(ContentDialogResult.None); + } } } } @@ -211,10 +226,7 @@ private void TryBindButtons() viewModelDirect.SecondaryButtonClick += OnDialogButtonClick; viewModelDirect.CloseButtonClick += OnDialogButtonClick; } - else if ( - (Content as Control)?.DataContext - is ContentDialogProgressViewModelBase progressViewModel - ) + else if ((Content as Control)?.DataContext is ContentDialogProgressViewModelBase progressViewModel) { progressViewModel.PrimaryButtonClick += OnDialogButtonClick; progressViewModel.SecondaryButtonClick += OnDialogButtonClick; @@ -234,8 +246,7 @@ is ContentDialogProgressViewModelBase progressViewModel } else { - PrimaryButton.IsVisible = - IsPrimaryButtonEnabled && !string.IsNullOrEmpty(PrimaryButtonText); + PrimaryButton.IsVisible = IsPrimaryButtonEnabled && !string.IsNullOrEmpty(PrimaryButtonText); } } From d991f4cd62a4cf57b440227f884777dbb8399d69 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Sun, 7 Jan 2024 15:06:36 +0800 Subject: [PATCH 128/276] Refresh on load and add clear selection method --- .../PackageExtensionBrowserViewModel.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs index 65b598a5d..46ea684ba 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; @@ -121,13 +122,23 @@ public async Task InstallSelectedExtensions() .Cast() .ToArray(); - var runner = new PackageModificationRunner { ShowDialogOnStart = true, HideCloseButton = true }; + var runner = new PackageModificationRunner { ShowDialogOnStart = true }; EventManager.Instance.OnPackageInstallProgressAdded(runner); await runner.ExecuteSteps(steps); + + ClearSelection(); + } + + /// + public override async Task OnLoadedAsync() + { + await base.OnLoadedAsync(); + + await Refresh(); } [RelayCommand] - private async Task Refresh() + public async Task Refresh() { if (PackagePair is null) return; @@ -170,6 +181,14 @@ private async Task Refresh() } } + public void ClearSelection() + { + foreach (var item in SelectedAvailableItems.ToImmutableArray()) + { + item.IsSelected = false; + } + } + private void OnSelectedItemsUpdate(Change, string> change) { Debug.WriteLine($"{change}"); From f0fba442eec40406f4ff58e72cab0c83284683bd Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 7 Jan 2024 01:30:43 -0800 Subject: [PATCH 129/276] added base model filter to checkpoints page (wip) and some other bug fixes n improvements n stuff idk read the chagenlog --- CHANGELOG.md | 7 ++ .../Base/InferenceGenerationViewModelBase.cs | 5 + .../CivitAiBrowserViewModel.cs | 16 +--- .../BaseModelOptionViewModel.cs | 12 +++ .../CheckpointManager/CheckpointFolder.cs | 50 +++++++--- .../ViewModels/CheckpointsPageViewModel.cs | 62 ++++++++++-- .../Dialogs/PythonPackagesItemViewModel.cs | 8 +- .../Inference/StackEditableCardViewModel.cs | 2 +- .../Inference/StackExpanderViewModel.cs | 7 +- .../ViewModels/NewCheckpointsPageViewModel.cs | 96 +++++++++++++------ .../Views/CheckpointsPage.axaml | 34 +++++++ .../Models/Api/CivitBaseModelType.cs | 32 +++++++ .../Services/MetadataImportService.cs | 2 +- 13 files changed, 266 insertions(+), 67 deletions(-) create mode 100644 StabilityMatrix.Avalonia/ViewModels/CheckpointManager/BaseModelOptionViewModel.cs create mode 100644 StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index c7cdbeb1d..83f837589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ 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.8.0-pre.1 +### Added +- Added base model filter to Checkpoints page +### Fixed +- Inference file name patterns with directory separator characters will now have the subdirectories created automatically +- Fixed missing up/downgrade buttons on the Python Packages dialog when the version was not semver compatible + ## v2.8.0-dev.4 ### Added - Auto-update support for macOS diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs index 7a50ee01e..1ac05c3ca 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs @@ -181,6 +181,11 @@ protected async Task WriteOutputImageAsync( file = outputDir.JoinFile($"{fileName}_{uuid}.{fileExtension}"); } + if (file.Info.DirectoryName != null) + { + Directory.CreateDirectory(file.Info.DirectoryName); + } + await using var fileStream = file.Info.OpenWrite(); await imageStream.CopyToAsync(fileStream); diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index 2911dc6be..a29b2f9d0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -129,18 +129,8 @@ private LRUCache< .Where(t => t == CivitModelType.All || t.ConvertTo() > 0) .OrderBy(t => t.ToString()); - public List BaseModelOptions => - [ - "All", - "SD 1.5", - "SD 1.5 LCM", - "SD 2.1", - "SDXL 0.9", - "SDXL 1.0", - "SDXL 1.0 LCM", - "SDXL Turbo", - "Other" - ]; + public IEnumerable BaseModelOptions => + Enum.GetValues().Select(t => t.GetStringValue()); public CivitAiBrowserViewModel( ICivitApi civitApi, @@ -424,7 +414,7 @@ private async Task SearchModels() if (SelectedModelType != CivitModelType.All) { - modelRequest.Types = new[] { SelectedModelType }; + modelRequest.Types = [SelectedModelType]; } if (SelectedBaseModelType != "All") diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/BaseModelOptionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/BaseModelOptionViewModel.cs new file mode 100644 index 000000000..b44b5d6f3 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/BaseModelOptionViewModel.cs @@ -0,0 +1,12 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace StabilityMatrix.Avalonia.ViewModels.CheckpointManager; + +public partial class BaseModelOptionViewModel : ObservableObject +{ + [ObservableProperty] + private bool isSelected; + + [ObservableProperty] + private string modelType = string.Empty; +} diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs index cfb4e373f..9537446cb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.IO; using System.Linq; @@ -22,6 +23,7 @@ using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; @@ -85,6 +87,14 @@ public partial class CheckpointFolder : ViewModelBase [ObservableProperty] private string searchFilter = string.Empty; + [ObservableProperty] + private ObservableCollection baseModelOptions = + new( + Enum.GetValues() + .Where(x => x != CivitBaseModelType.All) + .Select(x => x.GetStringValue()) + ); + public bool IsDragBlurEnabled => IsCurrentDragTarget || IsImportInProgress; public string TitleWithFilesCount => @@ -141,6 +151,7 @@ public CheckpointFolder( f.FileName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) || f.Title.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) ) + .Filter(BaseModelFilter) .Bind(DisplayedCheckpointFiles) .Subscribe(); @@ -161,6 +172,13 @@ public CheckpointFolder( // DisplayedCheckpointFiles = CheckpointFiles; } + private bool BaseModelFilter(CheckpointFile file) + { + return file.IsConnectedModel + ? BaseModelOptions.Contains(file.ConnectedModel!.BaseModel) + : BaseModelOptions.Contains("Other"); + } + /// /// When title is set, set the category enabled state from settings. /// @@ -187,6 +205,16 @@ partial void OnSearchFilterChanged(string value) checkpointFilesCache.Refresh(); } + partial void OnBaseModelOptionsChanged(ObservableCollection value) + { + foreach (var subFolder in SubFolders) + { + subFolder.BaseModelOptions = new ObservableCollection(value); + } + + checkpointFilesCache.Refresh(); + } + /// /// When toggling the category enabled state, save it to settings. /// @@ -393,7 +421,9 @@ public async Task ImportFilesAsync(IEnumerable files, bool convertToConn Progress.Value = report.Percentage; // For multiple files, add count Progress.Text = - copyPaths.Count > 1 ? $"Importing {report.Title} ({report.Message})" : $"Importing {report.Title}"; + copyPaths.Count > 1 + ? $"Importing {report.Title} ({report.Message})" + : $"Importing {report.Title}"; }); await FileTransfers.CopyFiles(copyPaths, progress); @@ -603,15 +633,13 @@ public void Index() SubFoldersCache.EditDiff(updatedFolders, (a, b) => a.Title == b.Title); // Index files - Dispatcher - .UIThread - .Post( - () => - { - var files = GetCheckpointFiles(); - checkpointFilesCache.EditDiff(files, CheckpointFile.FilePathComparer); - }, - DispatcherPriority.Background - ); + Dispatcher.UIThread.Post( + () => + { + var files = GetCheckpointFiles(); + checkpointFilesCache.EditDiff(files, CheckpointFile.FilePathComparer); + }, + DispatcherPriority.Background + ); } } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index efd84bf9c..b24630f01 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; +using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Notifications; @@ -17,7 +19,9 @@ using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; @@ -41,7 +45,19 @@ public partial class CheckpointsPageViewModel : PageViewModelBase public override string Title => "Checkpoints"; - public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Notebook, IsFilled = true }; + public override IconSource IconSource => + new SymbolIconSource { Symbol = Symbol.Notebook, IsFilled = true }; + + [ObservableProperty] + private ObservableCollection baseModelOptions = + new( + Enum.GetValues() + .Where(x => x != CivitBaseModelType.All) + .Select(x => x.GetStringValue()) + ); + + [ObservableProperty] + private ObservableCollection selectedBaseModels = []; // Toggle button for auto hashing new drag-and-dropped files for connected upgrade [ObservableProperty] @@ -97,12 +113,24 @@ ModelFinder modelFinder this.metadataImportService = metadataImportService; this.modelFinder = modelFinder; + SelectedBaseModels = new ObservableCollection(BaseModelOptions); + SelectedBaseModels.CollectionChanged += (sender, args) => + { + foreach (var folder in CheckpointFolders) + { + folder.BaseModelOptions = new ObservableCollection(SelectedBaseModels); + } + + CheckpointFoldersCache.Refresh(); + }; + CheckpointFoldersCache .Connect() .DeferUntilLoaded() .SortBy(x => x.Title) .Bind(CheckpointFolders) .Filter(ContainsSearchFilter) + .Filter(ContainsBaseModel) .Bind(DisplayedCheckpointFolders) .Subscribe(); } @@ -165,8 +193,7 @@ partial void OnShowConnectedModelImagesChanged(bool value) private bool ContainsSearchFilter(CheckpointFolder folder) { - if (folder == null) - throw new ArgumentNullException(nameof(folder)); + ArgumentNullException.ThrowIfNull(folder); if (string.IsNullOrWhiteSpace(SearchFilter)) { @@ -174,12 +201,28 @@ private bool ContainsSearchFilter(CheckpointFolder folder) } // Check files in the current folder - return folder.CheckpointFiles.Any(x => x.FileName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase)) + return folder.CheckpointFiles.Any( + x => + x.FileName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) + || x.ConnectedModel?.ModelName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) + == true + || x.ConnectedModel?.Tags.Any( + t => t.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) + ) == true + ) || // If no matching files were found in the current folder, check in all subfolders folder.SubFolders.Any(ContainsSearchFilter); } + private bool ContainsBaseModel(CheckpointFolder folder) + { + ArgumentNullException.ThrowIfNull(folder); + + return folder.CheckpointFiles.Any(x => SelectedBaseModels.Contains(x.ConnectedModel?.BaseModel)) + || folder.SubFolders.Any(ContainsBaseModel); + } + private void IndexFolders() { var modelsDirectory = settingsManager.ModelsDirectory; @@ -241,9 +284,16 @@ private async Task FindConnectedMetadata() Progress = report; }); - await metadataImportService.ScanDirectoryForMissingInfo(settingsManager.ModelsDirectory, progressHandler); + await metadataImportService.ScanDirectoryForMissingInfo( + settingsManager.ModelsDirectory, + progressHandler + ); - notificationService.Show("Scan Complete", "Finished scanning for missing metadata.", NotificationType.Success); + notificationService.Show( + "Scan Complete", + "Finished scanning for missing metadata.", + NotificationType.Success + ); DelayedClearProgress(TimeSpan.FromSeconds(1.5)); } diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs index 7259df548..a31e7cf2c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesItemViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Avalonia.Controls; @@ -49,8 +50,9 @@ value is null || !SemVersion.TryParse(value, out var selectedSemver) ) { - CanUpgrade = false; - CanDowngrade = false; + var compare = string.CompareOrdinal(value, Package.Version); + CanUpgrade = compare > 0; + CanDowngrade = compare < 0; return; } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs index d26b646c1..c4da8f2ff 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/StackEditableCardViewModel.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Newtonsoft.Json; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/StackExpanderViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/StackExpanderViewModel.cs index e3ed89661..c188dbb95 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/StackExpanderViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/StackExpanderViewModel.cs @@ -1,14 +1,11 @@ -using System.Linq; -using System.Text.Json.Nodes; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Newtonsoft.Json; using StabilityMatrix.Avalonia.Controls; -using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; -using StabilityMatrix.Core.Extensions; #pragma warning disable CS0657 // Not a valid attribute location for this declaration namespace StabilityMatrix.Avalonia.ViewModels.Inference; diff --git a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs index 87ebb0f5d..e97412849 100644 --- a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; @@ -34,35 +35,22 @@ namespace StabilityMatrix.Avalonia.ViewModels; [View(typeof(NewCheckpointsPage))] [Singleton] -public partial class NewCheckpointsPageViewModel : PageViewModelBase +public partial class NewCheckpointsPageViewModel( + ILogger logger, + ISettingsManager settingsManager, + ILiteDbContext liteDbContext, + ICivitApi civitApi, + ServiceManager dialogFactory, + INotificationService notificationService, + IDownloadService downloadService, + ModelFinder modelFinder, + IMetadataImportService metadataImportService +) : PageViewModelBase { - private readonly ILogger logger; - private readonly ISettingsManager settingsManager; - private readonly ILiteDbContext liteDbContext; - private readonly ICivitApi civitApi; - private readonly ServiceManager dialogFactory; - private readonly INotificationService notificationService; public override string Title => "Checkpoint Manager"; public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Cellular5g, IsFilled = true }; - public NewCheckpointsPageViewModel( - ILogger logger, - ISettingsManager settingsManager, - ILiteDbContext liteDbContext, - ICivitApi civitApi, - ServiceManager dialogFactory, - INotificationService notificationService - ) - { - this.logger = logger; - this.settingsManager = settingsManager; - this.liteDbContext = liteDbContext; - this.civitApi = civitApi; - this.dialogFactory = dialogFactory; - this.notificationService = notificationService; - } - [ObservableProperty] [NotifyPropertyChangedFor(nameof(ConnectedCheckpoints))] [NotifyPropertyChangedFor(nameof(NonConnectedCheckpoints))] @@ -89,7 +77,61 @@ public override async Task OnLoadedAsync() if (Design.IsDesignMode) return; - var files = CheckpointFile.GetAllCheckpointFiles(settingsManager.ModelsDirectory); + var files = CheckpointFile.GetAllCheckpointFiles(settingsManager.ModelsDirectory).ToList(); + + var uniqueSubFolders = files + .Select( + x => + x.FilePath.Replace(settingsManager.ModelsDirectory, string.Empty) + .Replace(x.FileName, string.Empty) + .Trim(Path.DirectorySeparatorChar) + ) + .Distinct() + .Where(x => x.Contains(Path.DirectorySeparatorChar)) + .Where(x => Directory.Exists(Path.Combine(settingsManager.ModelsDirectory, x))) + .ToList(); + + var checkpointFolders = Enum.GetValues() + .Where(x => Directory.Exists(Path.Combine(settingsManager.ModelsDirectory, x.ToString()))) + .Select( + folderType => + new CheckpointFolder( + settingsManager, + downloadService, + modelFinder, + notificationService, + metadataImportService + ) + { + Title = folderType.ToString(), + DirectoryPath = Path.Combine(settingsManager.ModelsDirectory, folderType.ToString()), + FolderType = folderType, + IsExpanded = true, + } + ) + .ToList(); + + foreach (var folder in uniqueSubFolders) + { + var folderType = Enum.Parse(folder.Split(Path.DirectorySeparatorChar)[0]); + var parentFolder = checkpointFolders.FirstOrDefault(x => x.FolderType == folderType); + var checkpointFolder = new CheckpointFolder( + settingsManager, + downloadService, + modelFinder, + notificationService, + metadataImportService + ) + { + Title = folderType.ToString(), + DirectoryPath = Path.Combine(settingsManager.ModelsDirectory, folder), + FolderType = folderType, + ParentFolder = parentFolder, + IsExpanded = true, + }; + parentFolder?.SubFolders.Add(checkpointFolder); + } + AllCheckpoints = new ObservableCollection(files); var connectedModelIds = ConnectedCheckpoints.Select(x => x.ConnectedModel.ModelId); @@ -99,8 +141,8 @@ public override async Task OnLoadedAsync() }; // See if query is cached - var cachedQuery = await liteDbContext.CivitModelQueryCache - .IncludeAll() + var cachedQuery = await liteDbContext + .CivitModelQueryCache.IncludeAll() .FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest)); // If cached, update model cards diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 021dc27f8..ddebb47b7 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -10,6 +10,9 @@ xmlns:checkpointManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointManager" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" xmlns:avalonia="https://github.com/projektanker/icons.avalonia" + xmlns:api="clr-namespace:StabilityMatrix.Core.Models.Api;assembly=StabilityMatrix.Core" + xmlns:generic="clr-namespace:System.Collections.Generic;assembly=System.Collections" + xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" d:DataContext="{x:Static mocks:DesignData.CheckpointsPageViewModel}" x:CompileBindings="True" x:DataType="vm:CheckpointsPageViewModel" @@ -24,6 +27,8 @@ Color="#FF000000" Opacity="0.2" x:Key="TextDropShadowEffect" /> + + @@ -490,6 +495,35 @@ + + + + + + + + + + + + + + + + + + + + + + ))] +public enum CivitBaseModelType +{ + All, + + [StringValue("SD 1.5")] + Sd15, + + [StringValue("SD 1.5 LCM")] + Sd15Lcm, + + [StringValue("SD 2.1")] + Sd21, + + [StringValue("SDXL 0.9")] + Sdxl09, + + [StringValue("SDXL 1.0")] + Sdxl10, + + [StringValue("SDXL 1.0 LCM")] + Sdxl10Lcm, + + [StringValue("SDXL Turbo")] + SdxlTurbo, + Other, +} diff --git a/StabilityMatrix.Core/Services/MetadataImportService.cs b/StabilityMatrix.Core/Services/MetadataImportService.cs index ca1803b4f..d31a603d9 100644 --- a/StabilityMatrix.Core/Services/MetadataImportService.cs +++ b/StabilityMatrix.Core/Services/MetadataImportService.cs @@ -237,7 +237,7 @@ await updatedCmInfo new ProgressReport( current: report.Current ?? 0, total: report.Total ?? 0, - $"Getting metadata for {filePath} ... {report.Percentage}%" + $"Getting metadata for {fileNameWithoutExtension} ... {report.Percentage}%" ) ); }); From 9b51e2580841654ee621267b87c7ecca91f2f423 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 7 Jan 2024 18:03:13 -0800 Subject: [PATCH 130/276] use observable stuffs for CheckpointFolder base model selection & save it to settings --- .../CheckpointManager/CheckpointFolder.cs | 54 +++++++++++-------- .../ViewModels/CheckpointsPageViewModel.cs | 39 ++++++++++++-- .../Inference/SelectImageCardViewModel.cs | 10 +++- .../Views/CheckpointsPage.axaml | 35 +++++++----- .../Views/MainWindow.axaml.cs | 20 ++++--- .../Models/Settings/Settings.cs | 13 ++++- 6 files changed, 117 insertions(+), 54 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs index 9537446cb..ed9e17c3d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs @@ -45,6 +45,8 @@ public partial class CheckpointFolder : ViewModelBase private readonly SourceCache checkpointFilesCache = new(x => x.FilePath); + public readonly SourceCache BaseModelOptionsCache = new(x => x); + // ReSharper disable once FieldCanBeMadeReadOnly.Local private bool useCategoryVisibility; @@ -87,14 +89,6 @@ public partial class CheckpointFolder : ViewModelBase [ObservableProperty] private string searchFilter = string.Empty; - [ObservableProperty] - private ObservableCollection baseModelOptions = - new( - Enum.GetValues() - .Where(x => x != CivitBaseModelType.All) - .Select(x => x.GetStringValue()) - ); - public bool IsDragBlurEnabled => IsCurrentDragTarget || IsImportInProgress; public string TitleWithFilesCount => @@ -115,6 +109,9 @@ public partial class CheckpointFolder : ViewModelBase public IObservableCollection DisplayedCheckpointFiles { get; set; } = new ObservableCollectionExtended(); + public IObservableCollection BaseModelOptions { get; } = + new ObservableCollectionExtended(); + public CheckpointFolder( ISettingsManager settingsManager, IDownloadService downloadService, @@ -141,17 +138,17 @@ public CheckpointFolder( .Subscribe(_ => checkpointFilesCache.Remove(file)) ) .Bind(CheckpointFiles) - .Sort( - SortExpressionComparer - .Descending(f => f.IsConnectedModel) - .ThenByAscending(f => f.IsConnectedModel ? f.ConnectedModel!.ModelName : f.FileName) - ) .Filter( f => f.FileName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) || f.Title.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) ) .Filter(BaseModelFilter) + .Sort( + SortExpressionComparer + .Descending(f => f.IsConnectedModel) + .ThenByAscending(f => f.IsConnectedModel ? f.ConnectedModel!.ModelName : f.FileName) + ) .Bind(DisplayedCheckpointFiles) .Subscribe(); @@ -168,6 +165,27 @@ public CheckpointFolder( .Bind(SubFolders) .Subscribe(); + BaseModelOptionsCache + .Connect() + .DeferUntilLoaded() + .Bind(BaseModelOptions) + .Subscribe(_ => + { + foreach (var subFolder in SubFolders) + { + subFolder.BaseModelOptionsCache.EditDiff(BaseModelOptions); + } + + checkpointFilesCache.Refresh(); + SubFoldersCache.Refresh(); + }); + + BaseModelOptionsCache.AddOrUpdate( + Enum.GetValues() + .Where(x => x != CivitBaseModelType.All) + .Select(x => x.GetStringValue()) + ); + CheckpointFiles.CollectionChanged += OnCheckpointFilesChanged; // DisplayedCheckpointFiles = CheckpointFiles; } @@ -205,16 +223,6 @@ partial void OnSearchFilterChanged(string value) checkpointFilesCache.Refresh(); } - partial void OnBaseModelOptionsChanged(ObservableCollection value) - { - foreach (var subFolder in SubFolders) - { - subFolder.BaseModelOptions = new ObservableCollection(value); - } - - checkpointFilesCache.Refresh(); - } - /// /// When toggling the category enabled state, save it to settings. /// diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index b24630f01..f426896e2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -14,6 +14,7 @@ using DynamicData.Binding; using FluentAvalonia.UI.Controls; using NLog; +using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; @@ -97,6 +98,11 @@ partial void OnIsImportAsConnectedChanged(bool value) public IObservableCollection DisplayedCheckpointFolders { get; } = new ObservableCollectionExtended(); + public string ClearButtonText => + SelectedBaseModels.Count == BaseModelOptions.Count + ? Resources.Action_ClearSelection + : Resources.Action_SelectAll; + public CheckpointsPageViewModel( ISharedFolders sharedFolders, ISettingsManager settingsManager, @@ -114,23 +120,27 @@ ModelFinder modelFinder this.modelFinder = modelFinder; SelectedBaseModels = new ObservableCollection(BaseModelOptions); - SelectedBaseModels.CollectionChanged += (sender, args) => + SelectedBaseModels.CollectionChanged += (_, _) => { foreach (var folder in CheckpointFolders) { - folder.BaseModelOptions = new ObservableCollection(SelectedBaseModels); + folder.BaseModelOptionsCache.EditDiff(SelectedBaseModels); } CheckpointFoldersCache.Refresh(); + OnPropertyChanged(nameof(ClearButtonText)); + settingsManager.Transaction( + settings => settings.SelectedBaseModels = SelectedBaseModels.ToList() + ); }; CheckpointFoldersCache .Connect() .DeferUntilLoaded() - .SortBy(x => x.Title) .Bind(CheckpointFolders) .Filter(ContainsSearchFilter) .Filter(ContainsBaseModel) + .SortBy(x => x.Title) .Bind(DisplayedCheckpointFolders) .Subscribe(); } @@ -140,7 +150,6 @@ public override void OnLoaded() base.OnLoaded(); var sw = Stopwatch.StartNew(); - // DisplayedCheckpointFolders = CheckpointFolders; // Set UI states IsImportAsConnected = settingsManager.Settings.IsImportAsConnected; @@ -164,6 +173,9 @@ public override void OnLoaded() IsLoading = false; IsIndexing = false; + SelectedBaseModels.Clear(); + SelectedBaseModels.AddRange(settingsManager.Settings.SelectedBaseModels); + Logger.Info($"OnLoadedAsync in {sw.ElapsedMilliseconds}ms"); } @@ -172,6 +184,19 @@ public void ClearSearchQuery() SearchFilter = string.Empty; } + public void ClearOrSelectAllBaseModels() + { + if (SelectedBaseModels.Count == BaseModelOptions.Count) + { + SelectedBaseModels.Clear(); + } + else + { + SelectedBaseModels.Clear(); + SelectedBaseModels.AddRange(BaseModelOptions); + } + } + // ReSharper disable once UnusedParameterInPartialMethod partial void OnSearchFilterChanged(string value) { @@ -219,6 +244,12 @@ private bool ContainsBaseModel(CheckpointFolder folder) { ArgumentNullException.ThrowIfNull(folder); + if (SelectedBaseModels.Count == 0 || SelectedBaseModels.Count == BaseModelOptions.Count) + return true; + + if (!folder.DisplayedCheckpointFiles.Any()) + return true; + return folder.CheckpointFiles.Any(x => SelectedBaseModels.Contains(x.ConnectedModel?.BaseModel)) || folder.SubFolders.Any(ContainsBaseModel); } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs index 7eecc919d..6e2e7b154 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs @@ -96,13 +96,21 @@ partial void OnImageSourceChanged(ImageSource? value) } } + private static FilePickerFileType SupportedImages { get; } = + new("Supported Images") + { + Patterns = new[] { "*.png", "*.jpg", "*.jpeg" }, + AppleUniformTypeIdentifiers = new[] { "public.jpeg", "public.png" }, + MimeTypes = new[] { "image/jpeg", "image/png" } + }; + [RelayCommand] private async Task SelectImageFromFilePickerAsync() { var files = await App.StorageProvider.OpenFilePickerAsync( new FilePickerOpenOptions { - FileTypeFilter = [FilePickerFileTypes.ImagePng, FilePickerFileTypes.ImageJpg] + FileTypeFilter = [FilePickerFileTypes.ImagePng, FilePickerFileTypes.ImageJpg, SupportedImages] } ); diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index ddebb47b7..e8de7da9e 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -504,20 +504,27 @@ HorizontalAlignment="Right"> - - - - - - - - - - - - + + @@ -133,19 +189,31 @@ + ItemsSource="{Binding FilteredItems}"> + + + + @@ -163,53 +231,108 @@ - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + public required IEnumerable Paths { get; init; } + /// + /// Primary path of the extension. + /// + public IPathObject? PrimaryPath => Paths.FirstOrDefault(); + /// /// The version of the extension. /// @@ -23,4 +28,33 @@ public record InstalledPackageExtension /// The PackageExtension definition, if available. /// public PackageExtension? Definition { get; init; } + + public string Title + { + get + { + if (Definition?.Title is { } title) + { + return title; + } + + if (Paths.FirstOrDefault()?.Name is { } pathName) + { + return pathName; + } + + return ""; + } + } + + /// + /// Path containing PrimaryPath and its parent. + /// + public string DisplayPath => + PrimaryPath switch + { + null => "", + DirectoryPath { Parent: { } parentDir } dir => $"{parentDir.Name}/{dir.Name}", + _ => PrimaryPath.Name + }; } diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs index 686d84354..2a0e07e47 100644 --- a/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs +++ b/StabilityMatrix.Core/Models/Packages/Extensions/PackageExtensionVersion.cs @@ -1,3 +1,6 @@ namespace StabilityMatrix.Core.Models.Packages.Extensions; -public record PackageExtensionVersion : GitVersion; +public record PackageExtensionVersion : GitVersion +{ + public override string ToString() => base.ToString(); +}; From 38565917bc6b9589628007ba82c438245ae8f5ba Mon Sep 17 00:00:00 2001 From: ionite34 Date: Mon, 8 Jan 2024 22:48:21 +0800 Subject: [PATCH 139/276] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 37169d9f1..a37a873d3 100644 --- a/.gitignore +++ b/.gitignore @@ -397,3 +397,4 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml +.husky/pre-commit From 9b3130e66264d8e69df5685cf814edbfa626a646 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Mon, 8 Jan 2024 23:01:56 +0800 Subject: [PATCH 140/276] Fix search symbol visibility --- .../Views/PackageManager/PackageExtensionBrowserView.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml index 2bdf1c527..6ed1141cf 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml @@ -152,7 +152,7 @@ @@ -249,7 +249,7 @@ From e4198a15169b96aaea30c5379c1d4256ad858203 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Mon, 8 Jan 2024 23:14:50 +0800 Subject: [PATCH 141/276] Fix DirectoryPath delete via IPathObject --- StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs index fdca61d49..7415cd7a7 100644 --- a/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs +++ b/StabilityMatrix.Core/Models/FileInterfaces/DirectoryPath.cs @@ -125,6 +125,10 @@ public Task GetSizeAsync(bool includeSymbolicLinks) /// public Task DeleteAsync(bool recursive) => Task.Run(() => Delete(recursive)); + void IPathObject.Delete() => Info.Delete(true); + + Task IPathObject.DeleteAsync() => DeleteAsync(true); + private void ThrowIfNotExists() { if (!Exists) From a3155de7f8289beb0f01064d988e44234383dfd5 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Mon, 8 Jan 2024 23:15:11 +0800 Subject: [PATCH 142/276] Add installed extension uninstall --- .../PackageExtensionBrowserViewModel.cs | 34 +++++++++++++++++++ .../PackageExtensionBrowserView.axaml | 19 +++++++---- .../UninstallExtensionStep.cs | 18 ++++++++++ 3 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 StabilityMatrix.Core/Models/PackageModification/UninstallExtensionStep.cs diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs index 84f08ffa6..843ab2adb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using Avalonia.Controls; using CommunityToolkit.Mvvm.ComponentModel; @@ -152,9 +153,42 @@ public async Task InstallSelectedExtensions() var runner = new PackageModificationRunner { ShowDialogOnStart = true }; EventManager.Instance.OnPackageInstallProgressAdded(runner); + + await runner.ExecuteSteps(steps); + + ClearSelection(); + + await Refresh(); + } + + [RelayCommand] + public async Task UninstallSelectedExtensions() + { + var extensions = SelectedInstalledItems.Select(x => x.Item).ToArray(); + + if (extensions.Length == 0) + return; + + var steps = extensions + .Select( + ext => + new UninstallExtensionStep( + PackagePair!.BasePackage.ExtensionManager!, + PackagePair.InstalledPackage, + ext + ) + ) + .Cast() + .ToArray(); + + var runner = new PackageModificationRunner { ShowDialogOnStart = true }; + EventManager.Instance.OnPackageInstallProgressAdded(runner); + await runner.ExecuteSteps(steps); ClearSelection(); + + await Refresh(); } /// diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml index 6ed1141cf..7603a72f9 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml @@ -152,12 +152,12 @@ @@ -187,7 +187,9 @@ - + @@ -284,8 +286,10 @@ - - + @@ -324,6 +328,7 @@ Classes="accent" Content="{x:Static lang:Resources.Action_Update}"/> - - - - + Text="{Binding AvailableItemsSearchCollection.Query, Mode=TwoWay}"/> - - - - + Text="{Binding Query, Mode=TwoWay}"/> - - - - - - - - - - - - - + FontWeight="Medium" + Text="Update Available" /> + + + - - + + + + + + + + + + + + + - - + + - + VerticalAlignment="Center" /> + - + + Margin="0,0,0,8" /> @@ -520,7 +549,7 @@ - + @@ -528,9 +557,8 @@ - - - + + + FontSize="18" /> + VerticalAlignment="Center" /> - + - + Command="{Binding UpdateExistingMetadataCommand}" /> @@ -604,7 +632,7 @@ Title="{x:Static lang:Resources.TeachingTip_MoreCheckpointCategories}" PreferredPlacement="Bottom" IsOpen="{Binding IsCategoryTipOpen}" /> - + + Margin="0,0,0,4" /> + Margin="16,4,16,16" /> logger EventManager.Instance.ToggleProgressFlyout += (_, _) => progressFlyout?.Hide(); EventManager.Instance.CultureChanged += (_, _) => SetDefaultFonts(); EventManager.Instance.UpdateAvailable += OnUpdateAvailable; + EventManager.Instance.NavigateAndFindCivitModelRequested += OnNavigateAndFindCivitModelRequested; Observable .FromEventPattern(this, nameof(SizeChanged)) @@ -138,6 +140,11 @@ ILogger logger }); } + private void OnNavigateAndFindCivitModelRequested(object? sender, int e) + { + navigationService.NavigateTo(); + } + /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { diff --git a/StabilityMatrix.Core/Helper/EventManager.cs b/StabilityMatrix.Core/Helper/EventManager.cs index 22c09cc24..f77e3047b 100644 --- a/StabilityMatrix.Core/Helper/EventManager.cs +++ b/StabilityMatrix.Core/Helper/EventManager.cs @@ -39,6 +39,7 @@ private EventManager() { } public event EventHandler? InferenceUpscaleRequested; public event EventHandler? InferenceImageToImageRequested; public event EventHandler? InferenceImageToVideoRequested; + public event EventHandler? NavigateAndFindCivitModelRequested; public void OnGlobalProgressChanged(int progress) => GlobalProgressChanged?.Invoke(this, progress); @@ -86,4 +87,7 @@ public void OnInferenceImageToImageRequested(LocalImageFile imageFile) => public void OnInferenceImageToVideoRequested(LocalImageFile imageFile) => InferenceImageToVideoRequested?.Invoke(this, imageFile); + + public void OnNavigateAndFindCivitModelRequested(int modelId) => + NavigateAndFindCivitModelRequested?.Invoke(this, modelId); } diff --git a/StabilityMatrix.Core/Helper/ModelFinder.cs b/StabilityMatrix.Core/Helper/ModelFinder.cs index f16408215..129b07d97 100644 --- a/StabilityMatrix.Core/Helper/ModelFinder.cs +++ b/StabilityMatrix.Core/Helper/ModelFinder.cs @@ -56,9 +56,9 @@ public ModelFinder(ILiteDbContext liteDbContext, ICivitApi civitApi) // VersionResponse is not actually the full data of ModelVersion, so find it again var version = model.ModelVersions!.First(version => version.Id == versionResponse.Id); - var file = versionResponse - .Files - .First(file => hashBlake3.Equals(file.Hashes.BLAKE3, StringComparison.OrdinalIgnoreCase)); + var file = versionResponse.Files.First( + file => hashBlake3.Equals(file.Hashes.BLAKE3, StringComparison.OrdinalIgnoreCase) + ); return new ModelSearchResult(model, version, file); } @@ -79,7 +79,12 @@ public ModelFinder(ILiteDbContext liteDbContext, ICivitApi civitApi) } else { - Logger.Warn(e, "Could not find remote model version using hash {Hash}: {Error}", hashBlake3, e.Message); + Logger.Warn( + e, + "Could not find remote model version using hash {Hash}: {Error}", + hashBlake3, + e.Message + ); } return null; @@ -95,4 +100,36 @@ public ModelFinder(ILiteDbContext liteDbContext, ICivitApi civitApi) return null; } } + + public async Task> FindRemoteModelsById(IEnumerable ids) + { + try + { + // split ids into batches of 20 + var batches = ids.Select((id, index) => (id, index)) + .GroupBy(tuple => tuple.index / 20) + .Select(group => group.Select(tuple => tuple.id)); + + var results = new List(); + foreach (var batch in batches) + { + var response = await civitApi + .GetModels(new CivitModelsRequest { CommaSeparatedModelIds = string.Join(",", batch) }) + .ConfigureAwait(false); + + if (response.Items == null || response.Items.Count == 0) + continue; + + results.AddRange(response.Items); + } + + return results; + } + catch (Exception e) + { + Logger.Error("Error while finding remote models by id: {Error}", e.Message); + } + + return Enumerable.Empty(); + } } diff --git a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs index 01db400bc..96c3092cd 100644 --- a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs +++ b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs @@ -34,6 +34,16 @@ public record LocalModelFile /// public string? PreviewImageFullPath { get; set; } + /// + /// Whether or not an update is available for this model + /// + public bool HasUpdate { get; set; } + + /// + /// Last time this model was checked for an update + /// + public DateTimeOffset LastUpdateCheck { get; set; } + /// /// File name of the relative path. /// diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index bd0182b35..164433543 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -1,6 +1,4 @@ -using System.Collections.Concurrent; -using System.Collections.Immutable; -using System.Diagnostics; +using System.Diagnostics; using System.Text; using AsyncAwaitBestPractices; using AutoCtor; @@ -10,6 +8,7 @@ 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; @@ -22,6 +21,7 @@ public partial class ModelIndexService : IModelIndexService private readonly ILogger logger; private readonly ISettingsManager settingsManager; private readonly ILiteDbContext liteDbContext; + private readonly ModelFinder modelFinder; public Dictionary> ModelIndex { get; private set; } = new(); @@ -219,4 +219,43 @@ public async Task RemoveModelAsync(LocalModelFile model) return false; } + + // idk do somethin with this + public async Task CheckModelsForUpdateAsync() + { + var installedHashes = settingsManager.Settings.InstalledModelHashes; + var dbModels = ( + await liteDbContext.LocalModelFiles.FindAllAsync().ConfigureAwait(false) + ?? Enumerable.Empty() + ).ToList(); + var ids = dbModels + .Where(x => x.ConnectedModelInfo != null) + .Where( + x => x.LastUpdateCheck == default || x.LastUpdateCheck < DateTimeOffset.UtcNow.AddHours(-8) + ) + .Select(x => x.ConnectedModelInfo!.ModelId); + var remoteModels = (await modelFinder.FindRemoteModelsById(ids).ConfigureAwait(false)).ToList(); + + foreach (var dbModel in dbModels) + { + if (dbModel.ConnectedModelInfo == null) + continue; + + var remoteModel = remoteModels.FirstOrDefault(m => m.Id == dbModel.ConnectedModelInfo!.ModelId); + + var latestVersion = remoteModel?.ModelVersions?.FirstOrDefault(); + var latestHashes = latestVersion + ?.Files + ?.Where(f => f.Type == CivitFileType.Model) + .Select(f => f.Hashes.BLAKE3); + + if (latestHashes == null) + continue; + + dbModel.HasUpdate = !latestHashes.Any(hash => installedHashes?.Contains(hash) ?? false); + dbModel.LastUpdateCheck = DateTimeOffset.UtcNow; + + await liteDbContext.LocalModelFiles.UpsertAsync(dbModel).ConfigureAwait(false); + } + } } From 9402983b9218708ecb22292ff9c80e63dfa16a83 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 9 Jan 2024 21:09:01 -0800 Subject: [PATCH 148/276] refactor & un-async Index method --- .../CheckpointManager/CheckpointFolder.cs | 4 +-- .../ViewModels/CheckpointsPageViewModel.cs | 12 ++++---- StabilityMatrix.Core/Helper/ModelFinder.cs | 29 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs index 3b27867b5..7db5427dd 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs @@ -615,13 +615,13 @@ private IEnumerable GetCheckpointFiles() /// public void BackgroundIndex() { - Dispatcher.UIThread.InvokeAsync(IndexAsync, DispatcherPriority.Background); + Dispatcher.UIThread.Post(Index, DispatcherPriority.Background); } /// /// Indexes the folder for checkpoint files and refreshes the CheckPointFiles collection. /// - public async Task IndexAsync() + public void Index() { var updatedFolders = new List(); // Get subfolders diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 3902484bc..8639c2104 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -149,9 +149,9 @@ ModelFinder modelFinder .Subscribe(); } - public override async Task OnLoadedAsync() + public override void OnLoaded() { - await base.OnLoadedAsync(); + base.OnLoaded(); var sw = Stopwatch.StartNew(); // Set UI states @@ -171,7 +171,7 @@ public override async Task OnLoadedAsync() IsLoading = CheckpointFolders.Count == 0; IsIndexing = CheckpointFolders.Count > 0; - await IndexFoldersAsync(); + IndexFolders(); IsLoading = false; IsIndexing = false; @@ -268,7 +268,7 @@ private bool ContainsBaseModel(CheckpointFolder folder) ) || folder.SubFolders.Any(ContainsBaseModel); } - private async Task IndexFoldersAsync() + private void IndexFolders() { var modelsDirectory = settingsManager.ModelsDirectory; @@ -287,7 +287,7 @@ private async Task IndexFoldersAsync() // Get from cache or create new if (CheckpointFoldersCache.Lookup(folder) is { HasValue: true } result) { - await result.Value.IndexAsync(); + result.Value.Index(); updatedFolders.Add(result.Value); } else @@ -304,7 +304,7 @@ private async Task IndexFoldersAsync() DirectoryPath = folder, IsExpanded = true // Top level folders expanded by default }; - await checkpointFolder.IndexAsync(); + checkpointFolder.Index(); updatedFolders.Add(checkpointFolder); } } diff --git a/StabilityMatrix.Core/Helper/ModelFinder.cs b/StabilityMatrix.Core/Helper/ModelFinder.cs index 129b07d97..43517c6af 100644 --- a/StabilityMatrix.Core/Helper/ModelFinder.cs +++ b/StabilityMatrix.Core/Helper/ModelFinder.cs @@ -103,15 +103,16 @@ public ModelFinder(ILiteDbContext liteDbContext, ICivitApi civitApi) public async Task> FindRemoteModelsById(IEnumerable ids) { - try - { - // split ids into batches of 20 - var batches = ids.Select((id, index) => (id, index)) - .GroupBy(tuple => tuple.index / 20) - .Select(group => group.Select(tuple => tuple.id)); + var results = new List(); + + // split ids into batches of 20 + var batches = ids.Select((id, index) => (id, index)) + .GroupBy(tuple => tuple.index / 20) + .Select(group => group.Select(tuple => tuple.id)); - var results = new List(); - foreach (var batch in batches) + foreach (var batch in batches) + { + try { var response = await civitApi .GetModels(new CivitModelsRequest { CommaSeparatedModelIds = string.Join(",", batch) }) @@ -122,14 +123,12 @@ public async Task> FindRemoteModelsById(IEnumerable results.AddRange(response.Items); } - - return results; - } - catch (Exception e) - { - Logger.Error("Error while finding remote models by id: {Error}", e.Message); + catch (Exception e) + { + Logger.Error("Error while finding remote models by id: {Error}", e.Message); + } } - return Enumerable.Empty(); + return results; } } From c4b4fe1e30509c7f71386dbb78252d27a38ab1f7 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 9 Jan 2024 21:14:27 -0800 Subject: [PATCH 149/276] dont .tolist --- .../ViewModels/CheckpointManager/CheckpointFolder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs index 7db5427dd..714d0bd7f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs @@ -659,7 +659,7 @@ public void Index() SubFoldersCache.EditDiff(updatedFolders, (a, b) => a.Title == b.Title); // Index files - var files = GetCheckpointFiles().ToList(); + var files = GetCheckpointFiles(); Dispatcher.UIThread.Post( () => checkpointFilesCache.EditDiff(files, CheckpointFile.FilePathComparer), From 20ff29dee6db3e3b6b8ca5011e5007d7f6a7a2a0 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 9 Jan 2024 21:17:03 -0800 Subject: [PATCH 150/276] localize & chagenlog --- CHANGELOG.md | 1 + StabilityMatrix.Avalonia/Languages/Resources.Designer.cs | 9 +++++++++ StabilityMatrix.Avalonia/Languages/Resources.resx | 3 +++ StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml | 4 ++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 561f363f2..93aa67be9 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 base model filter to Checkpoints page - Search box on Checkpoints page now searches tags and trigger words - Added "Compatible Images" category when selecting images for Inference projects +- Added "Find in Model Browser" option to the right-click menu on the Checkpoints page ### Changed - Removed "Failed to load image" notification when loading some images on the Checkpoints page - Installed models will no longer be selectable on the Hugging Face tab of the model browser diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index df668ab03..2a08ac04f 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -1184,6 +1184,15 @@ public static string Label_FindConnectedMetadata { } } + /// + /// Looks up a localized string similar to Find in Model Browser. + /// + public static string Label_FindInModelBrowser { + get { + return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); + } + } + /// /// Looks up a localized string similar to First Page. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index d96411540..701544994 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -927,4 +927,7 @@ Quality + + Find in Model Browser + diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index 5771612c5..c2831986f 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -72,7 +72,7 @@ IconSource="Copy" /> + Text="{x:Static lang:Resources.Label_UpdateAvailable}" /> + --> ? ExtraExtensionManifestUrls { get; set; } + /// /// Get the launch args host option value. /// @@ -239,7 +241,11 @@ public void OnDeserialized() if (string.IsNullOrWhiteSpace(InstalledBranch) && !string.IsNullOrWhiteSpace(PackageVersion)) { // release mode - Version = new InstalledPackageVersion { InstalledReleaseVersion = PackageVersion, IsPrerelease = false }; + Version = new InstalledPackageVersion + { + InstalledReleaseVersion = PackageVersion, + IsPrerelease = false + }; } else if (!string.IsNullOrWhiteSpace(PackageVersion)) { diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs index fe8384fbb..baf4fb3fb 100644 --- a/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs +++ b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs @@ -35,7 +35,22 @@ CancellationToken cancellationToken protected virtual IEnumerable GetManifests(InstalledPackage installedPackage) { - return DefaultManifests; + if (installedPackage.ExtraExtensionManifestUrls is not { } customUrls) + { + return DefaultManifests; + } + + var manifests = DefaultManifests.ToList(); + + foreach (var url in customUrls) + { + if (!string.IsNullOrEmpty(url) && Uri.TryCreate(url, UriKind.Absolute, out var uri)) + { + manifests.Add(new ExtensionManifest(uri)); + } + } + + return manifests; } /// From cec7342f6d11c18302375ae166f130b92893c791 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 11 Jan 2024 10:22:39 +0800 Subject: [PATCH 152/276] Move DirectoryPathExtensions to Core, add cancel token --- .../ViewModels/Dialogs/InstallerViewModel.cs | 1 + .../Dialogs/OneClickInstallViewModel.cs | 31 +++------- .../PackageInstallDetailViewModel.cs | 1 + .../Extensions/DirectoryPathExtensions.cs | 58 ++++++++++++------- 4 files changed, 46 insertions(+), 45 deletions(-) rename {StabilityMatrix.Avalonia => StabilityMatrix.Core}/Extensions/DirectoryPathExtensions.cs (59%) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs index 46fd634b0..ea12d39e0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs @@ -22,6 +22,7 @@ using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Factory; using StabilityMatrix.Core.Models; diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs index e18e710ef..14d218ad7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs @@ -12,6 +12,7 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Factory; using StabilityMatrix.Core.Models; @@ -87,15 +88,12 @@ INavigationService navigationService SubHeaderText = Resources.Text_OneClickInstaller_SubHeader; ShowInstallButton = true; - var filteredPackages = this.packageFactory - .GetAllAvailablePackages() + var filteredPackages = this.packageFactory.GetAllAvailablePackages() .Where(p => p is { OfferInOneClickInstaller: true, IsCompatible: true }) .ToList(); AllPackages = new ObservableCollection( - filteredPackages.Any() - ? filteredPackages - : this.packageFactory.GetAllAvailablePackages() + filteredPackages.Any() ? filteredPackages : this.packageFactory.GetAllAvailablePackages() ); SelectedPackage = AllPackages[0]; } @@ -136,11 +134,7 @@ private async Task DoInstall() }; // get latest version & download & install - var installLocation = Path.Combine( - settingsManager.LibraryDir, - "Packages", - SelectedPackage.Name - ); + var installLocation = Path.Combine(settingsManager.LibraryDir, "Packages", SelectedPackage.Name); if (Directory.Exists(installLocation)) { var installPath = new DirectoryPath(installLocation); @@ -163,11 +157,7 @@ private async Task DoInstall() var torchVersion = SelectedPackage.GetRecommendedTorchVersion(); var recommendedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod; - var downloadStep = new DownloadPackageVersionStep( - SelectedPackage, - installLocation, - downloadVersion - ); + var downloadStep = new DownloadPackageVersionStep(SelectedPackage, installLocation, downloadVersion); steps.Add(downloadStep); var installStep = new InstallPackageStep( @@ -199,17 +189,10 @@ private async Task DoInstall() PreferredSharedFolderMethod = recommendedSharedFolderMethod }; - var addInstalledPackageStep = new AddInstalledPackageStep( - settingsManager, - installedPackage - ); + var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, installedPackage); steps.Add(addInstalledPackageStep); - var runner = new PackageModificationRunner - { - ShowDialogOnStart = true, - HideCloseButton = true, - }; + var runner = new PackageModificationRunner { ShowDialogOnStart = true, HideCloseButton = true, }; EventManager.Instance.OnPackageInstallProgressAdded(runner); await runner.ExecuteSteps(steps); diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index 3c940d25a..cc0f6f06a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -16,6 +16,7 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Database; diff --git a/StabilityMatrix.Avalonia/Extensions/DirectoryPathExtensions.cs b/StabilityMatrix.Core/Extensions/DirectoryPathExtensions.cs similarity index 59% rename from StabilityMatrix.Avalonia/Extensions/DirectoryPathExtensions.cs rename to StabilityMatrix.Core/Extensions/DirectoryPathExtensions.cs index 508d0818a..eb6251d0b 100644 --- a/StabilityMatrix.Avalonia/Extensions/DirectoryPathExtensions.cs +++ b/StabilityMatrix.Core/Extensions/DirectoryPathExtensions.cs @@ -1,12 +1,9 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; using Polly; using StabilityMatrix.Core.Models.FileInterfaces; -namespace StabilityMatrix.Avalonia.Extensions; +namespace StabilityMatrix.Core.Extensions; [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public static class DirectoryPathExtensions @@ -15,21 +12,32 @@ public static class DirectoryPathExtensions /// Deletes a directory and all of its contents recursively. /// Uses Polly to retry the deletion if it fails, up to 5 times with an exponential backoff. /// - public static Task DeleteVerboseAsync(this DirectoryPath directory, ILogger? logger = default) + public static Task DeleteVerboseAsync( + this DirectoryPath directory, + ILogger? logger = default, + CancellationToken cancellationToken = default + ) { - var policy = Policy.Handle() - .WaitAndRetryAsync(3, attempt => TimeSpan.FromMilliseconds(50 * Math.Pow(2, attempt)), + var policy = Policy + .Handle() + .WaitAndRetryAsync( + 3, + attempt => TimeSpan.FromMilliseconds(50 * Math.Pow(2, attempt)), onRetry: (exception, calculatedWaitDuration) => { logger?.LogWarning( exception, "Deletion of {TargetDirectory} failed. Retrying in {CalculatedWaitDuration}", - directory, calculatedWaitDuration); - }); + directory, + calculatedWaitDuration + ); + } + ); return policy.ExecuteAsync(async () => { - await Task.Run(() => { DeleteVerbose(directory, logger); }); + await Task.Run(() => DeleteVerbose(directory, logger, cancellationToken), cancellationToken) + .ConfigureAwait(false); }); } @@ -37,8 +45,14 @@ public static Task DeleteVerboseAsync(this DirectoryPath directory, ILogger? log /// Deletes a directory and all of its contents recursively. /// Removes link targets without deleting the source. /// - public static void DeleteVerbose(this DirectoryPath directory, ILogger? logger = default) + public static void DeleteVerbose( + this DirectoryPath directory, + ILogger? logger = default, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + // Skip if directory does not exist if (!directory.Exists) { @@ -47,7 +61,7 @@ public static void DeleteVerbose(this DirectoryPath directory, ILogger? logger = // For junction points, delete with recursive false if (directory.IsSymbolicLink) { - logger?.LogInformation("Removing junction point {TargetDirectory}", directory); + logger?.LogInformation("Removing junction point {TargetDirectory}", directory.FullPath); try { directory.Delete(false); @@ -55,29 +69,31 @@ public static void DeleteVerbose(this DirectoryPath directory, ILogger? logger = } catch (IOException ex) { - throw new IOException($"Failed to delete junction point {directory}", ex); + throw new IOException($"Failed to delete junction point {directory.FullPath}", ex); } } // Recursively delete all subdirectories - foreach (var subDir in directory.Info.EnumerateDirectories()) + foreach (var subDir in directory.EnumerateDirectories()) { - DeleteVerbose(subDir, logger); + DeleteVerbose(subDir, logger, cancellationToken); } - + // Delete all files in the directory - foreach (var filePath in directory.Info.EnumerateFiles()) + foreach (var filePath in directory.EnumerateFiles()) { + cancellationToken.ThrowIfCancellationRequested(); + try { - filePath.Attributes = FileAttributes.Normal; + filePath.Info.Attributes = FileAttributes.Normal; filePath.Delete(); } catch (IOException ex) { - throw new IOException($"Failed to delete file {filePath.FullName}", ex); + throw new IOException($"Failed to delete file {filePath.FullPath}", ex); } } - + // Delete this directory try { From 9da30935f1fdcd13df01461a05e4d1fc834e2b16 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 11 Jan 2024 10:36:37 +0800 Subject: [PATCH 153/276] Use verbose delete for extension uninstall --- .backportrc.json | 9 +++++++++ .../Extensions/GitPackageExtensionManager.cs | 12 +++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .backportrc.json diff --git a/.backportrc.json b/.backportrc.json new file mode 100644 index 000000000..f58885352 --- /dev/null +++ b/.backportrc.json @@ -0,0 +1,9 @@ +{ + "repoOwner": "ionite34", + "repoName": "StabilityMatrix", + "branches": ["main"], + "targetBranchChoices": ["dev"], + "fork": false, + "targetPRLabels": ["backport"], + "prTitle": "[{{sourceBranch}} to {{targetBranch}}] backport: {{sourcePullRequest.title}} ({{sourcePullRequest.number}})" +} diff --git a/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs index baf4fb3fb..1213aab86 100644 --- a/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs +++ b/StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs @@ -1,5 +1,6 @@ using KGySoft.CoreLibraries; using NLog; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; @@ -216,7 +217,16 @@ public async Task UninstallExtensionAsync( { cancellationToken.ThrowIfCancellationRequested(); - await path.DeleteAsync().ConfigureAwait(false); + if (path is DirectoryPath directoryPath) + { + await directoryPath + .DeleteVerboseAsync(cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + else + { + await path.DeleteAsync().ConfigureAwait(false); + } } } } From 76660fdb03b5d079eece87d6792755694a71dfa4 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 11 Jan 2024 11:07:46 +0800 Subject: [PATCH 154/276] Extensions menu separator and visibility --- .../PackageManager/PackageCardViewModel.cs | 4 ++++ .../Views/PackageManagerPage.axaml | 24 ++++++++++--------- .../Models/Packages/BasePackage.cs | 4 ++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 83ab6fcbc..aa830bdaa 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -78,6 +78,9 @@ public partial class PackageCardViewModel : ProgressViewModel [ObservableProperty] private bool canUseSharedOutput; + [ObservableProperty] + private bool canUseExtensions; + public PackageCardViewModel( ILogger logger, IPackageFactory packageFactory, @@ -122,6 +125,7 @@ partial void OnPackageChanged(InstalledPackage? value) basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Symlink) ?? false; UseSharedOutput = Package?.UseSharedOutputFolder ?? false; CanUseSharedOutput = basePackage?.SharedOutputFolders != null; + CanUseExtensions = basePackage?.SupportsExtensions ?? false; } } diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml index f6e496c8c..456c3697a 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml @@ -66,31 +66,33 @@ + Command="{Binding OpenOnGitHubCommand}"> + Value="fa-brands fa-github" /> + + + + Command="{Binding OpenPythonPackagesDialogCommand}"> + Value="fa-brands fa-python" /> - + Header="Extensions" + IsVisible="{Binding CanUseExtensions}" + Command="{Binding OpenExtensionsDialogCommand}"> + Value="fa-solid fa-puzzle-piece" /> diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 61b261bb9..2972277bd 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -162,12 +162,12 @@ public virtual TorchVersion GetRecommendedTorchVersion() /// /// If defined, this package supports extensions using this manager. /// - public virtual IPackageExtensionManager? ExtensionManager { get; } + public virtual IPackageExtensionManager? ExtensionManager => null; /// /// True if this package supports extensions. /// - [MemberNotNullWhen(true)] + [MemberNotNullWhen(true, nameof(ExtensionManager))] public virtual bool SupportsExtensions => ExtensionManager is not null; public abstract Task GetAllVersionOptions(); From 3da476fa2e98f692e131c77ab4188a442aaeddc4 Mon Sep 17 00:00:00 2001 From: ionite34 Date: Thu, 11 Jan 2024 11:16:57 +0800 Subject: [PATCH 155/276] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93aa67be9..4e4fed95a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.8.0-pre.1 ### Added +- Added Package Extensions (Plugins) management - accessible from the Packages' 3-dot menu. Currently supports ComfyUI. - Added base model filter to Checkpoints page - Search box on Checkpoints page now searches tags and trigger words - Added "Compatible Images" category when selecting images for Inference projects From 8f1d28bd3f1702af383eff93e20781ed3d3190b1 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 10 Jan 2024 19:20:50 -0800 Subject: [PATCH 156/276] make extension checkbox toggle when you click anywhere & make downloads tab taller --- .../Models/SelectableItem.cs | 8 +- .../PackageExtensionBrowserViewModel.cs | 1 + .../PackageExtensionBrowserView.axaml | 287 ++++++++++-------- .../Views/ProgressManagerPage.axaml | 15 +- 4 files changed, 171 insertions(+), 140 deletions(-) rename {StabilityMatrix.Core => StabilityMatrix.Avalonia}/Models/SelectableItem.cs (81%) diff --git a/StabilityMatrix.Core/Models/SelectableItem.cs b/StabilityMatrix.Avalonia/Models/SelectableItem.cs similarity index 81% rename from StabilityMatrix.Core/Models/SelectableItem.cs rename to StabilityMatrix.Avalonia/Models/SelectableItem.cs index 906d36fef..599884ea8 100644 --- a/StabilityMatrix.Core/Models/SelectableItem.cs +++ b/StabilityMatrix.Avalonia/Models/SelectableItem.cs @@ -1,7 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Windows.Input; +using CommunityToolkit.Mvvm.Input; using DynamicData.Binding; using JetBrains.Annotations; -namespace StabilityMatrix.Core.Models; +namespace StabilityMatrix.Avalonia.Models; [PublicAPI] public class SelectableItem(T item) : AbstractNotifyPropertyChanged, IEquatable> @@ -16,6 +20,8 @@ public bool IsSelected set => SetAndRaise(ref _isSelected, value); } + public ICommand ToggleSelectedCommand => new RelayCommand(() => IsSelected = !IsSelected); + /// public bool Equals(SelectableItem? other) { diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs index f45807257..dda91fb0e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -19,6 +19,7 @@ using KGySoft.CoreLibraries; using StabilityMatrix.Avalonia.Collections; using StabilityMatrix.Avalonia.Languages; +using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Dialogs; diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml index b13e011f4..284b70ef0 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml @@ -15,6 +15,7 @@ xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" + xmlns:models1="clr-namespace:StabilityMatrix.Avalonia.Models" d:DataContext="{x:Static mocks:DesignData.PackageExtensionBrowserViewModel}" x:DataType="packageManager:PackageExtensionBrowserViewModel" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" @@ -22,135 +23,154 @@ - - + + - + - + - + - + - + - - - - + Watermark="{x:Static lang:Resources.Action_Search}" + HorizontalAlignment="Stretch" + VerticalAlignment="Center" + Text="{Binding AvailableItemsSearchCollection.Query, Mode=TwoWay}" /> + - + - - - @@ -186,7 +206,7 @@ - + @@ -194,49 +214,49 @@ Margin="32,16" IsIndeterminate="True" IsEnabled="{Binding IsLoading}" - IsVisible="{Binding IsLoading}"/> + IsVisible="{Binding IsLoading}" /> - + - + - + - - - + + Grid.Row="1"> + IsVisible="{Binding IsLoading}" /> - + - + @@ -301,17 +320,17 @@ diff --git a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml index c239f9e86..a71c8cdc5 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/UpscalerCard.axaml @@ -8,7 +8,7 @@ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:vmInference="using:StabilityMatrix.Avalonia.ViewModels.Inference" xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" x:DataType="vmInference:UpscalerCardViewModel"> diff --git a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml index c6e7f3e1f..5f156f844 100644 --- a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml +++ b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml @@ -1,8 +1,6 @@  + xmlns:controls="using:StabilityMatrix.Avalonia.Controls"> diff --git a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml.cs b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml.cs index 2c91651ec..af905ecf8 100644 --- a/StabilityMatrix.Avalonia/Controls/StarsRating.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/StarsRating.axaml.cs @@ -3,17 +3,12 @@ using System.Linq; using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Documents; using Avalonia.Controls.Primitives; -using Avalonia.Data; using Avalonia.Layout; -using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Media; using Avalonia.VisualTree; +using FluentIcons.Avalonia.Fluent; using FluentIcons.Common; -using FluentIcons.FluentAvalonia; -using SpacedGridControl.Avalonia; -using StabilityMatrix.Avalonia.Styles; namespace StabilityMatrix.Avalonia.Controls; @@ -36,10 +31,10 @@ public bool IsEditable set => SetValue(IsEditableProperty, value); } - public static readonly StyledProperty MaximumProperty = AvaloniaProperty.Register< - StarsRating, - int - >(nameof(Maximum), 5); + public static readonly StyledProperty MaximumProperty = AvaloniaProperty.Register( + nameof(Maximum), + 5 + ); public int Maximum { diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 9f2421989..48cea020d 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,1635 +59,2460 @@ 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 Trigger Words. + /// + public static string Action_CopyTriggerWords { get { - return ResourceManager.GetString("Label_Version", resourceCulture); + return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); } } - public static string Label_VersionType { + /// + /// Looks up a localized string similar to Delete. + /// + public static string Action_Delete { get { - return ResourceManager.GetString("Label_VersionType", resourceCulture); + return ResourceManager.GetString("Action_Delete", resourceCulture); } } - public static string Label_Releases { + /// + /// Looks up a localized string similar to Disconnect. + /// + public static string Action_Disconnect { get { - return ResourceManager.GetString("Label_Releases", resourceCulture); + return ResourceManager.GetString("Action_Disconnect", resourceCulture); } } - public static string Label_Branches { + /// + /// Looks up a localized string similar to Downgrade. + /// + public static string Action_Downgrade { get { - return ResourceManager.GetString("Label_Branches", resourceCulture); + return ResourceManager.GetString("Action_Downgrade", resourceCulture); } } - public static string Label_DragAndDropCheckpointsHereToImport { + /// + /// Looks up a localized string similar to Edit. + /// + public static string Action_Edit { get { - return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); + return ResourceManager.GetString("Action_Edit", resourceCulture); } } - public static string Label_Emphasis { + /// + /// Looks up a localized string similar to Exit Application. + /// + public static string Action_ExitApplication { get { - return ResourceManager.GetString("Label_Emphasis", resourceCulture); + return ResourceManager.GetString("Action_ExitApplication", resourceCulture); } } - public static string Label_Deemphasis { + /// + /// Looks up a localized string similar to Import. + /// + public static string Action_Import { get { - return ResourceManager.GetString("Label_Deemphasis", resourceCulture); + return ResourceManager.GetString("Action_Import", resourceCulture); } } - public static string Label_EmbeddingsOrTextualInversion { + /// + /// Looks up a localized string similar to Install. + /// + public static string Action_Install { get { - return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); + return ResourceManager.GetString("Action_Install", resourceCulture); } } - public static string Label_NetworksLoraOrLycoris { + /// + /// Looks up a localized string similar to Install Now. + /// + public static string Action_InstallNow { get { - return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); + return ResourceManager.GetString("Action_InstallNow", resourceCulture); } } - public static string Label_Comments { + /// + /// Looks up a localized string similar to Launch. + /// + public static string Action_Launch { get { - return ResourceManager.GetString("Label_Comments", resourceCulture); + return ResourceManager.GetString("Action_Launch", resourceCulture); } } - public static string Label_ShowPixelGridAtHighZoomLevels { + /// + /// Looks up a localized string similar to Login. + /// + public static string Action_Login { get { - return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); + return ResourceManager.GetString("Action_Login", resourceCulture); } } - public static string Label_Steps { + /// + /// Looks up a localized string similar to New. + /// + public static string Action_New { get { - return ResourceManager.GetString("Label_Steps", resourceCulture); + return ResourceManager.GetString("Action_New", resourceCulture); } } - public static string Label_StepsBase { + /// + /// Looks up a localized string similar to OK. + /// + public static string Action_OK { get { - return ResourceManager.GetString("Label_StepsBase", resourceCulture); + return ResourceManager.GetString("Action_OK", resourceCulture); } } - public static string Label_StepsRefiner { + /// + /// Looks up a localized string similar to Open on GitHub. + /// + public static string Action_OpenGithub { get { - return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); + return ResourceManager.GetString("Action_OpenGithub", resourceCulture); } } - public static string Label_CFGScale { + /// + /// Looks up a localized string similar to Open in Browser. + /// + public static string Action_OpenInBrowser { get { - return ResourceManager.GetString("Label_CFGScale", resourceCulture); + return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); } } - public static string Label_DenoisingStrength { + /// + /// Looks up a localized string similar to Open in Explorer. + /// + public static string Action_OpenInExplorer { get { - return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); + return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); } } - public static string Label_Width { + /// + /// Looks up a localized string similar to Open in Finder. + /// + public static string Action_OpenInFinder { get { - return ResourceManager.GetString("Label_Width", resourceCulture); + return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); } } - public static string Label_Height { + /// + /// Looks up a localized string similar to Open in Image Viewer. + /// + public static string Action_OpenInViewer { get { - return ResourceManager.GetString("Label_Height", resourceCulture); + return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); } } - public static string Label_Refiner { + /// + /// Looks up a localized string similar to Open on CivitAI. + /// + public static string Action_OpenOnCivitAi { get { - return ResourceManager.GetString("Label_Refiner", resourceCulture); + return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); } } - public static string Label_VAE { + /// + /// Looks up a localized string similar to Open on Hugging Face. + /// + public static string Action_OpenOnHuggingFace { get { - return ResourceManager.GetString("Label_VAE", resourceCulture); + return ResourceManager.GetString("Action_OpenOnHuggingFace", resourceCulture); } } - public static string Label_Model { + /// + /// Looks up a localized string similar to Open Project.... + /// + public static string Action_OpenProjectEllipsis { get { - return ResourceManager.GetString("Label_Model", resourceCulture); + return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); } } - public static string Action_Connect { + /// + /// Looks up a localized string similar to Open Web UI. + /// + public static string Action_OpenWebUI { get { - return ResourceManager.GetString("Action_Connect", resourceCulture); + return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); } } - public static string Label_ConnectingEllipsis { + /// + /// Looks up a localized string similar to Quit. + /// + public static string Action_Quit { get { - return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); + return ResourceManager.GetString("Action_Quit", resourceCulture); } } - public static string Action_Close { + /// + /// Looks up a localized string similar to Refresh. + /// + public static string Action_Refresh { get { - return ResourceManager.GetString("Action_Close", resourceCulture); + return ResourceManager.GetString("Action_Refresh", resourceCulture); } } - public static string Label_WaitingToConnectEllipsis { + /// + /// Looks up a localized string similar to Relaunch. + /// + public static string Action_Relaunch { get { - return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); + return ResourceManager.GetString("Action_Relaunch", resourceCulture); } } - public static string Label_UpdateAvailable { + /// + /// Looks up a localized string similar to Relaunch Later. + /// + public static string Action_RelaunchLater { get { - return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); + return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); } } - public static string Label_BecomeAPatron { + /// + /// Looks up a localized string similar to Remind Me Later. + /// + public static string Action_RemindMeLater { get { - return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); + return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); } } - public static string Label_JoinDiscord { + /// + /// Looks up a localized string similar to Remove. + /// + public static string Action_Remove { get { - return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); + return ResourceManager.GetString("Action_Remove", resourceCulture); } } - public static string Label_Downloads { + /// + /// Looks up a localized string similar to Rename. + /// + public static string Action_Rename { get { - return ResourceManager.GetString("Label_Downloads", resourceCulture); + return ResourceManager.GetString("Action_Rename", resourceCulture); } } - public static string Action_Install { + /// + /// Looks up a localized string similar to Replace Contents. + /// + public static string Action_ReplaceContents { get { - return ResourceManager.GetString("Action_Install", resourceCulture); + return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); } } - public static string Label_SkipSetup { + /// + /// Looks up a localized string similar to Restart. + /// + public static string Action_Restart { get { - return ResourceManager.GetString("Label_SkipSetup", resourceCulture); + return ResourceManager.GetString("Action_Restart", resourceCulture); } } - public static string Label_UnexpectedErrorOccurred { + /// + /// Looks up a localized string similar to Restore Default Layout. + /// + public static string Action_RestoreDefaultLayout { get { - return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); + return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); } } - public static string Action_ExitApplication { + /// + /// Looks up a localized string similar to Retry. + /// + public static string Action_Retry { get { - return ResourceManager.GetString("Action_ExitApplication", resourceCulture); + return ResourceManager.GetString("Action_Retry", resourceCulture); } } - public static string Label_DisplayName { + /// + /// Looks up a localized string similar to Save. + /// + public static string Action_Save { get { - return ResourceManager.GetString("Label_DisplayName", resourceCulture); + return ResourceManager.GetString("Action_Save", resourceCulture); } } - public static string Label_InstallationWithThisNameExists { + /// + /// Looks up a localized string similar to Save As.... + /// + public static string Action_SaveAsEllipsis { get { - return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); + return ResourceManager.GetString("Action_SaveAsEllipsis", resourceCulture); } } - public static string Label_PleaseChooseDifferentName { + /// + /// Looks up a localized string similar to Search. + /// + public static string Action_Search { get { - return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); + return ResourceManager.GetString("Action_Search", resourceCulture); } } - public static string Label_AdvancedOptions { + /// + /// Looks up a localized string similar to Select All. + /// + public static string Action_SelectAll { get { - return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); + return ResourceManager.GetString("Action_SelectAll", resourceCulture); } } - public static string Label_Commit { + /// + /// Looks up a localized string similar to Select Directory. + /// + public static string Action_SelectDirectory { get { - return ResourceManager.GetString("Label_Commit", resourceCulture); + return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); } } - public static string Label_SharedModelFolderStrategy { + /// + /// Looks up a localized string similar to Select File. + /// + public static string Action_SelectFile { get { - return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); + return ResourceManager.GetString("Action_SelectFile", resourceCulture); } } - public static string Label_PyTorchVersion { + /// + /// Looks up a localized string similar to Send. + /// + public static string Action_Send { get { - return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); + return ResourceManager.GetString("Action_Send", resourceCulture); } } - public static string Label_CloseDialogWhenFinished { + /// + /// Looks up a localized string similar to Send Input. + /// + public static string Action_SendInput { get { - return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); + return ResourceManager.GetString("Action_SendInput", resourceCulture); } } - public static string Label_DataDirectory { + /// + /// Looks up a localized string similar to Send to Inference. + /// + public static string Action_SendToInference { get { - return ResourceManager.GetString("Label_DataDirectory", resourceCulture); + return ResourceManager.GetString("Action_SendToInference", resourceCulture); } } - public static string Label_DataDirectoryExplanation { + /// + /// Looks up a localized string similar to Show in Explorer. + /// + public static string Action_ShowInExplorer { get { - return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); + return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); } } - public static string Label_FatWarning { + /// + /// Looks up a localized string similar to Signup. + /// + public static string Action_Signup { get { - return ResourceManager.GetString("Label_FatWarning", resourceCulture); + return ResourceManager.GetString("Action_Signup", resourceCulture); } } - public static string Label_PortableMode { + /// + /// Looks up a localized string similar to Stop. + /// + public static string Action_Stop { get { - return ResourceManager.GetString("Label_PortableMode", resourceCulture); + return ResourceManager.GetString("Action_Stop", resourceCulture); } } - public static string Label_PortableModeExplanation { + /// + /// Looks up a localized string similar to Uninstall. + /// + public static string Action_Uninstall { get { - return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); + return ResourceManager.GetString("Action_Uninstall", resourceCulture); } } - public static string Action_Continue { + /// + /// Looks up a localized string similar to Update. + /// + public static string Action_Update { get { - return ResourceManager.GetString("Action_Continue", resourceCulture); + return ResourceManager.GetString("Action_Update", resourceCulture); } } - public static string Label_PreviousImage { + /// + /// Looks up a localized string similar to Update Existing Metadata. + /// + public static string Action_UpdateExistingMetadata { get { - return ResourceManager.GetString("Label_PreviousImage", resourceCulture); + return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); } } - public static string Label_NextImage { + /// + /// Looks up a localized string similar to Upgrade. + /// + public static string Action_Upgrade { get { - return ResourceManager.GetString("Label_NextImage", resourceCulture); + return ResourceManager.GetString("Action_Upgrade", resourceCulture); } } - public static string Label_ModelDescription { + /// + /// Looks up a localized string similar to Yes. + /// + public static string Action_Yes { get { - return ResourceManager.GetString("Label_ModelDescription", resourceCulture); + return ResourceManager.GetString("Action_Yes", resourceCulture); } } - public static string Label_NewVersionAvailable { + /// + /// Looks up a localized string similar to About. + /// + public static string Label_About { get { - return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); + return ResourceManager.GetString("Label_About", resourceCulture); } } - public static string Label_ImportLatest { + /// + /// Looks up a localized string similar to Accounts. + /// + public static string Label_Accounts { get { - return ResourceManager.GetString("Label_ImportLatest", resourceCulture); + return ResourceManager.GetString("Label_Accounts", resourceCulture); } } - public static string Label_AllVersions { + /// + /// Looks up a localized string similar to Addons. + /// + public static string Label_Addons { get { - return ResourceManager.GetString("Label_AllVersions", resourceCulture); + return ResourceManager.GetString("Label_Addons", resourceCulture); } } - public static string Label_ModelSearchWatermark { + /// + /// Looks up a localized string similar to Add Stability Matrix to the Start Menu. + /// + public static string Label_AddToStartMenu { get { - return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); } } - public static string Action_Search { + /// + /// 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("Action_Search", resourceCulture); + return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); } } - public static string Label_Sort { + /// + /// Looks up a localized string similar to Advanced Options. + /// + public static string Label_AdvancedOptions { get { - return ResourceManager.GetString("Label_Sort", resourceCulture); + return ResourceManager.GetString("Label_AdvancedOptions", resourceCulture); } } - public static string Label_TimePeriod { + /// + /// Looks up a localized string similar to All Versions. + /// + public static string Label_AllVersions { get { - return ResourceManager.GetString("Label_TimePeriod", resourceCulture); + return ResourceManager.GetString("Label_AllVersions", resourceCulture); } } - public static string Label_ModelType { + /// + /// Looks up a localized string similar to API Key. + /// + public static string Label_ApiKey { get { - return ResourceManager.GetString("Label_ModelType", resourceCulture); + return ResourceManager.GetString("Label_ApiKey", resourceCulture); } } - public static string Label_BaseModel { + /// + /// Looks up a localized string similar to Appearance. + /// + public static string Label_Appearance { get { - return ResourceManager.GetString("Label_BaseModel", resourceCulture); + return ResourceManager.GetString("Label_Appearance", resourceCulture); } } - public static string Label_ShowNsfwContent { + /// + /// Looks up a localized string similar to Are you sure?. + /// + public static string Label_AreYouSure { get { - return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); + return ResourceManager.GetString("Label_AreYouSure", resourceCulture); } } - public static string Label_DataProvidedByCivitAi { + /// + /// Looks up a localized string similar to Augmentation Level. + /// + public static string Label_AugmentationLevel { get { - return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); + return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); } } - public static string Label_Page { + /// + /// Looks up a localized string similar to Auto Completion. + /// + public static string Label_AutoCompletion { get { - return ResourceManager.GetString("Label_Page", resourceCulture); + return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); } } - public static string Label_FirstPage { + /// + /// Looks up a localized string similar to Automatically scroll to end of console output. + /// + public static string Label_AutoScrollToEnd { get { - return ResourceManager.GetString("Label_FirstPage", resourceCulture); + return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); } } - public static string Label_PreviousPage { + /// + /// Looks up a localized string similar to Auto Updates. + /// + public static string Label_AutoUpdates { get { - return ResourceManager.GetString("Label_PreviousPage", resourceCulture); + return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); } } - public static string Label_NextPage { + /// + /// Looks up a localized string similar to Base Model. + /// + public static string Label_BaseModel { get { - return ResourceManager.GetString("Label_NextPage", resourceCulture); + return ResourceManager.GetString("Label_BaseModel", resourceCulture); } } - public static string Label_LastPage { + /// + /// Looks up a localized string similar to Batch Index. + /// + public static string Label_BatchIndex { get { - return ResourceManager.GetString("Label_LastPage", resourceCulture); + return ResourceManager.GetString("Label_BatchIndex", resourceCulture); } } - public static string Action_Rename { + /// + /// Looks up a localized string similar to Become a Patron. + /// + public static string Label_BecomeAPatron { get { - return ResourceManager.GetString("Action_Rename", resourceCulture); + return ResourceManager.GetString("Label_BecomeAPatron", resourceCulture); } } - public static string Action_Delete { + /// + /// Looks up a localized string similar to Branch. + /// + public static string Label_Branch { get { - return ResourceManager.GetString("Action_Delete", resourceCulture); + return ResourceManager.GetString("Label_Branch", resourceCulture); } } - public static string Action_OpenOnCivitAi { + /// + /// Looks up a localized string similar to Branches. + /// + public static string Label_Branches { get { - return ResourceManager.GetString("Action_OpenOnCivitAi", resourceCulture); + return ResourceManager.GetString("Label_Branches", resourceCulture); } } - public static string Label_ConnectedModel { + /// + /// Looks up a localized string similar to Callstack. + /// + public static string Label_Callstack { get { - return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); + return ResourceManager.GetString("Label_Callstack", resourceCulture); } } - public static string Label_LocalModel { + /// + /// Looks up a localized string similar to Categories. + /// + public static string Label_Categories { get { - return ResourceManager.GetString("Label_LocalModel", resourceCulture); + return ResourceManager.GetString("Label_Categories", resourceCulture); } } - public static string Action_ShowInExplorer { + /// + /// Looks up a localized string similar to CFG Scale. + /// + public static string Label_CFGScale { get { - return ResourceManager.GetString("Action_ShowInExplorer", resourceCulture); + return ResourceManager.GetString("Label_CFGScale", resourceCulture); } } - public static string Action_New { + /// + /// Looks up a localized string similar to Checkpoint Manager. + /// + public static string Label_CheckpointManager { get { - return ResourceManager.GetString("Action_New", resourceCulture); + return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); } } - public static string Label_Folder { + /// + /// Looks up a localized string similar to CivitAI. + /// + public static string Label_CivitAi { get { - return ResourceManager.GetString("Label_Folder", resourceCulture); + return ResourceManager.GetString("Label_CivitAi", resourceCulture); } } - public static string Label_DropFileToImport { + /// + /// 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("Label_DropFileToImport", resourceCulture); + return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); } } - public static string Label_ImportAsConnected { + /// + /// Looks up a localized string similar to CLIP Skip. + /// + public static string Label_CLIPSkip { get { - return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); + return ResourceManager.GetString("Label_CLIPSkip", resourceCulture); } } - public static string Label_ImportAsConnectedExplanation { + /// + /// Looks up a localized string similar to Close dialog when finished. + /// + public static string Label_CloseDialogWhenFinished { get { - return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); + return ResourceManager.GetString("Label_CloseDialogWhenFinished", resourceCulture); } } - public static string Label_Indexing { + /// + /// Looks up a localized string similar to Comments. + /// + public static string Label_Comments { get { - return ResourceManager.GetString("Label_Indexing", resourceCulture); + return ResourceManager.GetString("Label_Comments", resourceCulture); } } - public static string Label_ModelsFolder { + /// + /// Looks up a localized string similar to Commit. + /// + public static string Label_Commit { get { - return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); + return ResourceManager.GetString("Label_Commit", resourceCulture); } } - public static string Label_Categories { + /// + /// Looks up a localized string similar to Replace underscores with spaces when inserting completions. + /// + public static string Label_CompletionReplaceUnderscoresWithSpaces { get { - return ResourceManager.GetString("Label_Categories", resourceCulture); + return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); } } - public static string Label_LetsGetStarted { + /// + /// Looks up a localized string similar to Confirm Delete. + /// + public static string Label_ConfirmDelete { get { - return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); + return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); } } - public static string Label_ReadAndAgree { + /// + /// Looks up a localized string similar to Confirm Password. + /// + public static string Label_ConfirmPassword { get { - return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); + return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); } } - public static string Label_LicenseAgreement { + /// + /// Looks up a localized string similar to Confirm?. + /// + public static string Label_ConfirmQuestion { get { - return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); + return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); } } - public static string Label_FindConnectedMetadata { + /// + /// Looks up a localized string similar to Connected. + /// + public static string Label_Connected { get { - return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); + return ResourceManager.GetString("Label_Connected", resourceCulture); } } - public static string Label_ShowModelImages { + /// + /// Looks up a localized string similar to Connected Model. + /// + public static string Label_ConnectedModel { get { - return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); + return ResourceManager.GetString("Label_ConnectedModel", resourceCulture); } } - public static string Label_Appearance { + /// + /// Looks up a localized string similar to Connecting.... + /// + public static string Label_ConnectingEllipsis { get { - return ResourceManager.GetString("Label_Appearance", resourceCulture); + return ResourceManager.GetString("Label_ConnectingEllipsis", resourceCulture); } } - public static string Label_Theme { + /// + /// 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_Theme", resourceCulture); + return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); } } - public static string Label_CheckpointManager { + /// + /// Looks up a localized string similar to Control Steps. + /// + public static string Label_ControlSteps { get { - return ResourceManager.GetString("Label_CheckpointManager", resourceCulture); + return ResourceManager.GetString("Label_ControlSteps", resourceCulture); } } - public static string Label_RemoveSymlinksOnShutdown { + /// + /// Looks up a localized string similar to Control Weight. + /// + public static string Label_ControlWeight { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); + return ResourceManager.GetString("Label_ControlWeight", resourceCulture); } } - public static string Label_RemoveSymlinksOnShutdown_Details { + /// + /// Looks up a localized string similar to Current directory:. + /// + public static string Label_CurrentDirectory { get { - return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); + return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); } } - public static string Label_ResetCheckpointsCache { + /// + /// Looks up a localized string similar to Data Directory. + /// + public static string Label_DataDirectory { get { - return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); + return ResourceManager.GetString("Label_DataDirectory", resourceCulture); } } - public static string Label_ResetCheckpointsCache_Details { + /// + /// 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_ResetCheckpointsCache_Details", resourceCulture); + return ResourceManager.GetString("Label_DataDirectoryExplanation", resourceCulture); } } - public static string Label_PackageEnvironment { + /// + /// Looks up a localized string similar to Data Folder Name. + /// + public static string Label_DataFolderName { get { - return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); + return ResourceManager.GetString("Label_DataFolderName", resourceCulture); } } - public static string Action_Edit { + /// + /// Looks up a localized string similar to Data provided by CivitAI. + /// + public static string Label_DataProvidedByCivitAi { get { - return ResourceManager.GetString("Action_Edit", resourceCulture); + return ResourceManager.GetString("Label_DataProvidedByCivitAi", resourceCulture); } } - public static string Label_EnvironmentVariables { + /// + /// Looks up a localized string similar to Deemphasis. + /// + public static string Label_Deemphasis { get { - return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); + return ResourceManager.GetString("Label_Deemphasis", resourceCulture); } } - public static string Label_EmbeddedPython { + /// + /// Looks up a localized string similar to Denoising Strength. + /// + public static string Label_DenoisingStrength { get { - return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); + return ResourceManager.GetString("Label_DenoisingStrength", resourceCulture); } } - public static string Action_CheckVersion { + /// + /// Looks up a localized string similar to Details. + /// + public static string Label_Details { get { - return ResourceManager.GetString("Action_CheckVersion", resourceCulture); + return ResourceManager.GetString("Label_Details", resourceCulture); } } - public static string Label_Integrations { + /// + /// Looks up a localized string similar to Discord Rich Presence. + /// + public static string Label_DiscordRichPresence { get { - return ResourceManager.GetString("Label_Integrations", resourceCulture); + return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); } } - public static string Label_DiscordRichPresence { + /// + /// Looks up a localized string similar to Display Name. + /// + public static string Label_DisplayName { get { - return ResourceManager.GetString("Label_DiscordRichPresence", resourceCulture); + return ResourceManager.GetString("Label_DisplayName", resourceCulture); } } - public static string Label_System { + /// + /// Looks up a localized string similar to Download Failed. + /// + public static string Label_DownloadFailed { get { - return ResourceManager.GetString("Label_System", resourceCulture); + return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); } } - public static string Label_AddToStartMenu { + /// + /// Looks up a localized string similar to Downloads. + /// + public static string Label_Downloads { get { - return ResourceManager.GetString("Label_AddToStartMenu", resourceCulture); + return ResourceManager.GetString("Label_Downloads", resourceCulture); } } - public static string Label_AddToStartMenu_Details { + /// + /// Looks up a localized string similar to Drag & Drop checkpoints here to import. + /// + public static string Label_DragAndDropCheckpointsHereToImport { get { - return ResourceManager.GetString("Label_AddToStartMenu_Details", resourceCulture); + return ResourceManager.GetString("Label_DragAndDropCheckpointsHereToImport", resourceCulture); } } - public static string Label_OnlyAvailableOnWindows { + /// + /// Looks up a localized string similar to Drop file here to import. + /// + public static string Label_DropFileToImport { get { - return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); + return ResourceManager.GetString("Label_DropFileToImport", resourceCulture); } } - public static string Action_AddForCurrentUser { + /// + /// Looks up a localized string similar to Email. + /// + public static string Label_Email { get { - return ResourceManager.GetString("Action_AddForCurrentUser", resourceCulture); + return ResourceManager.GetString("Label_Email", resourceCulture); } } - public static string Action_AddForAllUsers { + /// + /// Looks up a localized string similar to Embedded Python. + /// + public static string Label_EmbeddedPython { get { - return ResourceManager.GetString("Action_AddForAllUsers", resourceCulture); + return ResourceManager.GetString("Label_EmbeddedPython", resourceCulture); } } - public static string Label_SelectNewDataDirectory { + /// + /// Looks up a localized string similar to Embeddings / Textual Inversion. + /// + public static string Label_EmbeddingsOrTextualInversion { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_EmbeddingsOrTextualInversion", resourceCulture); } } - public static string Label_SelectNewDataDirectory_Details { + /// + /// Looks up a localized string similar to Emphasis. + /// + public static string Label_Emphasis { get { - return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); + return ResourceManager.GetString("Label_Emphasis", resourceCulture); } } - public static string Action_SelectDirectory { + /// + /// Looks up a localized string similar to Environment Variables. + /// + public static string Label_EnvironmentVariables { get { - return ResourceManager.GetString("Action_SelectDirectory", resourceCulture); + return ResourceManager.GetString("Label_EnvironmentVariables", resourceCulture); } } - public static string Label_About { + /// + /// Looks up a localized string similar to Name. + /// + public static string Label_EnvVarsTable_Name { get { - return ResourceManager.GetString("Label_About", resourceCulture); + return ResourceManager.GetString("Label_EnvVarsTable_Name", resourceCulture); } } - public static string Label_StabilityMatrix { + /// + /// Looks up a localized string similar to Value. + /// + public static string Label_EnvVarsTable_Value { get { - return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_EnvVarsTable_Value", resourceCulture); } } - public static string Label_LicenseAndOpenSourceNotices { + /// + /// Looks up a localized string similar to Error installing package. + /// + public static string Label_ErrorInstallingPackage { get { - return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); + return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); } } - public static string TeachingTip_ClickLaunchToGetStarted { + /// + /// 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("TeachingTip_ClickLaunchToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_FatWarning", resourceCulture); } } - public static string Action_Stop { + /// + /// Looks up a localized string similar to Find Connected Metadata. + /// + public static string Label_FindConnectedMetadata { get { - return ResourceManager.GetString("Action_Stop", resourceCulture); + return ResourceManager.GetString("Label_FindConnectedMetadata", resourceCulture); } } - public static string Action_SendInput { + /// + /// Looks up a localized string similar to Find in Model Browser. + /// + public static string Label_FindInModelBrowser { get { - return ResourceManager.GetString("Action_SendInput", resourceCulture); + return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); } } - public static string Label_Input { + /// + /// Looks up a localized string similar to First Page. + /// + public static string Label_FirstPage { get { - return ResourceManager.GetString("Label_Input", resourceCulture); + return ResourceManager.GetString("Label_FirstPage", resourceCulture); } } - public static string Action_Send { + /// + /// Looks up a localized string similar to Folder. + /// + public static string Label_Folder { get { - return ResourceManager.GetString("Action_Send", resourceCulture); + return ResourceManager.GetString("Label_Folder", resourceCulture); } } - public static string Label_InputRequired { + /// + /// Looks up a localized string similar to Frames Per Second. + /// + public static string Label_Fps { get { - return ResourceManager.GetString("Label_InputRequired", resourceCulture); + return ResourceManager.GetString("Label_Fps", resourceCulture); } } - public static string Label_ConfirmQuestion { + /// + /// Looks up a localized string similar to Frames. + /// + public static string Label_Frames { get { - return ResourceManager.GetString("Label_ConfirmQuestion", resourceCulture); + return ResourceManager.GetString("Label_Frames", resourceCulture); } } - public static string Action_Yes { + /// + /// Looks up a localized string similar to General. + /// + public static string Label_General { get { - return ResourceManager.GetString("Action_Yes", resourceCulture); + return ResourceManager.GetString("Label_General", resourceCulture); } } - public static string Label_No { + /// + /// Looks up a localized string similar to Height. + /// + public static string Label_Height { get { - return ResourceManager.GetString("Label_No", resourceCulture); + return ResourceManager.GetString("Label_Height", resourceCulture); } } - public static string Action_OpenWebUI { + /// + /// Looks up a localized string similar to Holiday Mode. + /// + public static string Label_HolidayMode { get { - return ResourceManager.GetString("Action_OpenWebUI", resourceCulture); + return ResourceManager.GetString("Label_HolidayMode", resourceCulture); } } - public static string Text_WelcomeToStabilityMatrix { + /// + /// Looks up a localized string similar to Hugging Face. + /// + public static string Label_HuggingFace { get { - return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); + return ResourceManager.GetString("Label_HuggingFace", resourceCulture); } } - public static string Text_OneClickInstaller_SubHeader { + /// + /// Looks up a localized string similar to Image to Image. + /// + public static string Label_ImageToImage { get { - return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); + return ResourceManager.GetString("Label_ImageToImage", resourceCulture); } } - public static string Label_Installing { + /// + /// Looks up a localized string similar to Image to Video. + /// + public static string Label_ImageToVideo { get { - return ResourceManager.GetString("Label_Installing", resourceCulture); + return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); } } - public static string Text_ProceedingToLaunchPage { + /// + /// Looks up a localized string similar to Image Viewer. + /// + public static string Label_ImageViewer { get { - return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); + return ResourceManager.GetString("Label_ImageViewer", resourceCulture); } } - public static string Progress_DownloadingPackage { + /// + /// Looks up a localized string similar to Import with Metadata. + /// + public static string Label_ImportAsConnected { get { - return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnected", resourceCulture); } } - public static string Progress_DownloadComplete { + /// + /// Looks up a localized string similar to Search for connected metadata on new local imports. + /// + public static string Label_ImportAsConnectedExplanation { get { - return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); + return ResourceManager.GetString("Label_ImportAsConnectedExplanation", resourceCulture); } } - public static string Progress_InstallationComplete { + /// + /// Looks up a localized string similar to Import Latest -. + /// + public static string Label_ImportLatest { get { - return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); + return ResourceManager.GetString("Label_ImportLatest", resourceCulture); } } - public static string Progress_InstallingPrerequisites { + /// + /// Looks up a localized string similar to Indexing.... + /// + public static string Label_Indexing { get { - return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); + return ResourceManager.GetString("Label_Indexing", resourceCulture); } } - public static string Progress_InstallingPackageRequirements { + /// + /// Looks up a localized string similar to Inference. + /// + public static string Label_Inference { get { - return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); + return ResourceManager.GetString("Label_Inference", resourceCulture); } } - public static string Action_OpenInExplorer { + /// + /// Looks up a localized string similar to Inner exception. + /// + public static string Label_InnerException { get { - return ResourceManager.GetString("Action_OpenInExplorer", resourceCulture); + return ResourceManager.GetString("Label_InnerException", resourceCulture); } } - public static string Action_OpenInFinder { + /// + /// Looks up a localized string similar to Inpainting. + /// + public static string Label_Inpainting { + get { + return ResourceManager.GetString("Label_Inpainting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Input. + /// + public static string Label_Input { get { - return ResourceManager.GetString("Action_OpenInFinder", resourceCulture); + return ResourceManager.GetString("Label_Input", resourceCulture); } } - public static string Action_Uninstall { + /// + /// Looks up a localized string similar to Input required. + /// + public static string Label_InputRequired { get { - return ResourceManager.GetString("Action_Uninstall", resourceCulture); + return ResourceManager.GetString("Label_InputRequired", resourceCulture); } } - public static string Action_CheckForUpdates { + /// + /// Looks up a localized string similar to An installation with this name already exists.. + /// + public static string Label_InstallationWithThisNameExists { get { - return ResourceManager.GetString("Action_CheckForUpdates", resourceCulture); + return ResourceManager.GetString("Label_InstallationWithThisNameExists", resourceCulture); } } - public static string Action_Update { + /// + /// Looks up a localized string similar to Installed. + /// + public static string Label_Installed { get { - return ResourceManager.GetString("Action_Update", resourceCulture); + return ResourceManager.GetString("Label_Installed", resourceCulture); } } - public static string Action_AddPackage { + /// + /// Looks up a localized string similar to Installing. + /// + public static string Label_Installing { get { - return ResourceManager.GetString("Action_AddPackage", resourceCulture); + return ResourceManager.GetString("Label_Installing", resourceCulture); } } - public static string TeachingTip_AddPackageToGetStarted { + /// + /// Looks up a localized string similar to Integrations. + /// + public static string Label_Integrations { get { - return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); + return ResourceManager.GetString("Label_Integrations", resourceCulture); } } - public static string Label_EnvVarsTable_Name { + /// + /// Looks up a localized string similar to Invalid Package type. + /// + public static string Label_InvalidPackageType { get { - return ResourceManager.GetString("Label_EnvVarsTable_Name", resourceCulture); + return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); } } - public static string Label_EnvVarsTable_Value { + /// + /// Looks up a localized string similar to Join Discord Server. + /// + public static string Label_JoinDiscord { get { - return ResourceManager.GetString("Label_EnvVarsTable_Value", resourceCulture); + return ResourceManager.GetString("Label_JoinDiscord", resourceCulture); } } - public static string Action_Remove { + /// + /// Looks up a localized string similar to Language. + /// + public static string Label_Language { get { - return ResourceManager.GetString("Action_Remove", resourceCulture); + return ResourceManager.GetString("Label_Language", resourceCulture); } } - public static string Label_Details { + /// + /// Looks up a localized string similar to Last Page. + /// + public static string Label_LastPage { get { - return ResourceManager.GetString("Label_Details", resourceCulture); + return ResourceManager.GetString("Label_LastPage", resourceCulture); } } - public static string Label_Callstack { + /// + /// Looks up a localized string similar to Let's get started. + /// + public static string Label_LetsGetStarted { get { - return ResourceManager.GetString("Label_Callstack", resourceCulture); + return ResourceManager.GetString("Label_LetsGetStarted", resourceCulture); } } - public static string Label_InnerException { + /// + /// Looks up a localized string similar to License. + /// + public static string Label_License { get { - return ResourceManager.GetString("Label_InnerException", resourceCulture); + return ResourceManager.GetString("Label_License", resourceCulture); } } - public static string Label_SearchEllipsis { + /// + /// Looks up a localized string similar to License Agreement.. + /// + public static string Label_LicenseAgreement { get { - return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); + return ResourceManager.GetString("Label_LicenseAgreement", resourceCulture); } } - public static string Action_OK { + /// + /// Looks up a localized string similar to License and Open Source Notices. + /// + public static string Label_LicenseAndOpenSourceNotices { get { - return ResourceManager.GetString("Action_OK", resourceCulture); + return ResourceManager.GetString("Label_LicenseAndOpenSourceNotices", resourceCulture); } } - public static string Action_Retry { + /// + /// Looks up a localized string similar to Local Model. + /// + public static string Label_LocalModel { get { - return ResourceManager.GetString("Action_Retry", resourceCulture); + return ResourceManager.GetString("Label_LocalModel", resourceCulture); } } - public static string Label_PythonVersionInfo { + /// + /// Looks up a localized string similar to Lossless. + /// + public static string Label_Lossless { get { - return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); + return ResourceManager.GetString("Label_Lossless", resourceCulture); } } - public static string Action_Restart { + /// + /// Looks up a localized string similar to Min CFG. + /// + public static string Label_MinCfg { get { - return ResourceManager.GetString("Action_Restart", resourceCulture); + return ResourceManager.GetString("Label_MinCfg", resourceCulture); } } - public static string Label_ConfirmDelete { + /// + /// Looks up a localized string similar to Missing Image File. + /// + public static string Label_MissingImageFile { get { - return ResourceManager.GetString("Label_ConfirmDelete", resourceCulture); + return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); } } - public static string Text_PackageUninstall_Details { + /// + /// Looks up a localized string similar to Model. + /// + public static string Label_Model { get { - return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); + return ResourceManager.GetString("Label_Model", resourceCulture); } } - public static string Progress_UninstallingPackage { + /// + /// Looks up a localized string similar to Model Description. + /// + public static string Label_ModelDescription { get { - return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); + return ResourceManager.GetString("Label_ModelDescription", resourceCulture); } } - public static string Label_PackageUninstalled { + /// + /// Looks up a localized string similar to Search models, #tags, or @users. + /// + public static string Label_ModelSearchWatermark { get { - return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); + return ResourceManager.GetString("Label_ModelSearchWatermark", resourceCulture); } } - public static string Text_SomeFilesCouldNotBeDeleted { + /// + /// Looks up a localized string similar to Models Folder. + /// + public static string Label_ModelsFolder { get { - return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); + return ResourceManager.GetString("Label_ModelsFolder", resourceCulture); } } - public static string Label_InvalidPackageType { + /// + /// Looks up a localized string similar to Model Type. + /// + public static string Label_ModelType { get { - return ResourceManager.GetString("Label_InvalidPackageType", resourceCulture); + return ResourceManager.GetString("Label_ModelType", resourceCulture); } } - public static string TextTemplate_UpdatingPackage { + /// + /// Looks up a localized string similar to Motion Bucket ID. + /// + public static string Label_MotionBucketId { get { - return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); + return ResourceManager.GetString("Label_MotionBucketId", resourceCulture); } } - public static string Progress_UpdateComplete { + /// + /// Looks up a localized string similar to Networks (Lora / LyCORIS). + /// + public static string Label_NetworksLoraOrLycoris { get { - return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); + return ResourceManager.GetString("Label_NetworksLoraOrLycoris", resourceCulture); } } - public static string TextTemplate_PackageUpdatedToLatest { + /// + /// Looks up a localized string similar to A new version of Stability Matrix is available!. + /// + public static string Label_NewVersionAvailable { get { - return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); + return ResourceManager.GetString("Label_NewVersionAvailable", resourceCulture); } } - public static string TextTemplate_ErrorUpdatingPackage { + /// + /// Looks up a localized string similar to Next Image. + /// + public static string Label_NextImage { get { - return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); + return ResourceManager.GetString("Label_NextImage", resourceCulture); } } - public static string Progress_UpdateFailed { + /// + /// Looks up a localized string similar to Next Page. + /// + public static string Label_NextPage { get { - return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); + return ResourceManager.GetString("Label_NextPage", resourceCulture); } } - public static string Action_OpenInBrowser { + /// + /// Looks up a localized string similar to No. + /// + public static string Label_No { get { - return ResourceManager.GetString("Action_OpenInBrowser", resourceCulture); + return ResourceManager.GetString("Label_No", resourceCulture); } } - public static string Label_ErrorInstallingPackage { + /// + /// Looks up a localized string similar to No extensions found.. + /// + public static string Label_NoExtensionsFound { get { - return ResourceManager.GetString("Label_ErrorInstallingPackage", resourceCulture); + return ResourceManager.GetString("Label_NoExtensionsFound", resourceCulture); } } - public static string Label_Branch { + /// + /// Looks up a localized string similar to {0} images selected. + /// + public static string Label_NumImagesSelected { get { - return ResourceManager.GetString("Label_Branch", resourceCulture); + return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); } } - public static string Label_AutoScrollToEnd { + /// + /// Looks up a localized string similar to 1 image selected. + /// + public static string Label_OneImageSelected { get { - return ResourceManager.GetString("Label_AutoScrollToEnd", resourceCulture); + return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); } } - public static string Label_License { + /// + /// Looks up a localized string similar to Only available on Windows. + /// + public static string Label_OnlyAvailableOnWindows { get { - return ResourceManager.GetString("Label_License", resourceCulture); + return ResourceManager.GetString("Label_OnlyAvailableOnWindows", resourceCulture); } } - public static string Label_SharedModelStrategyShort { + /// + /// Looks up a localized string similar to Output Folder. + /// + public static string Label_OutputFolder { get { - return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); + return ResourceManager.GetString("Label_OutputFolder", resourceCulture); } } - public static string Label_PleaseSelectDataDirectory { + /// + /// Looks up a localized string similar to Output Image Files. + /// + public static string Label_OutputImageFiles { get { - return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); + return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); } } - public static string Label_DataFolderName { + /// + /// Looks up a localized string similar to Output Browser. + /// + public static string Label_OutputsPageTitle { get { - return ResourceManager.GetString("Label_DataFolderName", resourceCulture); + return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); } } - public static string Label_CurrentDirectory { + /// + /// Looks up a localized string similar to Output Type. + /// + public static string Label_OutputType { get { - return ResourceManager.GetString("Label_CurrentDirectory", resourceCulture); + return ResourceManager.GetString("Label_OutputType", resourceCulture); } } - public static string Text_AppWillRelaunchAfterUpdate { + /// + /// Looks up a localized string similar to Package Environment. + /// + public static string Label_PackageEnvironment { get { - return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); + return ResourceManager.GetString("Label_PackageEnvironment", resourceCulture); } } - public static string Action_RemindMeLater { + /// + /// Looks up a localized string similar to Package Type. + /// + public static string Label_PackageType { get { - return ResourceManager.GetString("Action_RemindMeLater", resourceCulture); + return ResourceManager.GetString("Label_PackageType", resourceCulture); } } - public static string Action_InstallNow { + /// + /// Looks up a localized string similar to Package Uninstalled. + /// + public static string Label_PackageUninstalled { get { - return ResourceManager.GetString("Action_InstallNow", resourceCulture); + return ResourceManager.GetString("Label_PackageUninstalled", resourceCulture); } } - public static string Label_ReleaseNotes { + /// + /// Looks up a localized string similar to Page. + /// + public static string Label_Page { get { - return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); + return ResourceManager.GetString("Label_Page", resourceCulture); } } - public static string Action_OpenProjectEllipsis { + /// + /// Looks up a localized string similar to Password. + /// + public static string Label_Password { get { - return ResourceManager.GetString("Action_OpenProjectEllipsis", resourceCulture); + return ResourceManager.GetString("Label_Password", resourceCulture); } } - public static string Action_SaveAsEllipsis { + /// + /// 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("Action_SaveAsEllipsis", resourceCulture); + return ResourceManager.GetString("Label_PleaseChooseDifferentName", resourceCulture); } } - public static string Action_RestoreDefaultLayout { + /// + /// Looks up a localized string similar to Please Select a Data Directory. + /// + public static string Label_PleaseSelectDataDirectory { get { - return ResourceManager.GetString("Action_RestoreDefaultLayout", resourceCulture); + return ResourceManager.GetString("Label_PleaseSelectDataDirectory", resourceCulture); } } - public static string Label_UseSharedOutputFolder { + /// + /// Looks up a localized string similar to Portable Mode. + /// + public static string Label_PortableMode { get { - return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); + return ResourceManager.GetString("Label_PortableMode", resourceCulture); } } - public static string Label_BatchIndex { + /// + /// 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("Label_BatchIndex", resourceCulture); + return ResourceManager.GetString("Label_PortableModeExplanation", resourceCulture); } } - public static string Action_Copy { + /// + /// Looks up a localized string similar to Preprocessor. + /// + public static string Label_Preprocessor { get { - return ResourceManager.GetString("Action_Copy", resourceCulture); + return ResourceManager.GetString("Label_Preprocessor", resourceCulture); } } - public static string Action_OpenInViewer { + /// + /// Looks up a localized string similar to Previous Image. + /// + public static string Label_PreviousImage { get { - return ResourceManager.GetString("Action_OpenInViewer", resourceCulture); + return ResourceManager.GetString("Label_PreviousImage", resourceCulture); } } - public static string Label_NumImagesSelected { + /// + /// Looks up a localized string similar to Previous Page. + /// + public static string Label_PreviousPage { get { - return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture); + return ResourceManager.GetString("Label_PreviousPage", resourceCulture); } } - public static string Label_OutputFolder { + /// + /// Looks up a localized string similar to Prompt. + /// + public static string Label_Prompt { get { - return ResourceManager.GetString("Label_OutputFolder", resourceCulture); + return ResourceManager.GetString("Label_Prompt", resourceCulture); } } - public static string Label_OutputType { + /// + /// Looks up a localized string similar to Prompt Tags. + /// + public static string Label_PromptTags { get { - return ResourceManager.GetString("Label_OutputType", resourceCulture); + return ResourceManager.GetString("Label_PromptTags", resourceCulture); } } - public static string Action_ClearSelection { + /// + /// 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("Action_ClearSelection", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); } } - public static string Action_SelectAll { + /// + /// Looks up a localized string similar to Import Prompt tags. + /// + public static string Label_PromptTagsImport { get { - return ResourceManager.GetString("Action_SelectAll", resourceCulture); + return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); } } - public static string Action_SendToInference { + /// + /// Looks up a localized string similar to Python Packages. + /// + public static string Label_PythonPackages { get { - return ResourceManager.GetString("Action_SendToInference", resourceCulture); + return ResourceManager.GetString("Label_PythonPackages", resourceCulture); } } - public static string Label_TextToImage { + /// + /// Looks up a localized string similar to Python Version Info. + /// + public static string Label_PythonVersionInfo { get { - return ResourceManager.GetString("Label_TextToImage", resourceCulture); + return ResourceManager.GetString("Label_PythonVersionInfo", resourceCulture); } } - public static string Label_ImageToImage { + /// + /// Looks up a localized string similar to PyTorch Version. + /// + public static string Label_PyTorchVersion { get { - return ResourceManager.GetString("Label_ImageToImage", resourceCulture); + return ResourceManager.GetString("Label_PyTorchVersion", resourceCulture); } } - public static string Label_Inpainting { + /// + /// Looks up a localized string similar to I have read and agree to the. + /// + public static string Label_ReadAndAgree { get { - return ResourceManager.GetString("Label_Inpainting", resourceCulture); + return ResourceManager.GetString("Label_ReadAndAgree", resourceCulture); } } - public static string Label_Upscale { + /// + /// Looks up a localized string similar to Refiner. + /// + public static string Label_Refiner { get { - return ResourceManager.GetString("Label_Upscale", resourceCulture); + return ResourceManager.GetString("Label_Refiner", resourceCulture); } } - public static string Label_OutputsPageTitle { + /// + /// Looks up a localized string similar to Relaunch Required. + /// + public static string Label_RelaunchRequired { get { - return ResourceManager.GetString("Label_OutputsPageTitle", resourceCulture); + return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); } } - public static string Label_OneImageSelected { + /// + /// Looks up a localized string similar to Release Notes. + /// + public static string Label_ReleaseNotes { get { - return ResourceManager.GetString("Label_OneImageSelected", resourceCulture); + return ResourceManager.GetString("Label_ReleaseNotes", resourceCulture); } } - public static string Label_Preprocessor { + /// + /// Looks up a localized string similar to Releases. + /// + public static string Label_Releases { get { - return ResourceManager.GetString("Label_Preprocessor", resourceCulture); + return ResourceManager.GetString("Label_Releases", resourceCulture); } } - public static string Label_Strength { + /// + /// 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_Strength", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown", resourceCulture); } } - public static string Label_ControlWeight { + /// + /// 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("Label_ControlWeight", resourceCulture); + return ResourceManager.GetString("Label_RemoveSymlinksOnShutdown_Details", resourceCulture); } } - public static string Label_ControlSteps { + /// + /// Looks up a localized string similar to Reset Checkpoints Cache. + /// + public static string Label_ResetCheckpointsCache { get { - return ResourceManager.GetString("Label_ControlSteps", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache", resourceCulture); } } - public static string Label_PythonPackages { + /// + /// 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_PythonPackages", resourceCulture); + return ResourceManager.GetString("Label_ResetCheckpointsCache_Details", resourceCulture); } } - public static string Action_Consolidate { + /// + /// Looks up a localized string similar to Save Intermediate Image. + /// + public static string Label_SaveIntermediateImage { get { - return ResourceManager.GetString("Action_Consolidate", resourceCulture); + return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); } } - public static string Label_AreYouSure { + /// + /// Looks up a localized string similar to Search.... + /// + public static string Label_SearchEllipsis { get { - return ResourceManager.GetString("Label_AreYouSure", resourceCulture); + return ResourceManager.GetString("Label_SearchEllipsis", resourceCulture); } } - public static string Label_ConsolidateExplanation { + /// + /// Looks up a localized string similar to Select new Data Directory. + /// + public static string Label_SelectNewDataDirectory { get { - return ResourceManager.GetString("Label_ConsolidateExplanation", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory", resourceCulture); } } - public static string Action_Refresh { + /// + /// Looks up a localized string similar to Does not move existing data. + /// + public static string Label_SelectNewDataDirectory_Details { get { - return ResourceManager.GetString("Action_Refresh", resourceCulture); + return ResourceManager.GetString("Label_SelectNewDataDirectory_Details", resourceCulture); } } - public static string Action_Upgrade { + /// + /// Looks up a localized string similar to Settings. + /// + public static string Label_Settings { get { - return ResourceManager.GetString("Action_Upgrade", resourceCulture); + return ResourceManager.GetString("Label_Settings", resourceCulture); } } - public static string Action_Downgrade { + /// + /// Looks up a localized string similar to Shared Model Folder Strategy. + /// + public static string Label_SharedModelFolderStrategy { get { - return ResourceManager.GetString("Action_Downgrade", resourceCulture); + return ResourceManager.GetString("Label_SharedModelFolderStrategy", resourceCulture); } } - public static string Action_OpenGithub { + /// + /// Looks up a localized string similar to Model Sharing. + /// + public static string Label_SharedModelStrategyShort { get { - return ResourceManager.GetString("Action_OpenGithub", resourceCulture); + return ResourceManager.GetString("Label_SharedModelStrategyShort", resourceCulture); } } - public static string Label_Connected { + /// + /// Looks up a localized string similar to Show Model Images. + /// + public static string Label_ShowModelImages { get { - return ResourceManager.GetString("Label_Connected", resourceCulture); + return ResourceManager.GetString("Label_ShowModelImages", resourceCulture); } } - public static string Action_Disconnect { + /// + /// Looks up a localized string similar to Show NSFW Content. + /// + public static string Label_ShowNsfwContent { get { - return ResourceManager.GetString("Action_Disconnect", resourceCulture); + return ResourceManager.GetString("Label_ShowNsfwContent", resourceCulture); } } - public static string Label_Email { + /// + /// Looks up a localized string similar to Show pixel grid at high zoom levels. + /// + public static string Label_ShowPixelGridAtHighZoomLevels { get { - return ResourceManager.GetString("Label_Email", resourceCulture); + return ResourceManager.GetString("Label_ShowPixelGridAtHighZoomLevels", resourceCulture); } } - public static string Label_Username { + /// + /// Looks up a localized string similar to Skip first-time setup. + /// + public static string Label_SkipSetup { get { - return ResourceManager.GetString("Label_Username", resourceCulture); + return ResourceManager.GetString("Label_SkipSetup", resourceCulture); } } - public static string Label_Password { + /// + /// Looks up a localized string similar to Sort. + /// + public static string Label_Sort { get { - return ResourceManager.GetString("Label_Password", resourceCulture); + return ResourceManager.GetString("Label_Sort", resourceCulture); } } - public static string Action_Login { + /// + /// Looks up a localized string similar to Stability Matrix. + /// + public static string Label_StabilityMatrix { get { - return ResourceManager.GetString("Action_Login", resourceCulture); + return ResourceManager.GetString("Label_StabilityMatrix", resourceCulture); } } - public static string Action_Signup { + /// + /// Looks up a localized string similar to Steps. + /// + public static string Label_Steps { get { - return ResourceManager.GetString("Action_Signup", resourceCulture); + return ResourceManager.GetString("Label_Steps", resourceCulture); } } - public static string Label_ConfirmPassword { + /// + /// Looks up a localized string similar to Steps - Base. + /// + public static string Label_StepsBase { get { - return ResourceManager.GetString("Label_ConfirmPassword", resourceCulture); + return ResourceManager.GetString("Label_StepsBase", resourceCulture); } } - public static string Label_ApiKey { + /// + /// Looks up a localized string similar to Steps - Refiner. + /// + public static string Label_StepsRefiner { get { - return ResourceManager.GetString("Label_ApiKey", resourceCulture); + return ResourceManager.GetString("Label_StepsRefiner", resourceCulture); } } - public static string Label_Accounts { + /// + /// Looks up a localized string similar to Strength. + /// + public static string Label_Strength { get { - return ResourceManager.GetString("Label_Accounts", resourceCulture); + return ResourceManager.GetString("Label_Strength", resourceCulture); } } - public static string Label_CivitAiLoginRequired { + /// + /// Looks up a localized string similar to System. + /// + public static string Label_System { get { - return ResourceManager.GetString("Label_CivitAiLoginRequired", resourceCulture); + return ResourceManager.GetString("Label_System", resourceCulture); } } - public static string Label_DownloadFailed { + /// + /// Looks up a localized string similar to System Information. + /// + public static string Label_SystemInformation { get { - return ResourceManager.GetString("Label_DownloadFailed", resourceCulture); + return ResourceManager.GetString("Label_SystemInformation", resourceCulture); } } - public static string Label_AutoUpdates { + /// + /// Looks up a localized string similar to Text to Image. + /// + public static string Label_TextToImage { get { - return ResourceManager.GetString("Label_AutoUpdates", resourceCulture); + return ResourceManager.GetString("Label_TextToImage", resourceCulture); } } - public static string Label_UpdatesPreviewChannelDescription { + /// + /// Looks up a localized string similar to Theme. + /// + public static string Label_Theme { get { - return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_Theme", resourceCulture); } } - public static string Label_UpdatesDevChannelDescription { + /// + /// Looks up a localized string similar to Period. + /// + public static string Label_TimePeriod { get { - return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); + return ResourceManager.GetString("Label_TimePeriod", resourceCulture); } } - public static string Label_Updates { + /// + /// Looks up a localized string similar to Trigger words:. + /// + public static string Label_TriggerWords { get { - return ResourceManager.GetString("Label_Updates", resourceCulture); + return ResourceManager.GetString("Label_TriggerWords", resourceCulture); } } - public static string Label_YouAreUpToDate { + /// + /// Looks up a localized string similar to An unexpected error occurred. + /// + public static string Label_UnexpectedErrorOccurred { get { - return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); + return ResourceManager.GetString("Label_UnexpectedErrorOccurred", resourceCulture); } } - public static string TextTemplate_LastChecked { + /// + /// Looks up a localized string similar to Unknown Package. + /// + public static string Label_UnknownPackage { get { - return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); + return ResourceManager.GetString("Label_UnknownPackage", resourceCulture); } } - public static string Action_CopyTriggerWords { + /// + /// Looks up a localized string similar to Update Available. + /// + public static string Label_UpdateAvailable { get { - return ResourceManager.GetString("Action_CopyTriggerWords", resourceCulture); + return ResourceManager.GetString("Label_UpdateAvailable", resourceCulture); } } - public static string Label_TriggerWords { + /// + /// Looks up a localized string similar to Updates. + /// + public static string Label_Updates { get { - return ResourceManager.GetString("Label_TriggerWords", resourceCulture); + return ResourceManager.GetString("Label_Updates", resourceCulture); } } - public static string TeachingTip_MoreCheckpointCategories { + /// + /// 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("TeachingTip_MoreCheckpointCategories", resourceCulture); + return ResourceManager.GetString("Label_UpdatesDevChannelDescription", resourceCulture); } } - public static string Action_OpenOnHuggingFace { + /// + /// 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("Action_OpenOnHuggingFace", resourceCulture); + return ResourceManager.GetString("Label_UpdatesPreviewChannelDescription", resourceCulture); } } - public static string Action_UpdateExistingMetadata { + /// + /// Looks up a localized string similar to Upscale. + /// + public static string Label_Upscale { get { - return ResourceManager.GetString("Action_UpdateExistingMetadata", resourceCulture); + return ResourceManager.GetString("Label_Upscale", resourceCulture); } } - public static string Label_General { + /// + /// Looks up a localized string similar to Username. + /// + public static string Label_Username { get { - return ResourceManager.GetString("Label_General", resourceCulture); + return ResourceManager.GetString("Label_Username", resourceCulture); } } - public static string Label_Inference { + /// + /// Looks up a localized string similar to Output Sharing. + /// + public static string Label_UseSharedOutputFolder { get { - return ResourceManager.GetString("Label_Inference", resourceCulture); + return ResourceManager.GetString("Label_UseSharedOutputFolder", resourceCulture); } } - public static string Label_Prompt { + /// + /// Looks up a localized string similar to VAE. + /// + public static string Label_VAE { get { - return ResourceManager.GetString("Label_Prompt", resourceCulture); + return ResourceManager.GetString("Label_VAE", resourceCulture); } } - public static string Label_OutputImageFiles { + /// + /// Looks up a localized string similar to Version. + /// + public static string Label_Version { get { - return ResourceManager.GetString("Label_OutputImageFiles", resourceCulture); + return ResourceManager.GetString("Label_Version", resourceCulture); } } - public static string Label_ImageViewer { + /// + /// Looks up a localized string similar to Version Type. + /// + public static string Label_VersionType { get { - return ResourceManager.GetString("Label_ImageViewer", resourceCulture); + return ResourceManager.GetString("Label_VersionType", resourceCulture); } } - public static string Label_AutoCompletion { + /// + /// Looks up a localized string similar to Method. + /// + public static string Label_VideoOutputMethod { get { - return ResourceManager.GetString("Label_AutoCompletion", resourceCulture); + return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); } } - public static string Label_CompletionReplaceUnderscoresWithSpaces { + /// + /// Looks up a localized string similar to Quality. + /// + public static string Label_VideoQuality { get { - return ResourceManager.GetString("Label_CompletionReplaceUnderscoresWithSpaces", resourceCulture); + return ResourceManager.GetString("Label_VideoQuality", resourceCulture); } } - public static string Label_PromptTags { + /// + /// Looks up a localized string similar to Waiting to connect.... + /// + public static string Label_WaitingToConnectEllipsis { get { - return ResourceManager.GetString("Label_PromptTags", resourceCulture); + return ResourceManager.GetString("Label_WaitingToConnectEllipsis", resourceCulture); } } - public static string Label_PromptTagsImport { + /// + /// Looks up a localized string similar to Width. + /// + public static string Label_Width { get { - return ResourceManager.GetString("Label_PromptTagsImport", resourceCulture); + return ResourceManager.GetString("Label_Width", resourceCulture); } } - public static string Label_PromptTagsDescription { + /// + /// Looks up a localized string similar to Not yet available. + /// + public static string Label_WipFeature { get { - return ResourceManager.GetString("Label_PromptTagsDescription", resourceCulture); + return ResourceManager.GetString("Label_WipFeature", resourceCulture); } } - public static string Label_SystemInformation { + /// + /// 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_SystemInformation", resourceCulture); + return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); } } - public static string Label_CivitAi { + /// + /// Looks up a localized string similar to You're up to date. + /// + public static string Label_YouAreUpToDate { get { - return ResourceManager.GetString("Label_CivitAi", resourceCulture); + return ResourceManager.GetString("Label_YouAreUpToDate", resourceCulture); } } - public static string Label_HuggingFace { + /// + /// Looks up a localized string similar to Download complete. + /// + public static string Progress_DownloadComplete { get { - return ResourceManager.GetString("Label_HuggingFace", resourceCulture); + return ResourceManager.GetString("Progress_DownloadComplete", resourceCulture); } } - public static string Label_Addons { + /// + /// Looks up a localized string similar to Downloading package.... + /// + public static string Progress_DownloadingPackage { get { - return ResourceManager.GetString("Label_Addons", resourceCulture); + return ResourceManager.GetString("Progress_DownloadingPackage", resourceCulture); } } - public static string Label_SaveIntermediateImage { + /// + /// Looks up a localized string similar to Installation complete. + /// + public static string Progress_InstallationComplete { get { - return ResourceManager.GetString("Label_SaveIntermediateImage", resourceCulture); + return ResourceManager.GetString("Progress_InstallationComplete", resourceCulture); } } - public static string Label_Settings { + /// + /// Looks up a localized string similar to Installing package requirements.... + /// + public static string Progress_InstallingPackageRequirements { get { - return ResourceManager.GetString("Label_Settings", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPackageRequirements", resourceCulture); } } - public static string Action_SelectFile { + /// + /// Looks up a localized string similar to Installing prerequisites.... + /// + public static string Progress_InstallingPrerequisites { get { - return ResourceManager.GetString("Action_SelectFile", resourceCulture); + return ResourceManager.GetString("Progress_InstallingPrerequisites", resourceCulture); } } - public static string Action_ReplaceContents { + /// + /// Looks up a localized string similar to Uninstalling package.... + /// + public static string Progress_UninstallingPackage { get { - return ResourceManager.GetString("Action_ReplaceContents", resourceCulture); + return ResourceManager.GetString("Progress_UninstallingPackage", resourceCulture); } } - public static string Label_WipFeature { + /// + /// Looks up a localized string similar to Update complete. + /// + public static string Progress_UpdateComplete { get { - return ResourceManager.GetString("Label_WipFeature", resourceCulture); + return ResourceManager.GetString("Progress_UpdateComplete", resourceCulture); } } - public static string Label_WipFeatureDescription { + /// + /// Looks up a localized string similar to Update failed. + /// + public static string Progress_UpdateFailed { get { - return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture); + return ResourceManager.GetString("Progress_UpdateFailed", resourceCulture); } } - public static string Label_MissingImageFile { + /// + /// Looks up a localized string similar to Add a package to get started!. + /// + public static string TeachingTip_AddPackageToGetStarted { get { - return ResourceManager.GetString("Label_MissingImageFile", resourceCulture); + return ResourceManager.GetString("TeachingTip_AddPackageToGetStarted", resourceCulture); } } - public static string Label_HolidayMode { + /// + /// Looks up a localized string similar to Click Launch to get started!. + /// + public static string TeachingTip_ClickLaunchToGetStarted { get { - return ResourceManager.GetString("Label_HolidayMode", resourceCulture); + return ResourceManager.GetString("TeachingTip_ClickLaunchToGetStarted", resourceCulture); } } - public static string Label_CLIPSkip { + /// + /// 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_CLIPSkip", resourceCulture); + return ResourceManager.GetString("TeachingTip_MoreCheckpointCategories", resourceCulture); } } - public static string Label_ImageToVideo { + /// + /// Looks up a localized string similar to The app will relaunch after updating. + /// + public static string Text_AppWillRelaunchAfterUpdate { get { - return ResourceManager.GetString("Label_ImageToVideo", resourceCulture); + return ResourceManager.GetString("Text_AppWillRelaunchAfterUpdate", resourceCulture); } } - public static string Label_Fps { + /// + /// Looks up a localized string similar to Choose your preferred interface and click Install to get started. + /// + public static string Text_OneClickInstaller_SubHeader { get { - return ResourceManager.GetString("Label_Fps", resourceCulture); + return ResourceManager.GetString("Text_OneClickInstaller_SubHeader", resourceCulture); } } - public static string Label_MinCfg { + /// + /// 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("Label_MinCfg", resourceCulture); + return ResourceManager.GetString("Text_PackageUninstall_Details", resourceCulture); } } - public static string Label_Lossless { + /// + /// Looks up a localized string similar to Proceeding to Launch page. + /// + public static string Text_ProceedingToLaunchPage { get { - return ResourceManager.GetString("Label_Lossless", resourceCulture); + return ResourceManager.GetString("Text_ProceedingToLaunchPage", resourceCulture); } } - public static string Label_Frames { + /// + /// 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_Frames", resourceCulture); + return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); } } - public static string Label_MotionBucketId { + /// + /// 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_MotionBucketId", resourceCulture); + return ResourceManager.GetString("Text_SomeFilesCouldNotBeDeleted", resourceCulture); } } - public static string Label_AugmentationLevel { + /// + /// Looks up a localized string similar to Welcome to Stability Matrix!. + /// + public static string Text_WelcomeToStabilityMatrix { get { - return ResourceManager.GetString("Label_AugmentationLevel", resourceCulture); + return ResourceManager.GetString("Text_WelcomeToStabilityMatrix", resourceCulture); } } - public static string Label_VideoOutputMethod { + /// + /// Looks up a localized string similar to Error updating {0}. + /// + public static string TextTemplate_ErrorUpdatingPackage { get { - return ResourceManager.GetString("Label_VideoOutputMethod", resourceCulture); + return ResourceManager.GetString("TextTemplate_ErrorUpdatingPackage", resourceCulture); } } - public static string Label_VideoQuality { + /// + /// Looks up a localized string similar to Last checked: {0}. + /// + public static string TextTemplate_LastChecked { get { - return ResourceManager.GetString("Label_VideoQuality", resourceCulture); + return ResourceManager.GetString("TextTemplate_LastChecked", resourceCulture); } } - public static string Label_FindInModelBrowser { + /// + /// Looks up a localized string similar to {0} has been updated to the latest version. + /// + public static string TextTemplate_PackageUpdatedToLatest { get { - return ResourceManager.GetString("Label_FindInModelBrowser", resourceCulture); + return ResourceManager.GetString("TextTemplate_PackageUpdatedToLatest", resourceCulture); } } - public static string Label_Installed { + /// + /// Looks up a localized string similar to Updating {0}. + /// + public static string TextTemplate_UpdatingPackage { get { - return ResourceManager.GetString("Label_Installed", resourceCulture); + return ResourceManager.GetString("TextTemplate_UpdatingPackage", resourceCulture); } } } diff --git a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx index 0ff36a238..f971db524 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx @@ -142,7 +142,7 @@ Relancer plus tard - Relance nécessaire + Relancement nécessaire Paquet inconnu @@ -250,7 +250,7 @@ Une erreur inattendue s'est produite - Demande de sortie + Quitter l'application Nom d'affichage @@ -678,4 +678,186 @@ Rétablir la présentation par défaut + + Partager des générations + + + Copier + + + Ouvrir dans la visionneuse d'images + + + {0} images sélectionnées + + + Dossier + Hey hey :) is this used somewhere else ? if it's only inside the "output browser", I suggest to remove "output" from translation, but you're the boss, lmk :) + + + Type + + + Annuler la sélection + + + Sélectionner tout + + + Envoyer à l'inférence + + + Texte vers image + + + Image vers image + + + Amélioration de qualité + + + Explorateur des générations + + + 1 image sélectionnée + + + Paquets Python + + + Consolider + + + Êtes-vous sure ? + + + Cela déplacera toutes les images générées des packages sélectionnés vers le répertoire consolidé du dossier de sorties partagées. Cette action ne peut pas être annulée. + + + Rafraichir + + + Passer à la version supérieure + What is this related to ? + + + Passer à la version inférieure + What is this related to ? + + + Ouvrir sur GitHub + + + Connecté + + + Se déconnecter + + + Email + + + Nom d'utilisateur + + + Mot de passe + + + Ouvrir une session + + + S'enregistrer + + + Confirmer le mot de passe + + + Clé d'API + + + Comptes + + + Préprocesseur + + + Force + + + Vous devez être loggué pour télécharger ce checkpoint. Veuillez entrer une clé d'API CivitAI dans les paramètres. + + + Echec du téléchargement + + + Mises à jour automatiques + + + Mises à jour + + + Vous êtes à jour + + + Dernière vérification: {0} + + + Ouvrir sur Hugging Face + + + Mettre à jour les métadonnées existantes + + + Générale + A general settings category + + + Informations système + + + CivitAI + + + Hugging Face + + + Modules complémentaires + Inference Sampler Addons + + + Paramètres + + + Sélectionner un fichier + + + Remplacer des contenus + + + Pas encore disponible + + + Fonctionnalité disponible dans une mise à jour future + + + Fichier image manquant + + + Image vers vidéo + + + Images par seconde + + + CFG Min + + + Sans perte + + + Méthode + + + Qualité + \ No newline at end of file diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 41521a7e1..9a64e94f9 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -933,4 +933,7 @@ Installed + + No extensions found. + diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 51fd37cc9..1e6b71d07 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -32,19 +32,19 @@ - + - - - + + + - + - - - - - + + + + + @@ -55,9 +55,9 @@ - - - + + + @@ -68,17 +68,17 @@ - + - - + + - + - + diff --git a/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml index e2e71476c..7565401ba 100644 --- a/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml +++ b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml @@ -2,7 +2,7 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:mocks="using:StabilityMatrix.Avalonia.DesignData" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" diff --git a/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml b/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml index 87b06b982..e49ef7547 100644 --- a/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml +++ b/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml @@ -2,7 +2,7 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:ui="using:FluentAvalonia.UI.Controls"> diff --git a/StabilityMatrix.Avalonia/Styles/FAComboBoxStyles.axaml b/StabilityMatrix.Avalonia/Styles/FAComboBoxStyles.axaml index d0c54b78c..55d68fd35 100644 --- a/StabilityMatrix.Avalonia/Styles/FAComboBoxStyles.axaml +++ b/StabilityMatrix.Avalonia/Styles/FAComboBoxStyles.axaml @@ -2,7 +2,7 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:mocks="using:StabilityMatrix.Avalonia.DesignData" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs index 051bd7958..fd2ccc1f3 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs @@ -12,7 +12,7 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index 8639c2104..f5bc68b9d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -26,7 +26,7 @@ using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; using TeachingTip = StabilityMatrix.Core.Models.Settings.TeachingTip; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs index b03988a59..d1a7660fe 100644 --- a/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/ExtensionViewModel.cs @@ -4,7 +4,7 @@ namespace StabilityMatrix.Avalonia.ViewModels; -public partial class ExtensionViewModel() : ViewModelBase +public partial class ExtensionViewModel : ViewModelBase { [ObservableProperty] private bool isSelected; diff --git a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs index 3662f4521..c36fa1289 100644 --- a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs @@ -35,7 +35,7 @@ using InferenceTabViewModelBase = StabilityMatrix.Avalonia.ViewModels.Base.InferenceTabViewModelBase; using Path = System.IO.Path; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs index b9ed79abc..4509831b9 100644 --- a/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs @@ -35,7 +35,7 @@ using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; @@ -58,8 +58,7 @@ public partial class LaunchPageViewModel : PageViewModelBase, IDisposable, IAsyn private static partial Regex InputYesNoRegex(); public override string Title => "Launch"; - public override IconSource IconSource => - new SymbolIconSource { Symbol = Symbol.Rocket, IsFilled = true }; + public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Rocket, IsFilled = true }; public ConsoleViewModel Console { get; } = new(); @@ -154,8 +153,7 @@ ServiceManager dialogFactory }; } - private void OnTeachingTooltipNeeded(object? sender, EventArgs e) => - IsLaunchTeachingTipsOpen = true; + private void OnTeachingTooltipNeeded(object? sender, EventArgs e) => IsLaunchTeachingTipsOpen = true; private void OnInstalledPackagesChanged(object? sender, EventArgs e) => OnLoaded(); @@ -353,9 +351,7 @@ private async Task Config() // Open a config page var userLaunchArgs = settingsManager.GetLaunchArgs(activeInstall.Id); var viewModel = dialogFactory.Get(); - viewModel.Cards = LaunchOptionCard - .FromDefinitions(definitions, userLaunchArgs) - .ToImmutableArray(); + viewModel.Cards = LaunchOptionCard.FromDefinitions(definitions, userLaunchArgs).ToImmutableArray(); logger.LogDebug("Launching config dialog with cards: {CardsCount}", viewModel.Cards.Count); @@ -454,14 +450,10 @@ public void OpenWebUi() private void OnProcessExited(object? sender, int exitCode) { EventManager.Instance.OnRunningPackageStatusChanged(null); - Dispatcher.UIThread - .InvokeAsync(async () => + Dispatcher + .UIThread.InvokeAsync(async () => { - logger.LogTrace( - "Process exited ({Code}) at {Time:g}", - exitCode, - DateTimeOffset.Now - ); + logger.LogTrace("Process exited ({Code}) at {Time:g}", exitCode, DateTimeOffset.Now); // Need to wait for streams to finish before detaching handlers if (sender is BaseGitPackage { VenvRunner: not null } package) @@ -477,10 +469,7 @@ private void OnProcessExited(object? sender, int exitCode) } catch (OperationCanceledException e) { - logger.LogWarning( - "Waiting for process EOF timed out: {Message}", - e.Message - ); + logger.LogWarning("Waiting for process EOF timed out: {Message}", e.Message); } } } @@ -499,9 +488,7 @@ private void OnProcessExited(object? sender, int exitCode) // Need to reset cursor in case its in some weird position // from progress bars await Console.ResetWriteCursor(); - Console.PostLine( - $"{Environment.NewLine}Process finished with exit code {exitCode}" - ); + Console.PostLine($"{Environment.NewLine}Process finished with exit code {exitCode}"); }) .SafeFireAndForget(); } @@ -538,8 +525,8 @@ public void OnMainWindowClosing(WindowClosingEventArgs e) e.Cancel = true; var dialog = CreateExitConfirmDialog(); - Dispatcher.UIThread - .InvokeAsync(async () => + Dispatcher + .UIThread.InvokeAsync(async () => { if ( (TaskDialogStandardResult)await dialog.ShowAsync(true) diff --git a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs index e97412849..45ea5ed08 100644 --- a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs @@ -29,7 +29,7 @@ using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs index 0cd0e6897..d900f2bc0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs @@ -10,7 +10,7 @@ using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs index f11867512..95cd86ec1 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs @@ -39,7 +39,7 @@ using StabilityMatrix.Core.Services; using Size = StabilityMatrix.Core.Models.Settings.Size; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs index b9ce8cae0..9aa2e6fc0 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -46,6 +46,7 @@ public partial class PackageExtensionBrowserViewModel : ViewModelBase, IDisposab public PackagePair? PackagePair { get; set; } [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowNoExtensionsFoundMessage))] private bool isLoading; private SourceCache availableExtensionsSource = @@ -78,6 +79,9 @@ public SearchCollection< public IObservableCollection InstalledExtensions { get; } = new ObservableCollectionExtended(); + [ObservableProperty] + private bool showNoExtensionsFoundMessage; + public PackageExtensionBrowserViewModel( INotificationService notificationService, ISettingsManager settingsManager, @@ -316,6 +320,7 @@ public async Task Refresh() finally { IsLoading = false; + ShowNoExtensionsFoundMessage = AvailableItemsSearchCollection.FilteredItems.Count == 0; } } diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index cd6f92624..d6e9e0ef9 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -26,7 +26,7 @@ using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; using PackageInstallDetailView = StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallDetailView; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels.PackageManager; diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs index 3fc0b95e4..019b6c3e7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs @@ -30,7 +30,7 @@ using StabilityMatrix.Core.Models.Packages; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; diff --git a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs index c06336971..90c9d5cc5 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs @@ -23,7 +23,7 @@ using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels.Progress; @@ -61,10 +61,7 @@ INavigationService settingsNavService EventManager.Instance.ToggleProgressFlyout += (_, _) => IsOpen = !IsOpen; } - private void InstanceOnPackageInstallProgressAdded( - object? sender, - IPackageModificationRunner runner - ) + private void InstanceOnPackageInstallProgressAdded(object? sender, IPackageModificationRunner runner) { AddPackageInstall(runner).SafeFireAndForget(); } @@ -181,9 +178,7 @@ private Task AddPackageInstall(IPackageModificationRunner packageModificationRun ); ProgressItems.Add(vm); - return packageModificationRunner.ShowDialogOnStart - ? vm.ShowProgressDialog() - : Task.CompletedTask; + return packageModificationRunner.ShowDialogOnStart ? vm.ShowProgressDialog() : Task.CompletedTask; } private void ShowFailedNotification(string title, string message) diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs index 15cdf3720..def248c3f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs @@ -23,7 +23,7 @@ using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; using TeachingTip = StabilityMatrix.Core.Models.Settings.TeachingTip; namespace StabilityMatrix.Avalonia.ViewModels.Settings; @@ -42,8 +42,7 @@ public partial class AccountSettingsViewModel : PageViewModelBase public override string Title => "Accounts"; /// - public override IconSource IconSource => - new SymbolIconSource { Symbol = Symbol.Person, IsFilled = true }; + public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Person, IsFilled = true }; [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ConnectLykosCommand))] @@ -59,12 +58,10 @@ public partial class AccountSettingsViewModel : PageViewModelBase [ObservableProperty] [NotifyPropertyChangedFor(nameof(LykosProfileImageUrl))] - private LykosAccountStatusUpdateEventArgs lykosStatus = - LykosAccountStatusUpdateEventArgs.Disconnected; + private LykosAccountStatusUpdateEventArgs lykosStatus = LykosAccountStatusUpdateEventArgs.Disconnected; [ObservableProperty] - private CivitAccountStatusUpdateEventArgs civitStatus = - CivitAccountStatusUpdateEventArgs.Disconnected; + private CivitAccountStatusUpdateEventArgs civitStatus = CivitAccountStatusUpdateEventArgs.Disconnected; public AccountSettingsViewModel( IAccountsService accountsService, @@ -116,11 +113,7 @@ public override void OnLoaded() private async Task BeforeConnectCheck() { // Show credentials storage notice if not seen - if ( - !settingsManager.Settings.SeenTeachingTips.Contains( - TeachingTip.AccountsCredentialsStorageNotice - ) - ) + if (!settingsManager.Settings.SeenTeachingTips.Contains(TeachingTip.AccountsCredentialsStorageNotice)) { var dialog = new BetterContentDialog { @@ -242,10 +235,7 @@ Login to [CivitAI](https://civitai.com/) and head to your [Account](https://civi ); dialog.PrimaryButtonText = Resources.Action_Connect; - if ( - await dialog.ShowAsync() != ContentDialogResult.Primary - || textFields[0].Text is not { } apiToken - ) + if (await dialog.ShowAsync() != ContentDialogResult.Primary || textFields[0].Text is not { } apiToken) { return; } diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs index 6f3c3c4c5..290bed3c5 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs @@ -24,7 +24,7 @@ using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels.Settings; @@ -40,7 +40,8 @@ public partial class InferenceSettingsViewModel : PageViewModelBase public override string Title => "Inference"; /// - public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true }; + public override IconSource IconSource => + new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true }; [ObservableProperty] private bool isPromptCompletionEnabled = true; @@ -64,8 +65,9 @@ public partial class InferenceSettingsViewModel : PageViewModelBase public IEnumerable OutputImageFileNameFormatVars => FileNameFormatProvider .GetSample() - .Substitutions - .Select(kv => new FileNameFormatVar { Variable = $"{{{kv.Key}}}", Example = kv.Value.Invoke() }); + .Substitutions.Select( + kv => new FileNameFormatVar { Variable = $"{{{kv.Key}}}", Example = kv.Value.Invoke() } + ); [ObservableProperty] private bool isImageViewerPixelGridEnabled = true; @@ -114,7 +116,10 @@ ISettingsManager settingsManager var provider = FileNameFormatProvider.GetSample(); var template = formatProperty.Value ?? string.Empty; - if (!string.IsNullOrEmpty(template) && provider.Validate(template) == ValidationResult.Success) + if ( + !string.IsNullOrEmpty(template) + && provider.Validate(template) == ValidationResult.Success + ) { var format = FileNameFormat.Parse(template, provider); OutputImageFileNameFormatSample = format.GetFileName() + ".png"; @@ -147,7 +152,10 @@ ISettingsManager settingsManager /// /// Validator for /// - public static ValidationResult ValidateOutputImageFileNameFormat(string? format, ValidationContext context) + public static ValidationResult ValidateOutputImageFileNameFormat( + string? format, + ValidationContext context + ) { return FileNameFormatProvider.GetSample().Validate(format ?? string.Empty); } diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs index 97cad1f09..08c37695a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs @@ -55,7 +55,7 @@ using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels.Settings; diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/UpdateSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/UpdateSettingsViewModel.cs index ff7a263db..a0babde05 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/UpdateSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/UpdateSettingsViewModel.cs @@ -21,7 +21,7 @@ using StabilityMatrix.Core.Services; using StabilityMatrix.Core.Updater; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels.Settings; @@ -111,9 +111,7 @@ INavigationService settingsNavService var isBetaChannelsEnabled = args.User?.IsActiveSupporter == true; foreach ( - var card in AvailableUpdateChannelCards.Where( - c => c.UpdateChannel > UpdateChannel.Stable - ) + var card in AvailableUpdateChannelCards.Where(c => c.UpdateChannel > UpdateChannel.Stable) ) { card.IsSelectable = isBetaChannelsEnabled; @@ -169,8 +167,8 @@ public bool VerifyChannelSelection(UpdateChannelCard card) public void ShowLoginRequiredDialog() { - Dispatcher.UIThread - .InvokeAsync(async () => + Dispatcher + .UIThread.InvokeAsync(async () => { var dialog = DialogHelper.CreateTaskDialog( "Become a Supporter", @@ -214,7 +212,8 @@ partial void OnUpdateStatusChanged(UpdateStatusChangedEventArgs? value) // Use maximum version from platforms equal or lower than current foreach (var card in AvailableUpdateChannelCards) { - card.LatestVersion = value?.UpdateChannels + card.LatestVersion = value + ?.UpdateChannels .Where(kv => kv.Key <= card.UpdateChannel) .Select(kv => kv.Value) .MaxBy(info => info.Version, SemVersion.PrecedenceComparer) diff --git a/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs index 70f221be6..f12458148 100644 --- a/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs @@ -9,7 +9,7 @@ using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; using Symbol = FluentIcons.Common.Symbol; -using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; +using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; namespace StabilityMatrix.Avalonia.ViewModels; @@ -18,7 +18,8 @@ namespace StabilityMatrix.Avalonia.ViewModels; public partial class SettingsViewModel : PageViewModelBase { public override string Title => "Settings"; - public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true }; + public override IconSource IconSource => + new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true }; public IReadOnlyList SubPages { get; } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/PythonPackagesDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/PythonPackagesDialog.axaml index bb7ddddac..242ef7d2a 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/PythonPackagesDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/PythonPackagesDialog.axaml @@ -15,7 +15,7 @@ xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels" xmlns:vmDialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia" d:DataContext="{x:Static mocks:DesignData.PythonPackagesViewModel}" d:DesignHeight="450" diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml index f118e90e2..e53b82f0e 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/SelectModelVersionDialog.axaml @@ -7,7 +7,7 @@ xmlns:designData="clr-namespace:StabilityMatrix.Avalonia.DesignData" mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="850" x:DataType="dialogs:SelectModelVersionViewModel" - xmlns:fluentAvalonia="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentAvalonia="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:models="clr-namespace:StabilityMatrix.Avalonia.Models" xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml index 51e6f43ca..00bea3979 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml @@ -8,7 +8,7 @@ xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" d:DataContext="{x:Static mocks:DesignData.UpdateViewModel}" x:DataType="dialogs:UpdateViewModel" mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="550" diff --git a/StabilityMatrix.Avalonia/Views/InferencePage.axaml b/StabilityMatrix.Avalonia/Views/InferencePage.axaml index c1a8a74fa..f8e385999 100644 --- a/StabilityMatrix.Avalonia/Views/InferencePage.axaml +++ b/StabilityMatrix.Avalonia/Views/InferencePage.axaml @@ -5,7 +5,7 @@ xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:fluentIcons="using:FluentIcons.FluentAvalonia" + xmlns:fluentIcons="using:FluentIcons.Avalonia.Fluent" xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml b/StabilityMatrix.Avalonia/Views/MainWindow.axaml index 6e51fafe7..1480f64fa 100644 --- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml +++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml @@ -9,7 +9,7 @@ xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:base="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Base" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550" d:DataContext="{x:Static mocks:DesignData.MainWindowViewModel}" x:DataType="vm:MainWindowViewModel" diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml index 22fdbc372..3b1a02bbb 100644 --- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml @@ -6,7 +6,7 @@ xmlns:avaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:fluentAvalonia="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentAvalonia="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml index aa9c88a46..188e09712 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageExtensionBrowserView.axaml @@ -11,7 +11,7 @@ xmlns:extensions="clr-namespace:StabilityMatrix.Core.Models.Packages.Extensions;assembly=StabilityMatrix.Core" xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" - xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" @@ -201,6 +201,11 @@ + + > GetManifestExtensionsA CancellationToken cancellationToken = default ) { - // Get json - var content = await package - .DownloadService.GetContentAsync(manifest.Uri.ToString(), cancellationToken) - .ConfigureAwait(false); - - // Parse json - var jsonManifest = JsonSerializer.Deserialize( - content, - A1111ExtensionManifestSerializerContext.Default.Options - ); - - return jsonManifest?.GetPackageExtensions() ?? Enumerable.Empty(); + try + { + // Get json + var content = await package + .DownloadService.GetContentAsync(manifest.Uri.ToString(), cancellationToken) + .ConfigureAwait(false); + + // Parse json + var jsonManifest = JsonSerializer.Deserialize( + content, + A1111ExtensionManifestSerializerContext.Default.Options + ); + + return jsonManifest?.GetPackageExtensions() ?? Enumerable.Empty(); + } + catch (Exception e) + { + Logger.Error(e, "Failed to get extensions from manifest"); + return Enumerable.Empty(); + } } } } diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 689bbebf5..fcdd31bbd 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -486,18 +486,26 @@ public override async Task> GetManifestExtensionsA CancellationToken cancellationToken = default ) { - // Get json - var content = await package - .DownloadService.GetContentAsync(manifest.Uri.ToString(), cancellationToken) - .ConfigureAwait(false); - - // Parse json - var jsonManifest = JsonSerializer.Deserialize( - content, - ComfyExtensionManifestSerializerContext.Default.Options - ); - - return jsonManifest?.GetPackageExtensions() ?? Enumerable.Empty(); + try + { + // Get json + var content = await package + .DownloadService.GetContentAsync(manifest.Uri.ToString(), cancellationToken) + .ConfigureAwait(false); + + // Parse json + var jsonManifest = JsonSerializer.Deserialize( + content, + ComfyExtensionManifestSerializerContext.Default.Options + ); + + return jsonManifest?.GetPackageExtensions() ?? Enumerable.Empty(); + } + catch (Exception e) + { + Logger.Error(e, "Failed to get package extensions"); + return Enumerable.Empty(); + } } /// diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 698c9f1a2..094640ea8 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -1,5 +1,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; @@ -32,7 +34,9 @@ IPrerequisiteHelper prerequisiteHelper public override string LaunchCommand => "launch.py"; public override Uri PreviewImageUri => - new("https://user-images.githubusercontent.com/19834515/261830306-f79c5981-cf80-4ee3-b06b-3fef3f8bfbc7.png"); + new( + "https://user-images.githubusercontent.com/19834515/261830306-f79c5981-cf80-4ee3-b06b-3fef3f8bfbc7.png" + ); public override List LaunchOptions => new() @@ -81,7 +85,13 @@ IPrerequisiteHelper prerequisiteHelper MemoryLevel.Medium => "--always-normal-vram", _ => null }, - Options = { "--always-high-vram", "--always-normal-vram", "--always-low-vram", "--always-no-vram" } + Options = + { + "--always-high-vram", + "--always-normal-vram", + "--always-low-vram", + "--always-no-vram" + } }, new LaunchOptionDefinition { @@ -107,10 +117,10 @@ IPrerequisiteHelper prerequisiteHelper LaunchOptionDefinition.Extras }; - public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink; + public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Configuration; public override IEnumerable AvailableSharedFolderMethods => - new[] { SharedFolderMethod.Symlink, SharedFolderMethod.None }; + new[] { SharedFolderMethod.Symlink, SharedFolderMethod.Configuration, SharedFolderMethod.None }; public override Dictionary> SharedFolders => new() @@ -222,4 +232,106 @@ void HandleExit(int i) VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit); } + + public override Task SetupModelFolders( + DirectoryPath installDirectory, + SharedFolderMethod sharedFolderMethod + ) + { + return sharedFolderMethod switch + { + SharedFolderMethod.Symlink + => base.SetupModelFolders(installDirectory, SharedFolderMethod.Symlink), + SharedFolderMethod.Configuration => SetupModelFoldersConfig(installDirectory), + SharedFolderMethod.None => WriteDefaultConfig(installDirectory), + _ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null) + }; + } + + public override Task RemoveModelFolderLinks( + DirectoryPath installDirectory, + SharedFolderMethod sharedFolderMethod + ) + { + return sharedFolderMethod switch + { + SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory, sharedFolderMethod), + SharedFolderMethod.Configuration => WriteDefaultConfig(installDirectory), + SharedFolderMethod.None => Task.CompletedTask, + _ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null) + }; + } + + private JsonSerializerOptions jsonSerializerOptions = + new() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + + private async Task SetupModelFoldersConfig(DirectoryPath installDirectory) + { + var fooocusConfigPath = installDirectory.JoinFile("config.txt"); + var fooocusConfig = new FooocusConfig(); + if (fooocusConfigPath.Exists) + { + var configText = await fooocusConfigPath.ReadAllTextAsync().ConfigureAwait(false); + fooocusConfig = JsonSerializer.Deserialize(configText) ?? new FooocusConfig(); + } + else + { + fooocusConfigPath.Create(); + } + + fooocusConfig.PathCheckpoints = Path.Combine(settingsManager.ModelsDirectory, "StableDiffusion"); + fooocusConfig.PathLoras = Path.Combine(settingsManager.ModelsDirectory, "Lora"); + fooocusConfig.PathEmbeddings = Path.Combine(settingsManager.ModelsDirectory, "TextualInversion"); + fooocusConfig.PathVaeApprox = Path.Combine(settingsManager.ModelsDirectory, "ApproxVAE"); + fooocusConfig.PathUpscaleModels = Path.Combine(settingsManager.ModelsDirectory, "ESRGAN"); + fooocusConfig.PathInpaint = Path.Combine(installDirectory, "models", "inpaint"); + fooocusConfig.PathControlnet = Path.Combine(settingsManager.ModelsDirectory, "ControlNet"); + fooocusConfig.PathClipVision = Path.Combine(settingsManager.ModelsDirectory, "CLIP"); + fooocusConfig.PathFooocusExpansion = Path.Combine( + installDirectory, + "models", + "prompt_expansion", + "fooocus_expansion" + ); + fooocusConfig.PathOutputs = Path.Combine(installDirectory, OutputFolderName); + + await fooocusConfigPath + .WriteAllTextAsync(JsonSerializer.Serialize(fooocusConfig, jsonSerializerOptions)) + .ConfigureAwait(false); + } + + private async Task WriteDefaultConfig(DirectoryPath installDirectory) + { + var fooocusConfigPath = installDirectory.JoinFile("config.txt"); + var fooocusConfig = new FooocusConfig(); + if (fooocusConfigPath.Exists) + { + var configText = await fooocusConfigPath.ReadAllTextAsync().ConfigureAwait(false); + fooocusConfig = JsonSerializer.Deserialize(configText) ?? new FooocusConfig(); + } + else + { + fooocusConfigPath.Create(); + } + + fooocusConfig.PathCheckpoints = Path.Combine(installDirectory, "models", "checkpoints"); + fooocusConfig.PathLoras = Path.Combine(installDirectory, "models", "loras"); + fooocusConfig.PathEmbeddings = Path.Combine(installDirectory, "models", "embeddings"); + fooocusConfig.PathVaeApprox = Path.Combine(installDirectory, "models", "vae_approx"); + fooocusConfig.PathUpscaleModels = Path.Combine(installDirectory, "models", "upscale_models"); + fooocusConfig.PathInpaint = Path.Combine(installDirectory, "models", "inpaint"); + fooocusConfig.PathControlnet = Path.Combine(installDirectory, "models", "controlnet"); + fooocusConfig.PathClipVision = Path.Combine(installDirectory, "models", "clip_vision"); + fooocusConfig.PathFooocusExpansion = Path.Combine( + installDirectory, + "models", + "prompt_expansion", + "fooocus_expansion" + ); + fooocusConfig.PathOutputs = Path.Combine(installDirectory, OutputFolderName); + + await fooocusConfigPath + .WriteAllTextAsync(JsonSerializer.Serialize(fooocusConfig, jsonSerializerOptions)) + .ConfigureAwait(false); + } } diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj index 44f76ba69..152ab78f6 100644 --- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj +++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj @@ -17,19 +17,19 @@ - + - - - - - + + + + + - + - + @@ -38,23 +38,23 @@ - - + + - + - + - + - - - + + + diff --git a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj index a0acdc339..4acde2abc 100644 --- a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj +++ b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj @@ -12,9 +12,9 @@ - + - + @@ -23,7 +23,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/StabilityMatrix.UITests/MainWindowTests.cs b/StabilityMatrix.UITests/MainWindowTests.cs index 1c002cf55..2e2037468 100644 --- a/StabilityMatrix.UITests/MainWindowTests.cs +++ b/StabilityMatrix.UITests/MainWindowTests.cs @@ -8,7 +8,6 @@ namespace StabilityMatrix.UITests; -[UsesVerify] [Collection("TempDir")] [TestCaseOrderer("StabilityMatrix.UITests.PriorityOrderer", "StabilityMatrix.UITests")] public class MainWindowTests : TestBase diff --git a/StabilityMatrix.UITests/ModelBrowser/CivitAiBrowserTests.cs b/StabilityMatrix.UITests/ModelBrowser/CivitAiBrowserTests.cs index fd9b2fd23..0aadb3fc6 100644 --- a/StabilityMatrix.UITests/ModelBrowser/CivitAiBrowserTests.cs +++ b/StabilityMatrix.UITests/ModelBrowser/CivitAiBrowserTests.cs @@ -1,13 +1,4 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Threading; -using Avalonia.VisualTree; -using FluentAvalonia.UI.Controls; -using StabilityMatrix.Avalonia.Views; -using StabilityMatrix.UITests.Extensions; +namespace StabilityMatrix.UITests.ModelBrowser; -namespace StabilityMatrix.UITests.ModelBrowser; - -[UsesVerify] [Collection("TempDir")] -public class CivitAiBrowserTests : TestBase { } +public class CivitAiBrowserTests : TestBase; diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj index 429b86f12..f94bfc767 100644 --- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj +++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj @@ -10,16 +10,16 @@ - + - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all From 3827c189c49f748c442325996e9128b62cdbb7fb Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 19 Jan 2024 15:28:04 -0500 Subject: [PATCH 189/276] Add CopyDetails resource --- StabilityMatrix.Avalonia/Languages/Resources.Designer.cs | 9 +++++++++ StabilityMatrix.Avalonia/Languages/Resources.resx | 3 +++ 2 files changed, 12 insertions(+) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 48cea020d..daf138bed 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 Details. + /// + public static string Action_CopyDetails { + get { + return ResourceManager.GetString("Action_CopyDetails", resourceCulture); + } + } + /// /// Looks up a localized string similar to Copy Trigger Words. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index 9a64e94f9..cef291193 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -936,4 +936,7 @@ No extensions found. + + Copy Details + From 47736c828cd2ba222d12292f4346b2a11871df50 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 19 Jan 2024 15:28:15 -0500 Subject: [PATCH 190/276] Add copy button for exception dialog --- StabilityMatrix.Avalonia/Program.cs | 9 +++- .../ViewModels/Dialogs/ExceptionViewModel.cs | 35 ++++++++++++++++ .../Views/Dialogs/ExceptionDialog.axaml | 41 +++++++++++++++---- .../Views/Dialogs/ExceptionDialog.axaml.cs | 12 ++++++ 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 40d8531c5..8e60cfe72 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -347,11 +347,13 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc if (e.ExceptionObject is not Exception ex) return; + SentryId? sentryId = null; + // Exception automatically logged by Sentry if enabled if (SentrySdk.IsEnabled) { ex.SetSentryMechanism("AppDomain.UnhandledException", handled: false); - SentrySdk.CaptureException(ex); + sentryId = SentrySdk.CaptureException(ex); SentrySdk.FlushAsync().SafeFireAndForget(); } else @@ -361,7 +363,10 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) { - var dialog = new ExceptionDialog { DataContext = new ExceptionViewModel { Exception = ex } }; + var dialog = new ExceptionDialog + { + DataContext = new ExceptionViewModel { Exception = ex, SentryId = sentryId } + }; var mainWindow = lifetime.MainWindow; // We can only show dialog if main window exists, and is visible diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs index 42e8a6d65..9531c8641 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs @@ -1,4 +1,5 @@ using System; +using Sentry; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Attributes; @@ -12,7 +13,41 @@ public partial class ExceptionViewModel : ViewModelBase { public Exception? Exception { get; set; } + public SentryId? SentryId { get; set; } + public string? Message => Exception?.Message; public string? ExceptionType => Exception?.GetType().Name ?? ""; + + public string? FormatAsMarkdown() + { + if (Exception is null) + { + return null; + } + + var message = $"## Exception\n{ExceptionType}: {Message}\n"; + + if (SentryId is not null) + { + message += $"### Sentry ID\n```\n{SentryId}\n```\n"; + } + + if (Exception.StackTrace != null) + { + message += $"### Stack Trace\n```\n{Exception.StackTrace}\n```\n"; + } + + if (Exception.InnerException is { } innerException) + { + message += $"## Inner Exception\n{innerException.GetType().Name}: {innerException.Message}\n"; + + if (innerException.StackTrace != null) + { + message += $"### Stack Trace\n```\n{innerException.StackTrace}\n```\n"; + } + } + + return message; + } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml index 2612d4db7..89bf3c971 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml @@ -6,6 +6,7 @@ xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" + xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" d:DataContext="{x:Static mocks:DesignData.ExceptionViewModel}" x:DataType="dialogs:ExceptionViewModel" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550" @@ -73,16 +74,38 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml.cs new file mode 100644 index 000000000..9930025ab --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; +using Avalonia.Controls; +using Avalonia.Interactivity; +using FluentAvalonia.UI.Controls; +using KGySoft.CoreLibraries; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Core.Models.Packages; + +namespace StabilityMatrix.Avalonia.Views.Dialogs; + +public partial class NewOneClickInstallDialog : UserControlBase +{ + public NewOneClickInstallDialog() + { + InitializeComponent(); + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + var teachingTip = + this.FindControl("InferenceTeachingTip") + ?? throw new InvalidOperationException("TeachingTip not found"); + + teachingTip.ActionButtonClick += (_, _) => + { + teachingTip.IsOpen = false; + }; + + // Find ComfyUI listbox item + var listBox = this.FindControl("PackagesRepeater"); + + // Find ComfyUI listbox item + if (listBox?.ItemsSource?.Cast().FirstOrDefault(p => p is ComfyUI) is { } comfy) + { + var comfyItem = listBox.TryGetElement(listBox?.ItemsSource?.IndexOf(comfy) ?? 0); + + // comfyItem!.IsSelected = true; + + teachingTip.Target = comfyItem; + teachingTip.IsOpen = true; + } + } +} diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml index dc8ba2ca4..b88f77179 100644 --- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml +++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml @@ -20,7 +20,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml.cs new file mode 100644 index 000000000..c478fa10c --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml.cs @@ -0,0 +1,11 @@ +using StabilityMatrix.Avalonia.Controls; + +namespace StabilityMatrix.Avalonia.Views.Dialogs; + +public partial class RecommendedModelsDialog : UserControlBase +{ + public RecommendedModelsDialog() + { + InitializeComponent(); + } +} diff --git a/StabilityMatrix.Core/Models/Api/CivitFile.cs b/StabilityMatrix.Core/Models/Api/CivitFile.cs index 114bc2495..fa2c9d226 100644 --- a/StabilityMatrix.Core/Models/Api/CivitFile.cs +++ b/StabilityMatrix.Core/Models/Api/CivitFile.cs @@ -6,16 +6,16 @@ public class CivitFile { [JsonPropertyName("sizeKB")] public double SizeKb { get; set; } - + [JsonPropertyName("pickleScanResult")] public string PickleScanResult { get; set; } - + [JsonPropertyName("virusScanResult")] public string VirusScanResult { get; set; } - + [JsonPropertyName("scannedAt")] public DateTime? ScannedAt { get; set; } - + [JsonPropertyName("metadata")] public CivitFileMetadata Metadata { get; set; } @@ -24,19 +24,23 @@ public class CivitFile [JsonPropertyName("downloadUrl")] public string DownloadUrl { get; set; } - + [JsonPropertyName("hashes")] public CivitFileHashes Hashes { get; set; } - + [JsonPropertyName("type")] public CivitFileType Type { get; set; } - + + [JsonPropertyName("primary")] + public bool IsPrimary { get; set; } + private FileSizeType? fullFilesSize; public FileSizeType FullFilesSize { get { - if (fullFilesSize != null) return fullFilesSize; + if (fullFilesSize != null) + return fullFilesSize; fullFilesSize = new FileSizeType(SizeKb); return fullFilesSize; } diff --git a/StabilityMatrix.Core/Models/Api/Lykos/GetRecommendedModelsResponse.cs b/StabilityMatrix.Core/Models/Api/Lykos/GetRecommendedModelsResponse.cs index 3c13a2533..29aa4596e 100644 --- a/StabilityMatrix.Core/Models/Api/Lykos/GetRecommendedModelsResponse.cs +++ b/StabilityMatrix.Core/Models/Api/Lykos/GetRecommendedModelsResponse.cs @@ -2,6 +2,13 @@ public class GetRecommendedModelsResponse { - public required IEnumerable Sd15 { get; set; } - public required IEnumerable Sdxl { get; set; } + public required ModelLists Sd15 { get; set; } + public required ModelLists Sdxl { get; set; } + public required ModelLists Decoders { get; set; } +} + +public class ModelLists +{ + public IEnumerable? CivitAi { get; set; } + public IEnumerable? HuggingFace { get; set; } } From 490745f77c6580e2536a4bd73a24644adaca58b0 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 26 Jan 2024 19:05:34 -0800 Subject: [PATCH 223/276] mostly finished recommended models view --- .../Languages/Resources.Designer.cs | 18 +++ .../Languages/Resources.resx | 6 + .../Dialogs/NewOneClickInstallViewModel.cs | 2 +- .../Dialogs/RecommendedModelItemViewModel.cs | 4 + .../Dialogs/RecommendedModelsViewModel.cs | 144 +++++++++++++++++- .../ViewModels/MainWindowViewModel.cs | 21 ++- .../Dialogs/RecommendedModelsDialog.axaml | 77 ++++++++-- .../Views/MainWindow.axaml | 8 + .../Views/MainWindow.axaml.cs | 21 +++ StabilityMatrix.Core/Api/ILykosAuthApi.cs | 3 +- StabilityMatrix.Core/Helper/EventManager.cs | 4 + .../Models/Settings/TeachingTip.cs | 1 + 12 files changed, 285 insertions(+), 24 deletions(-) diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 132fdfbc2..4a44530c1 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -212,6 +212,15 @@ public static string Action_Downgrade { } } + /// + /// Looks up a localized string similar to Download. + /// + public static string Action_Download { + get { + return ResourceManager.GetString("Action_Download", resourceCulture); + } + } + /// /// Looks up a localized string similar to Edit. /// @@ -2426,6 +2435,15 @@ public static string TeachingTip_ClickLaunchToGetStarted { } } + /// + /// 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("TeachingTip_DownloadsExplanation", resourceCulture); + } + } + /// /// Looks up a localized string similar to Additional folders such as IPAdapters and TextualInversions (embeddings) can be enabled here. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index f731e8b01..51ead9bc3 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -942,4 +942,10 @@ Copy Details + + Download + + + Check the progress of your package installations and model downloads here. + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs index 5a9ea21e3..d5ab42714 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs @@ -149,7 +149,7 @@ private async Task InstallPackage(BasePackage selectedPackage) var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, installedPackage); steps.Add(addInstalledPackageStep); - var runner = new PackageModificationRunner { ShowDialogOnStart = true, HideCloseButton = true, }; + var runner = new PackageModificationRunner { ShowDialogOnStart = false, HideCloseButton = false, }; EventManager.Instance.OnAddPackageInstallWithoutBlocking(this, runner, steps); OnPrimaryButtonClick(); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs index 59f8dba11..3de1d5daa 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Models.Api; @@ -24,4 +25,7 @@ public partial class RecommendedModelItemViewModel : ViewModelBase ModelVersion.Images?.FirstOrDefault()?.Url == null ? Assets.NoImage : new Uri(ModelVersion.Images.First().Url); + + [RelayCommand] + public void ToggleSelection() => IsSelected = !IsSelected; } diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs index e88da7da2..4b915e6cd 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs @@ -1,30 +1,37 @@ using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using Avalonia.Controls; +using CommunityToolkit.Mvvm.Input; using DynamicData; using DynamicData.Binding; -using LiteDB; -using LiteDB.Async; using Microsoft.Extensions.Logging; +using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Api; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Database; using StabilityMatrix.Core.Extensions; -using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api; +using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; [Transient] [ManagedService] -public class RecommendedModelsViewModel : ContentDialogViewModelBase +public partial class RecommendedModelsViewModel : ContentDialogViewModelBase { private readonly ILogger logger; private readonly ILykosAuthApi lykosApi; private readonly ICivitApi civitApi; private readonly ILiteDbContext liteDbContext; + private readonly ISettingsManager settingsManager; + private readonly INotificationService notificationService; + private readonly ITrackedDownloadService trackedDownloadService; + private readonly IDownloadService downloadService; public SourceCache CivitModels { get; } = new(p => p.ModelVersion.Id); public IObservableCollection Sd15Models { get; set; } = @@ -37,13 +44,21 @@ public RecommendedModelsViewModel( ILogger logger, ILykosAuthApi lykosApi, ICivitApi civitApi, - ILiteDbContext liteDbContext + ILiteDbContext liteDbContext, + ISettingsManager settingsManager, + INotificationService notificationService, + ITrackedDownloadService trackedDownloadService, + IDownloadService downloadService ) { this.logger = logger; this.lykosApi = lykosApi; this.civitApi = civitApi; this.liteDbContext = liteDbContext; + this.settingsManager = settingsManager; + this.notificationService = notificationService; + this.trackedDownloadService = trackedDownloadService; + this.downloadService = downloadService; CivitModels .Connect() @@ -65,6 +80,125 @@ public override async Task OnLoadedAsync() if (Design.IsDesignMode) return; + // See if query is cached + CivitModelQueryCacheEntry? cachedQuery = null; + var recommendedModels = await lykosApi.GetRecommendedModels(); + + CivitModels.AddOrUpdate( + recommendedModels.Items.Select( + model => + new RecommendedModelItemViewModel + { + ModelVersion = model.ModelVersions.First( + x => !x.BaseModel.Contains("Turbo", StringComparison.OrdinalIgnoreCase) + ), + Author = $"by {model.Creator.Username}", + CivitModel = model + } + ) + ); + } + + [RelayCommand] + private async Task DoImport() + { + var selectedModels = SdxlModels.Where(x => x.IsSelected).Concat(Sd15Models.Where(x => x.IsSelected)); + + foreach (var model in selectedModels) + { + // Get latest version file + var modelFile = model.ModelVersion.Files?.FirstOrDefault( + x => x is { Type: CivitFileType.Model, IsPrimary: true } + ); + if (modelFile is null) + { + continue; + } + + var rootModelsDirectory = new DirectoryPath(settingsManager.ModelsDirectory); + + var downloadDirectory = rootModelsDirectory.JoinDir( + model.CivitModel.Type.ConvertTo().GetStringValue() + ); + // Folders might be missing if user didn't install any packages yet + downloadDirectory.Create(); + + var downloadPath = downloadDirectory.JoinFile(modelFile.Name); + + // Download model info and preview first + var cmInfoPath = await SaveCmInfo( + model.CivitModel, + model.ModelVersion, + modelFile, + downloadDirectory + ); + var previewImagePath = await SavePreviewImage(model.ModelVersion, downloadPath); + + // Create tracked download + var download = trackedDownloadService.NewDownload(modelFile.DownloadUrl, downloadPath); + + // Add hash info + download.ExpectedHashSha256 = modelFile.Hashes.SHA256; + + // Add files to cleanup list + download.ExtraCleanupFileNames.Add(cmInfoPath); + if (previewImagePath is not null) + { + download.ExtraCleanupFileNames.Add(previewImagePath); + } + + // Add hash context action + download.ContextAction = CivitPostDownloadContextAction.FromCivitFile(modelFile); + + download.Start(); + } + } + + private static async Task SaveCmInfo( + CivitModel model, + CivitModelVersion modelVersion, + CivitFile modelFile, + DirectoryPath downloadDirectory + ) + { + var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Name); + var modelInfo = new ConnectedModelInfo(model, modelVersion, modelFile, DateTime.UtcNow); + + await modelInfo.SaveJsonToDirectory(downloadDirectory, modelFileName); + + var jsonName = $"{modelFileName}.cm-info.json"; + return downloadDirectory.JoinFile(jsonName); + } + + /// + /// Saves the preview image to the same directory as the model file + /// + /// + /// + /// The file path of the saved preview image + private async Task SavePreviewImage(CivitModelVersion modelVersion, FilePath modelFilePath) + { + // Skip if model has no images + if (modelVersion.Images == null || modelVersion.Images.Count == 0) + { + return null; + } + + var image = modelVersion.Images[0]; + var imageExtension = Path.GetExtension(image.Url).TrimStart('.'); + if (imageExtension is "jpg" or "jpeg" or "png") + { + var imageDownloadPath = modelFilePath.Directory!.JoinFile( + $"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" + ); + + var imageTask = downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); + await notificationService.TryAsync(imageTask, "Could not download preview image"); + + return imageDownloadPath; + } + + return null; } } diff --git a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs index 6a14ebe16..b4922d29b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs @@ -128,7 +128,7 @@ protected override async Task OnInitialLoadedAsync() if (Program.Args.DebugOneClickInstall || settingsManager.Settings.InstalledPackages.Count == 0) { - var viewModel = dialogFactory.Get(); + var viewModel = dialogFactory.Get(); var dialog = new BetterContentDialog { IsPrimaryButtonEnabled = false, @@ -136,7 +136,7 @@ protected override async Task OnInitialLoadedAsync() IsFooterVisible = false, FullSizeDesired = true, MinDialogHeight = 775, - Content = new RecommendedModelsDialog { DataContext = viewModel }, + Content = new NewOneClickInstallDialog { DataContext = viewModel }, }; EventManager.Instance.OneClickInstallFinished += (_, skipped) => @@ -149,6 +149,23 @@ protected override async Task OnInitialLoadedAsync() }; await dialog.ShowAsync(App.TopLevel); + + var recommendedModelsViewModel = dialogFactory.Get(); + dialog = new BetterContentDialog + { + IsPrimaryButtonEnabled = true, + FullSizeDesired = true, + MinDialogHeight = 900, + PrimaryButtonText = Resources.Action_Download, + CloseButtonText = Resources.Action_Close, + DefaultButton = ContentDialogButton.Primary, + PrimaryButtonCommand = recommendedModelsViewModel.DoImportCommand, + Content = new RecommendedModelsDialog { DataContext = recommendedModelsViewModel }, + }; + + await dialog.ShowAsync(App.TopLevel); + + EventManager.Instance.OnDownloadsTeachingTipRequested(); } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml index e3c58d873..a1abb3811 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/RecommendedModelsDialog.axaml @@ -11,17 +11,59 @@ xmlns:packages="clr-namespace:StabilityMatrix.Core.Models.Packages;assembly=StabilityMatrix.Core" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:api="clr-namespace:StabilityMatrix.Core.Models.Api;assembly=StabilityMatrix.Core" + xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="725" x:DataType="dialogs:RecommendedModelsViewModel" d:DataContext="{x:Static mocks:DesignData.RecommendedModelsViewModel}" x:Class="StabilityMatrix.Avalonia.Views.Dialogs.RecommendedModelsDialog"> + + + + + + + + + + + + +