From b4fd64e7fc9592b60ba9dd2c6fa3887a1986080e Mon Sep 17 00:00:00 2001 From: jt Date: Sat, 18 Nov 2023 00:14:22 -0800 Subject: [PATCH 01/15] 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 eb84e3f3..84e8c3f9 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 c2821641..2e08109c 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 e500a1e4..a6f04b3d 100644 --- a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs +++ b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs @@ -64,7 +64,7 @@ public class UriHandler { RegisterUriSchemeWin(); } - else + else if (Compat.IsLinux) { RegisterUriSchemeUnix(); } diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index fb16d35f..d3111ecd 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 29ff06b9..f704b0f0 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -133,6 +133,11 @@ public abstract class BasePackage 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 eeef1ce3..933e4fb3 100644 --- a/StabilityMatrix.Core/Models/Packages/VoltaML.cs +++ b/StabilityMatrix.Core/Models/Packages/VoltaML.cs @@ -62,7 +62,7 @@ public class VoltaML : BaseGitPackage 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 3a20cc60..8adde5eb 100644 --- a/StabilityMatrix.Core/Processes/ProcessRunner.cs +++ b/StabilityMatrix.Core/Processes/ProcessRunner.cs @@ -92,7 +92,7 @@ public static class ProcessRunner 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 254f8efe..f62ba22a 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 87423475..a0acdc33 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 8062d3bd..961598f0 100644 --- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj +++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj @@ -11,6 +11,7 @@ + From c5bda38264cd5fc9e0eb3e80c2fc39d840ab33b2 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 12:18:21 -0500 Subject: [PATCH 02/15] Add CLIPSetLastLayer Node --- .../Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index 25d3f9cf..f308e993 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -119,6 +119,14 @@ public class ComfyNodeBuilder public required int Width { get; init; } } + public record CLIPSetLastLayer : ComfyTypedNodeBase + { + public required ClipNodeConnection Clip { get; init; } + + [Range(-24, -1)] + public int StopAtClipLayer { get; init; } = -1; + } + public static NamedComfyNode LatentFromBatch( string name, LatentNodeConnection samples, From 097845a70984eb7ec5eb9f15da8ffa006461a603 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:14:12 -0500 Subject: [PATCH 03/15] Add NullableExtensions.Unwrap --- .../Extensions/NullableExtensions.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 StabilityMatrix.Core/Extensions/NullableExtensions.cs diff --git a/StabilityMatrix.Core/Extensions/NullableExtensions.cs b/StabilityMatrix.Core/Extensions/NullableExtensions.cs new file mode 100644 index 00000000..aa644fb9 --- /dev/null +++ b/StabilityMatrix.Core/Extensions/NullableExtensions.cs @@ -0,0 +1,28 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace StabilityMatrix.Core.Extensions; + +public static class NullableExtensions +{ + /// + /// Unwraps a nullable object, throwing an exception if it is null. + /// + /// + /// Thrown if () is null. + /// + [DebuggerStepThrough] + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Unwrap([NotNull] this T? obj, [CallerArgumentExpression("obj")] string? paramName = null) + where T : class + { + if (obj is null) + { + throw new ArgumentNullException(paramName, $"Unwrap of a null value ({typeof(T)}) {paramName}."); + } + return obj; + } +} From 74aac6272b9cdb10ea4759262c29527c81f9725f Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:53:14 -0500 Subject: [PATCH 04/15] Add NullableExtensions.Unwrap struct overload --- .../Extensions/NullableExtensions.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/StabilityMatrix.Core/Extensions/NullableExtensions.cs b/StabilityMatrix.Core/Extensions/NullableExtensions.cs index aa644fb9..64264ef6 100644 --- a/StabilityMatrix.Core/Extensions/NullableExtensions.cs +++ b/StabilityMatrix.Core/Extensions/NullableExtensions.cs @@ -25,4 +25,23 @@ public static class NullableExtensions } return obj; } + + /// + /// Unwraps a nullable struct object, throwing an exception if it is null. + /// + /// + /// Thrown if () is null. + /// + [DebuggerStepThrough] + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Unwrap([NotNull] this T? obj, [CallerArgumentExpression("obj")] string? paramName = null) + where T : struct + { + if (obj is null) + { + throw new ArgumentNullException(paramName, $"Unwrap of a null value ({typeof(T)}) {paramName}."); + } + return obj.Value; + } } From 5871241d6feedc05466857498d1d463737a3dbc6 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:54:39 -0500 Subject: [PATCH 05/15] Add Clip skip and model connection refactors --- .../Extensions/ComfyNodeBuilderExtensions.cs | 67 +++++----- .../Inference/ModuleApplyStepEventArgs.cs | 15 +-- .../Inference/ModelCardViewModel.cs | 79 +++++++---- .../Inference/Modules/FreeUModule.cs | 31 ++--- .../Inference/Modules/HiresFixModule.cs | 9 +- .../Inference/PromptCardViewModel.cs | 125 ++++-------------- .../Inference/SamplerCardViewModel.cs | 64 ++++----- .../NodeTypes/ConditioningConnections.cs | 12 ++ .../Api/Comfy/NodeTypes/ModelConnections.cs | 15 +++ .../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 35 ++--- 10 files changed, 208 insertions(+), 244 deletions(-) create mode 100644 StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ConditioningConnections.cs create mode 100644 StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ModelConnections.cs diff --git a/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs b/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs index 38c28fb3..a4a88705 100644 --- a/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs +++ b/StabilityMatrix.Avalonia/Extensions/ComfyNodeBuilderExtensions.cs @@ -20,15 +20,17 @@ public static class ComfyNodeBuilderExtensions int? batchIndex = null ) { - var emptyLatent = builder.Nodes.AddTypedNode( - new ComfyNodeBuilder.EmptyLatentImage - { - Name = "EmptyLatentImage", - BatchSize = batchSize, - Height = height, - Width = width - } - ); + var emptyLatent = builder + .Nodes + .AddTypedNode( + new ComfyNodeBuilder.EmptyLatentImage + { + Name = "EmptyLatentImage", + BatchSize = batchSize, + Height = height, + Width = width + } + ); builder.Connections.Primary = emptyLatent.Output; builder.Connections.PrimarySize = new Size(width, height); @@ -36,7 +38,8 @@ public static class ComfyNodeBuilderExtensions // If batch index is selected, add a LatentFromBatch if (batchIndex is not null) { - builder.Connections.Primary = builder.Nodes + builder.Connections.Primary = builder + .Nodes .AddNamedNode( ComfyNodeBuilder.LatentFromBatch( "LatentFromBatch", @@ -64,9 +67,9 @@ public static class ComfyNodeBuilderExtensions var sourceImageRelativePath = Path.Combine("Inference", image.GetHashGuidFileNameCached()); // Load source - var loadImage = builder.Nodes.AddTypedNode( - new ComfyNodeBuilder.LoadImage { Name = "LoadImage", Image = sourceImageRelativePath } - ); + var loadImage = builder + .Nodes + .AddTypedNode(new ComfyNodeBuilder.LoadImage { Name = "LoadImage", Image = sourceImageRelativePath }); builder.Connections.Primary = loadImage.Output1; builder.Connections.PrimarySize = imageSize; @@ -74,7 +77,8 @@ public static class ComfyNodeBuilderExtensions // If batch index is selected, add a LatentFromBatch if (batchIndex is not null) { - builder.Connections.Primary = builder.Nodes + builder.Connections.Primary = builder + .Nodes .AddNamedNode( ComfyNodeBuilder.LatentFromBatch( "LatentFromBatch", @@ -93,24 +97,25 @@ public static class ComfyNodeBuilderExtensions if (builder.Connections.Primary is null) throw new ArgumentException("No Primary"); - var image = builder.Connections.Primary.Match( - _ => - builder.GetPrimaryAsImage( - builder.Connections.PrimaryVAE - ?? builder.Connections.RefinerVAE - ?? builder.Connections.BaseVAE - ?? throw new ArgumentException("No Primary, Refiner, or Base VAE") - ), - image => image - ); + var image = builder + .Connections + .Primary + .Match( + _ => + builder.GetPrimaryAsImage( + builder.Connections.PrimaryVAE + ?? builder.Connections.Refiner.VAE + ?? builder.Connections.Base.VAE + ?? throw new ArgumentException("No Primary, Refiner, or Base VAE") + ), + image => image + ); - var previewImage = builder.Nodes.AddTypedNode( - new ComfyNodeBuilder.PreviewImage - { - Name = builder.Nodes.GetUniqueName("SaveImage"), - Images = image - } - ); + var previewImage = builder + .Nodes + .AddTypedNode( + new ComfyNodeBuilder.PreviewImage { Name = builder.Nodes.GetUniqueName("SaveImage"), Images = image } + ); builder.Connections.OutputNodes.Add(previewImage); diff --git a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs index f90baa4b..8119abc1 100644 --- a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs +++ b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using StabilityMatrix.Core.Models.Api.Comfy.Nodes; using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; +using StabilityMatrix.Core.Models.Api.Comfy.Nodes; namespace StabilityMatrix.Avalonia.Models.Inference; @@ -29,26 +29,19 @@ public class ModuleApplyStepEventArgs : EventArgs /// /// Generation overrides (like hires fix generate, current seed generate, etc.) /// - public IReadOnlyDictionary IsEnabledOverrides { get; init; } = - new Dictionary(); + public IReadOnlyDictionary IsEnabledOverrides { get; init; } = new Dictionary(); public class ModuleApplyStepTemporaryArgs { /// /// Temporary conditioning apply step, used by samplers to apply control net. /// - public ( - ConditioningNodeConnection Positive, - ConditioningNodeConnection Negative - )? Conditioning { get; set; } + public ConditioningConnections? Conditioning { get; set; } /// /// Temporary refiner conditioning apply step, used by samplers to apply control net. /// - public ( - ConditioningNodeConnection Positive, - ConditioningNodeConnection Negative - )? RefinerConditioning { get; set; } + public ConditioningConnections? RefinerConditioning { get; set; } /// /// Temporary model apply step, used by samplers to apply control net. diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs index 5336a3e1..38e13bb2 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs @@ -9,9 +9,10 @@ using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models; -using StabilityMatrix.Core.Models.Api.Comfy.Nodes; using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; +using StabilityMatrix.Core.Models.Api.Comfy.Nodes; namespace StabilityMatrix.Avalonia.ViewModels.Inference; @@ -38,6 +39,14 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) [ObservableProperty] private bool isVaeSelectionEnabled; + [ObservableProperty] + private bool isClipSkipEnabled; + + [NotifyDataErrorInfo] + [ObservableProperty] + [Range(1, 24)] + private int clipSkip = 1; + public IInferenceClientManager ClientManager { get; } = clientManager; /// @@ -47,50 +56,68 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) var baseLoader = e.Nodes.AddTypedNode( new ComfyNodeBuilder.CheckpointLoaderSimple { - Name = "CheckpointLoader", - CkptName = - SelectedModel?.RelativePath - ?? throw new ValidationException("Model not selected") + Name = "CheckpointLoader_Base", + CkptName = SelectedModel?.RelativePath ?? throw new ValidationException("Model not selected") } ); - e.Builder.Connections.BaseModel = baseLoader.Output1; - e.Builder.Connections.BaseClip = baseLoader.Output2; - e.Builder.Connections.BaseVAE = baseLoader.Output3; + e.Builder.Connections.Base.Model = baseLoader.Output1; + e.Builder.Connections.Base.Clip = baseLoader.Output2; + e.Builder.Connections.Base.VAE = baseLoader.Output3; - // Load refiner + // Load refiner if enabled if (IsRefinerSelectionEnabled && SelectedRefiner is { IsNone: false }) { var refinerLoader = e.Nodes.AddTypedNode( new ComfyNodeBuilder.CheckpointLoaderSimple { - Name = "Refiner_CheckpointLoader", + Name = "CheckpointLoader_Refiner", CkptName = SelectedRefiner?.RelativePath ?? throw new ValidationException("Refiner Model enabled but not selected") } ); - e.Builder.Connections.RefinerModel = refinerLoader.Output1; - e.Builder.Connections.RefinerClip = refinerLoader.Output2; - e.Builder.Connections.RefinerVAE = refinerLoader.Output3; + e.Builder.Connections.Refiner.Model = refinerLoader.Output1; + e.Builder.Connections.Refiner.Clip = refinerLoader.Output2; + e.Builder.Connections.Refiner.VAE = refinerLoader.Output3; } - // Load custom VAE + // Load VAE override if enabled if (IsVaeSelectionEnabled && SelectedVae is { IsNone: false, IsDefault: false }) { var vaeLoader = e.Nodes.AddTypedNode( new ComfyNodeBuilder.VAELoader { Name = "VAELoader", - VaeName = - SelectedVae?.RelativePath - ?? throw new ValidationException("VAE enabled but not selected") + VaeName = SelectedVae?.RelativePath ?? throw new ValidationException("VAE enabled but not selected") } ); e.Builder.Connections.PrimaryVAE = vaeLoader.Output; } + + // Clip skip all models if enabled + if (IsClipSkipEnabled) + { + foreach (var (modelName, model) in e.Builder.Connections.Models) + { + if (model.Clip is not { } modelClip) + continue; + + var clipSetLastLayer = e.Nodes.AddTypedNode( + new ComfyNodeBuilder.CLIPSetLastLayer + { + Name = $"CLIP_Skip_{modelName}", + Clip = modelClip, + // Need to convert to negative indexing from (1 to 24) to (-1 to -24) + StopAtClipLayer = -ClipSkip + } + ); + + model.Clip = clipSetLastLayer.Output; + } + } } /// @@ -102,8 +129,10 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) SelectedModelName = SelectedModel?.RelativePath, SelectedVaeName = SelectedVae?.RelativePath, SelectedRefinerName = SelectedRefiner?.RelativePath, + ClipSkip = ClipSkip, IsVaeSelectionEnabled = IsVaeSelectionEnabled, - IsRefinerSelectionEnabled = IsRefinerSelectionEnabled + IsRefinerSelectionEnabled = IsRefinerSelectionEnabled, + IsClipSkipEnabled = IsClipSkipEnabled } ); } @@ -125,8 +154,11 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) ? HybridModelFile.None : ClientManager.Models.FirstOrDefault(x => x.RelativePath == model.SelectedRefinerName); + ClipSkip = model.ClipSkip; + IsVaeSelectionEnabled = model.IsVaeSelectionEnabled; IsRefinerSelectionEnabled = model.IsRefinerSelectionEnabled; + IsClipSkipEnabled = model.IsClipSkipEnabled; } /// @@ -145,19 +177,14 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) model = currentModels.FirstOrDefault( m => m.Local?.ConnectedModelInfo?.Hashes.SHA256 is { } sha256 - && sha256.StartsWith( - parameters.ModelHash, - StringComparison.InvariantCultureIgnoreCase - ) + && sha256.StartsWith(parameters.ModelHash, StringComparison.InvariantCultureIgnoreCase) ); } else { // Name matches model = currentModels.FirstOrDefault(m => m.RelativePath.EndsWith(paramsModelName)); - model ??= currentModels.FirstOrDefault( - m => m.ShortDisplayName.StartsWith(paramsModelName) - ); + model ??= currentModels.FirstOrDefault(m => m.ShortDisplayName.StartsWith(paramsModelName)); } if (model is not null) @@ -181,8 +208,10 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) public string? SelectedModelName { get; init; } public string? SelectedRefinerName { get; init; } public string? SelectedVaeName { get; init; } + public int ClipSkip { get; init; } public bool IsVaeSelectionEnabled { get; init; } public bool IsRefinerSelectionEnabled { get; init; } + public bool IsClipSkipEnabled { get; init; } } } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FreeUModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FreeUModule.cs index 4ac393b6..12093310 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FreeUModule.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/FreeUModule.cs @@ -1,7 +1,9 @@ -using StabilityMatrix.Avalonia.Models.Inference; +using System.Linq; +using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules; @@ -25,34 +27,17 @@ public class FreeUModule : ModuleBase { var card = GetCard(); - // Currently applies to both base and refiner model + // Currently applies to all models // TODO: Add option to apply to either base or refiner - if (e.Builder.Connections.BaseModel is not null) + foreach (var modelConnections in e.Builder.Connections.Models.Values.Where(m => m.Model is not null)) { - e.Builder.Connections.BaseModel = e.Nodes + modelConnections.Model = e.Nodes .AddTypedNode( new ComfyNodeBuilder.FreeU { - Name = e.Nodes.GetUniqueName("FreeU"), - Model = e.Builder.Connections.BaseModel, - B1 = card.B1, - B2 = card.B2, - S1 = card.S1, - S2 = card.S2 - } - ) - .Output; - } - - if (e.Builder.Connections.RefinerModel is not null) - { - e.Builder.Connections.RefinerModel = e.Nodes - .AddTypedNode( - new ComfyNodeBuilder.FreeU - { - Name = e.Nodes.GetUniqueName("Refiner_FreeU"), - Model = e.Builder.Connections.RefinerModel, + Name = e.Nodes.GetUniqueName($"FreeU_{modelConnections.Name}"), + Model = modelConnections.Model!, B1 = card.B1, B2 = card.B2, S1 = card.S1, diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/HiresFixModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/HiresFixModule.cs index 4fd98fea..588cd263 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/HiresFixModule.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/HiresFixModule.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Input; -using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; @@ -73,7 +70,7 @@ public partial class HiresFixModule : ModuleBase { builder.Connections.Primary = builder.Group_Upscale( builder.Nodes.GetUniqueName("HiresFix"), - builder.Connections.Primary ?? throw new ArgumentException("No Primary"), + builder.Connections.Primary.Unwrap(), builder.Connections.GetDefaultVAE(), selectedUpscaler, hiresSize.Width, @@ -99,8 +96,8 @@ public partial class HiresFixModule : ModuleBase samplerCard.SelectedScheduler?.Name ?? e.Builder.Connections.PrimaryScheduler?.Name ?? throw new ArgumentException("No PrimaryScheduler"), - Positive = builder.Connections.GetRefinerOrBaseConditioning(), - Negative = builder.Connections.GetRefinerOrBaseNegativeConditioning(), + Positive = builder.Connections.GetRefinerOrBaseConditioning().Positive, + Negative = builder.Connections.GetRefinerOrBaseConditioning().Negative, LatentImage = builder.GetPrimaryAsLatent(), Denoise = samplerCard.DenoiseStrength } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs index bad20dba..b6973534 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs @@ -18,6 +18,7 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Exceptions; using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; using StabilityMatrix.Core.Services; @@ -26,10 +27,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference; [View(typeof(PromptCard))] [ManagedService] [Transient] -public partial class PromptCardViewModel - : LoadableViewModelBase, - IParametersLoadableState, - IComfyStep +public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoadableState, IComfyStep { private readonly IModelIndexService modelIndexService; @@ -74,13 +72,11 @@ public partial class PromptCardViewModel /// Applies the prompt step. /// Requires: /// - /// - /// + /// - Model, Clip /// /// Provides: /// - /// - /// + /// - Conditioning /// /// public void ApplyStep(ModuleApplyStepEventArgs e) @@ -91,90 +87,44 @@ public partial class PromptCardViewModel var negativePrompt = GetNegativePrompt(); negativePrompt.Process(); - // If need to load loras, add a group - if (positivePrompt.ExtraNetworks.Count > 0) + foreach (var modelConnections in e.Builder.Connections.Models.Values) { - var loras = positivePrompt.GetExtraNetworksAsLocalModels(modelIndexService).ToList(); - // Add group to load loras onto model and clip in series - var lorasGroup = e.Builder.Group_LoraLoadMany( - "Loras", - e.Builder.Connections.BaseModel ?? throw new ArgumentException("BaseModel is null"), - e.Builder.Connections.BaseClip ?? throw new ArgumentException("BaseClip is null"), - loras - ); - - // Set last outputs as base model and clip - e.Builder.Connections.BaseModel = lorasGroup.Output1; - e.Builder.Connections.BaseClip = lorasGroup.Output2; + if (modelConnections.Model is not { } model || modelConnections.Clip is not { } clip) + continue; - // Refiner loras - if (e.Builder.Connections.RefinerModel is not null) + // If need to load loras, add a group + if (positivePrompt.ExtraNetworks.Count > 0) { - // Add group to load loras onto refiner model and clip in series - var lorasGroupRefiner = e.Builder.Group_LoraLoadMany( - "Refiner_Loras", - e.Builder.Connections.RefinerModel - ?? throw new ArgumentException("RefinerModel is null"), - e.Builder.Connections.RefinerClip - ?? throw new ArgumentException("RefinerClip is null"), - loras - ); + var loras = positivePrompt.GetExtraNetworksAsLocalModels(modelIndexService).ToList(); - // Set last outputs as refiner model and clip - e.Builder.Connections.RefinerModel = lorasGroupRefiner.Output1; - e.Builder.Connections.RefinerClip = lorasGroupRefiner.Output2; - } - } + // Add group to load loras onto model and clip in series + var lorasGroup = e.Builder.Group_LoraLoadMany($"Loras_{modelConnections.Name}", model, clip, loras); - // Clips - var positiveClip = e.Builder.Nodes.AddTypedNode( - new ComfyNodeBuilder.CLIPTextEncode - { - Name = "PositiveCLIP", - Clip = e.Builder.Connections.BaseClip!, - Text = positivePrompt.ProcessedText - } - ); - var negativeClip = e.Builder.Nodes.AddTypedNode( - new ComfyNodeBuilder.CLIPTextEncode - { - Name = "NegativeCLIP", - Clip = e.Builder.Connections.BaseClip!, - Text = negativePrompt.ProcessedText + // Set last outputs as model and clip + modelConnections.Model = lorasGroup.Output1; + modelConnections.Clip = lorasGroup.Output2; } - ); - // Set base conditioning from Clips - e.Builder.Connections.BaseConditioning = positiveClip.Output; - e.Builder.Connections.BaseNegativeConditioning = negativeClip.Output; - - // Refiner Clips - if (e.Builder.Connections.RefinerModel is not null) - { - var positiveClipRefiner = e.Builder.Nodes.AddTypedNode( + // Clips + var positiveClip = e.Nodes.AddTypedNode( new ComfyNodeBuilder.CLIPTextEncode { - Name = "Refiner_PositiveCLIP", - Clip = - e.Builder.Connections.RefinerClip - ?? throw new ArgumentException("RefinerClip is null"), + Name = $"PositiveCLIP_{modelConnections.Name}", + Clip = e.Builder.Connections.Base.Clip!, Text = positivePrompt.ProcessedText } ); - var negativeClipRefiner = e.Builder.Nodes.AddTypedNode( + var negativeClip = e.Nodes.AddTypedNode( new ComfyNodeBuilder.CLIPTextEncode { - Name = "Refiner_NegativeCLIP", - Clip = - e.Builder.Connections.RefinerClip - ?? throw new ArgumentException("RefinerClip is null"), + Name = $"NegativeCLIP_{modelConnections.Name}", + Clip = e.Builder.Connections.Base.Clip!, Text = negativePrompt.ProcessedText } ); - // Set refiner conditioning from Clips - e.Builder.Connections.RefinerConditioning = positiveClipRefiner.Output; - e.Builder.Connections.RefinerNegativeConditioning = negativeClipRefiner.Output; + // Set conditioning from Clips + modelConnections.Conditioning = (positiveClip.Output, negativeClip.Output); } } @@ -283,11 +233,7 @@ public partial class PromptCardViewModel ``` """; - var dialog = DialogHelper.CreateMarkdownDialog( - md, - "Prompt Syntax", - TextEditorPreset.Prompt - ); + var dialog = DialogHelper.CreateMarkdownDialog(md, "Prompt Syntax", TextEditorPreset.Prompt); dialog.MinDialogWidth = 800; dialog.MaxDialogHeight = 1000; dialog.MaxDialogWidth = 1000; @@ -305,9 +251,7 @@ public partial class PromptCardViewModel } catch (PromptError e) { - await DialogHelper - .CreatePromptErrorDialog(e, prompt.RawText, modelIndexService) - .ShowAsync(); + await DialogHelper.CreatePromptErrorDialog(e, prompt.RawText, modelIndexService).ShowAsync(); return; } @@ -327,10 +271,7 @@ public partial class PromptCardViewModel builder.AppendLine($"## Networks ({networks.Count}):"); builder.AppendLine("```csharp"); builder.AppendLine( - JsonSerializer.Serialize( - networks, - new JsonSerializerOptions() { WriteIndented = true, } - ) + JsonSerializer.Serialize(networks, new JsonSerializerOptions() { WriteIndented = true, }) ); builder.AppendLine("```"); } @@ -378,11 +319,7 @@ public partial class PromptCardViewModel public override JsonObject SaveStateToJsonObject() { return SerializeModel( - new PromptCardModel - { - Prompt = PromptDocument.Text, - NegativePrompt = NegativePromptDocument.Text - } + new PromptCardModel { Prompt = PromptDocument.Text, NegativePrompt = NegativePromptDocument.Text } ); } @@ -405,10 +342,6 @@ public partial class PromptCardViewModel /// public GenerationParameters SaveStateToParameters(GenerationParameters parameters) { - return parameters with - { - PositivePrompt = PromptDocument.Text, - NegativePrompt = NegativePromptDocument.Text - }; + return parameters with { PositivePrompt = PromptDocument.Text, NegativePrompt = NegativePromptDocument.Text }; } } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index 32640d8e..a129696f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -12,6 +12,7 @@ using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Inference.Modules; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.Api.Comfy; @@ -116,14 +117,8 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo } // Provide temp values - e.Temp.Conditioning = ( - e.Builder.Connections.BaseConditioning!, - e.Builder.Connections.BaseNegativeConditioning! - ); - e.Temp.RefinerConditioning = ( - e.Builder.Connections.RefinerConditioning!, - e.Builder.Connections.RefinerNegativeConditioning! - ); + e.Temp.Conditioning = e.Builder.Connections.Base.Conditioning; + e.Temp.RefinerConditioning = e.Builder.Connections.Refiner.Conditioning; // Apply steps from our addons ApplyAddonSteps(e); @@ -147,15 +142,17 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo var primaryLatent = e.Builder.GetPrimaryAsLatent(); // Set primary sampler and scheduler - e.Builder.Connections.PrimarySampler = SelectedSampler ?? throw new ValidationException("Sampler not selected"); - e.Builder.Connections.PrimaryScheduler = - SelectedScheduler ?? throw new ValidationException("Scheduler not selected"); + var primarySampler = SelectedSampler ?? throw new ValidationException("Sampler not selected"); + e.Builder.Connections.PrimarySampler = primarySampler; + + var primaryScheduler = SelectedScheduler ?? throw new ValidationException("Scheduler not selected"); + e.Builder.Connections.PrimaryScheduler = primaryScheduler; // Use custom sampler if SDTurbo scheduler is selected if (e.Builder.Connections.PrimaryScheduler == ComfyScheduler.SDTurbo) { // Error if using refiner - if (e.Builder.Connections.RefinerModel is not null) + if (e.Builder.Connections.Refiner.Model is not null) { throw new ValidationException("SDTurbo Scheduler cannot be used with Refiner Model"); } @@ -172,7 +169,7 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo new ComfyNodeBuilder.SDTurboScheduler { Name = "SDTurboScheduler", - Model = e.Builder.Connections.BaseModel ?? throw new ArgumentException("No BaseModel"), + Model = e.Builder.Connections.Base.Model.Unwrap(), Steps = Steps } ); @@ -181,7 +178,7 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo new ComfyNodeBuilder.SamplerCustom { Name = "Sampler", - Model = e.Builder.Connections.BaseModel ?? throw new ArgumentException("No BaseModel"), + Model = e.Builder.Connections.Base.Model, AddNoise = true, NoiseSeed = e.Builder.Connections.Seed, Cfg = CfgScale, @@ -199,21 +196,23 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo } // Use KSampler if no refiner, otherwise need KSamplerAdvanced - if (e.Builder.Connections.RefinerModel is null) + if (e.Builder.Connections.Refiner.Model is null) { + var baseConditioning = e.Builder.Connections.Base.Conditioning.Unwrap(); + // No refiner var sampler = e.Nodes.AddTypedNode( new ComfyNodeBuilder.KSampler { Name = "Sampler", - Model = e.Builder.Connections.BaseModel ?? throw new ArgumentException("No BaseModel"), + Model = e.Builder.Connections.Base.Model.Unwrap(), Seed = e.Builder.Connections.Seed, - SamplerName = e.Builder.Connections.PrimarySampler?.Name!, - Scheduler = e.Builder.Connections.PrimaryScheduler?.Name!, + SamplerName = primarySampler.Name, + Scheduler = primaryScheduler.Name, Steps = Steps, Cfg = CfgScale, - Positive = e.Temp.Conditioning?.Positive!, - Negative = e.Temp.Conditioning?.Negative!, + Positive = baseConditioning.Positive, + Negative = baseConditioning.Negative, LatentImage = primaryLatent, Denoise = DenoiseStrength, } @@ -223,20 +222,23 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo } else { + var baseConditioning = e.Builder.Connections.Base.Conditioning.Unwrap(); + var refinerConditioning = e.Builder.Connections.Refiner.Conditioning.Unwrap(); + // Advanced base sampler for refiner var sampler = e.Nodes.AddTypedNode( new ComfyNodeBuilder.KSamplerAdvanced { Name = "Sampler", - Model = e.Builder.Connections.BaseModel ?? throw new ArgumentException("No BaseModel"), + Model = e.Builder.Connections.Base.Model.Unwrap(), AddNoise = true, NoiseSeed = e.Builder.Connections.Seed, Steps = TotalSteps, Cfg = CfgScale, - SamplerName = e.Builder.Connections.PrimarySampler?.Name!, - Scheduler = e.Builder.Connections.PrimaryScheduler?.Name!, - Positive = e.Temp.Conditioning?.Positive!, - Negative = e.Temp.Conditioning?.Negative!, + SamplerName = primarySampler.Name, + Scheduler = primaryScheduler.Name, + Positive = baseConditioning.Positive, + Negative = baseConditioning.Negative, LatentImage = primaryLatent, StartAtStep = 0, EndAtStep = Steps, @@ -248,16 +250,16 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo var refinerSampler = e.Nodes.AddTypedNode( new ComfyNodeBuilder.KSamplerAdvanced { - Name = "Refiner_Sampler", - Model = e.Builder.Connections.RefinerModel ?? throw new ArgumentException("No RefinerModel"), + Name = "Sampler_Refiner", + Model = e.Builder.Connections.Refiner.Model, AddNoise = false, NoiseSeed = e.Builder.Connections.Seed, Steps = TotalSteps, Cfg = CfgScale, - SamplerName = e.Builder.Connections.PrimarySampler?.Name!, - Scheduler = e.Builder.Connections.PrimaryScheduler?.Name!, - Positive = e.Temp.RefinerConditioning?.Positive!, - Negative = e.Temp.RefinerConditioning?.Negative!, + SamplerName = primarySampler.Name, + Scheduler = primaryScheduler.Name, + Positive = refinerConditioning.Positive, + Negative = refinerConditioning.Negative, // Connect to previous sampler LatentImage = sampler.Output, StartAtStep = Steps, diff --git a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ConditioningConnections.cs b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ConditioningConnections.cs new file mode 100644 index 00000000..02a3c2af --- /dev/null +++ b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ConditioningConnections.cs @@ -0,0 +1,12 @@ +namespace StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; + +/// +/// Combination of the positive and negative conditioning connections. +/// +public record ConditioningConnections(ConditioningNodeConnection Positive, ConditioningNodeConnection Negative) +{ + // Implicit from tuple + public static implicit operator ConditioningConnections( + (ConditioningNodeConnection Positive, ConditioningNodeConnection Negative) value + ) => new(value.Positive, value.Negative); +} diff --git a/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ModelConnections.cs b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ModelConnections.cs new file mode 100644 index 00000000..abb66596 --- /dev/null +++ b/StabilityMatrix.Core/Models/Api/Comfy/NodeTypes/ModelConnections.cs @@ -0,0 +1,15 @@ +namespace StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; + +/// +/// Connections from a loaded model +/// +public record ModelConnections(string Name) +{ + public ModelNodeConnection? Model { get; set; } + + public VAENodeConnection? VAE { get; set; } + + public ClipNodeConnection? Clip { get; set; } + + public ConditioningConnections? Conditioning { get; set; } +} diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index f308e993..73e94197 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -733,18 +733,16 @@ public class ComfyNodeBuilder public int BatchSize { get; set; } = 1; public int? BatchIndex { get; set; } - public ModelNodeConnection? BaseModel { get; set; } - public VAENodeConnection? BaseVAE { get; set; } - public ClipNodeConnection? BaseClip { get; set; } + public Dictionary Models { get; } = + new() { ["Base"] = new ModelConnections("Base"), ["Refiner"] = new ModelConnections("Refiner") }; - public ConditioningNodeConnection? BaseConditioning { get; set; } - public ConditioningNodeConnection? BaseNegativeConditioning { get; set; } + /// + /// ModelConnections from with set + /// + public IEnumerable LoadedModels => Models.Values.Where(m => m.Model is not null); - public ModelNodeConnection? RefinerModel { get; set; } - public VAENodeConnection? RefinerVAE { get; set; } - public ClipNodeConnection? RefinerClip { get; set; } - public ConditioningNodeConnection? RefinerConditioning { get; set; } - public ConditioningNodeConnection? RefinerNegativeConditioning { get; set; } + public ModelConnections Base => Models["Base"]; + public ModelConnections Refiner => Models["Refiner"]; public PrimaryNodeConnection? Primary { get; set; } public VAENodeConnection? PrimaryVAE { get; set; } @@ -759,24 +757,19 @@ public class ComfyNodeBuilder public ModelNodeConnection GetRefinerOrBaseModel() { - return RefinerModel ?? BaseModel ?? throw new NullReferenceException("No Model"); - } - - public ConditioningNodeConnection GetRefinerOrBaseConditioning() - { - return RefinerConditioning ?? BaseConditioning ?? throw new NullReferenceException("No Conditioning"); + return Refiner.Model ?? Base.Model ?? throw new NullReferenceException("No Refiner or Base Model"); } - public ConditioningNodeConnection GetRefinerOrBaseNegativeConditioning() + public ConditioningConnections GetRefinerOrBaseConditioning() { - return RefinerNegativeConditioning - ?? BaseNegativeConditioning - ?? throw new NullReferenceException("No Negative Conditioning"); + return Refiner.Conditioning + ?? Base.Conditioning + ?? throw new NullReferenceException("No Refiner or Base Conditioning"); } public VAENodeConnection GetDefaultVAE() { - return PrimaryVAE ?? RefinerVAE ?? BaseVAE ?? throw new NullReferenceException("No VAE"); + return PrimaryVAE ?? Refiner.VAE ?? Base.VAE ?? throw new NullReferenceException("No VAE"); } } From 5eaaedf4dd23fac184feca37a171db728255531f Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 16:55:06 -0500 Subject: [PATCH 06/15] Add clip skip selection to ModelCard control --- .../Controls/Inference/ModelCard.axaml | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml index e0fc6a1c..7bf995a8 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ModelCard.axaml @@ -7,6 +7,7 @@ xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" + xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" x:DataType="inference:ModelCardViewModel"> @@ -21,7 +22,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 07/15] 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 4f4e7191..26bf7897 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 @@ public class ControlNetModule : ModuleBase { 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 @@ public class ControlNetModule : ModuleBase 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 @@ public class ControlNetModule : ModuleBase 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 @@ public class ControlNetModule : ModuleBase 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 08/15] 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 446a2476..2113c78c 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 09/15] 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 38e13bb2..b8a1d94b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs @@ -9,9 +9,7 @@ using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; -using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models; -using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; using StabilityMatrix.Core.Models.Api.Comfy.Nodes; namespace StabilityMatrix.Avalonia.ViewModels.Inference; @@ -208,7 +206,7 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager) 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 10/15] 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 f54dc933..afeea869 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 00000000..7209879c --- /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 00000000..887299ca --- /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 11/15] 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 7bf995a8..4e5a3ed2 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}"/>