diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 17227789..7bb427f5 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,12 +1,12 @@ name: Automatic Backport on: - pull_request_target: - types: ["labeled", "closed"] + pull_request: + types: ["closed", "labeled"] jobs: backport: - if: startsWith(github.event.pull_request.labels.*.name, 'backport-to-') + if: ${{ (github.event.pull_request.merged == true) && (contains(github.event.pull_request.labels.*.name, 'backport-to-main') == true) }} name: Backport PR runs-on: ubuntu-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cab19b2..25c58bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 ## v2.8.2 ### Fixed - Fixed Inference Image to Image Denoise setting becoming hidden after changing schedulers +- Fixed Inference ControlNet models showing as downloadable even when they are already installed +- Fixed Inference Sampler Addon conditioning not applying (i.e. ControlNet) ## v2.8.1 ### Fixed diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index 995a93bb..b3afcdf2 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -56,7 +56,8 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache modelsSource = new(p => p.GetId()); - public IObservableCollection Models { get; } = new ObservableCollectionExtended(); + public IObservableCollection Models { get; } = + new ObservableCollectionExtended(); private readonly SourceCache vaeModelsSource = new(p => p.GetId()); @@ -67,14 +68,16 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache controlNetModelsSource = new(p => p.GetId()); - private readonly SourceCache downloadableControlNetModelsSource = new(p => p.GetId()); + private readonly SourceCache downloadableControlNetModelsSource = + new(p => p.GetId()); public IObservableCollection ControlNetModels { get; } = new ObservableCollectionExtended(); private readonly SourceCache samplersSource = new(p => p.Name); - public IObservableCollection Samplers { get; } = new ObservableCollectionExtended(); + public IObservableCollection Samplers { get; } = + new ObservableCollectionExtended(); private readonly SourceCache modelUpscalersSource = new(p => p.Name); @@ -82,7 +85,8 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient private readonly SourceCache downloadableUpscalersSource = new(p => p.Name); - public IObservableCollection Upscalers { get; } = new ObservableCollectionExtended(); + public IObservableCollection Upscalers { get; } = + new ObservableCollectionExtended(); private readonly SourceCache schedulersSource = new(p => p.Name); @@ -105,7 +109,11 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient modelsSource .Connect() - .SortBy(f => f.ShortDisplayName, SortDirection.Ascending, SortOptimisations.ComparesImmutableValuesOnly) + .SortBy( + f => f.ShortDisplayName, + SortDirection.Ascending, + SortOptimisations.ComparesImmutableValuesOnly + ) .DeferUntilLoaded() .Bind(Models) .Subscribe(); @@ -114,7 +122,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient .Connect() .Or(downloadableControlNetModelsSource.Connect()) .Sort( - SortExpressionComparer.Ascending(f => f.Type).ThenByAscending(f => f.ShortDisplayName) + SortExpressionComparer + .Ascending(f => f.Type) + .ThenByAscending(f => f.ShortDisplayName) ) .DeferUntilLoaded() .Bind(ControlNetModels) @@ -153,7 +163,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient if (IsConnected) { LoadSharedPropertiesAsync() - .SafeFireAndForget(onException: ex => logger.LogError(ex, "Error loading shared properties")); + .SafeFireAndForget( + onException: ex => logger.LogError(ex, "Error loading shared properties") + ); } }; } @@ -176,7 +188,10 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient } // Get control net model names - if (await Client.GetNodeOptionNamesAsync("ControlNetLoader", "control_net_name") is { } controlNetModelNames) + if ( + await Client.GetNodeOptionNamesAsync("ControlNetLoader", "control_net_name") is + { } controlNetModelNames + ) { controlNetModelsSource.EditDiff( controlNetModelNames.Select(HybridModelFile.FromRemote), @@ -187,13 +202,18 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient // Fetch sampler names from KSampler node if (await Client.GetSamplerNamesAsync() is { } samplerNames) { - samplersSource.EditDiff(samplerNames.Select(name => new ComfySampler(name)), ComfySampler.Comparer); + samplersSource.EditDiff( + samplerNames.Select(name => new ComfySampler(name)), + ComfySampler.Comparer + ); } // Upscalers is latent and esrgan combined // Add latent upscale methods from LatentUpscale node - if (await Client.GetNodeOptionNamesAsync("LatentUpscale", "upscale_method") is { } latentUpscalerNames) + if ( + await Client.GetNodeOptionNamesAsync("LatentUpscale", "upscale_method") is { } latentUpscalerNames + ) { latentUpscalersSource.EditDiff( latentUpscalerNames.Select(s => new ComfyUpscaler(s, ComfyUpscalerType.Latent)), @@ -204,7 +224,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient } // Add Model upscale methods - if (await Client.GetNodeOptionNamesAsync("UpscaleModelLoader", "model_name") is { } modelUpscalerNames) + if ( + await Client.GetNodeOptionNamesAsync("UpscaleModelLoader", "model_name") is { } modelUpscalerNames + ) { modelUpscalersSource.EditDiff( modelUpscalerNames.Select(s => new ComfyUpscaler(s, ComfyUpscalerType.ESRGAN)), @@ -219,7 +241,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient schedulersSource.Edit(updater => { updater.AddOrUpdate( - schedulerNames.Where(n => !schedulersSource.Keys.Contains(n)).Select(s => new ComfyScheduler(s)) + schedulerNames + .Where(n => !schedulersSource.Keys.Contains(n)) + .Select(s => new ComfyScheduler(s)) ); }); logger.LogTrace("Loaded scheduler methods: {@Schedulers}", schedulerNames); @@ -233,20 +257,24 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient { // Load local models modelsSource.EditDiff( - modelIndexService.GetFromModelIndex(SharedFolderType.StableDiffusion).Select(HybridModelFile.FromLocal), + modelIndexService + .GetFromModelIndex(SharedFolderType.StableDiffusion) + .Select(HybridModelFile.FromLocal), HybridModelFile.Comparer ); // Load local control net models controlNetModelsSource.EditDiff( - modelIndexService.GetFromModelIndex(SharedFolderType.ControlNet).Select(HybridModelFile.FromLocal), + modelIndexService + .GetFromModelIndex(SharedFolderType.ControlNet) + .Select(HybridModelFile.FromLocal), HybridModelFile.Comparer ); // Downloadable ControlNet models - var downloadableControlNets = RemoteModels - .ControlNetModels - .Where(u => !modelUpscalersSource.Lookup(u.GetId()).HasValue); + var downloadableControlNets = RemoteModels.ControlNetModels.Where( + u => !controlNetModelsSource.Lookup(u.GetId()).HasValue + ); downloadableControlNetModelsSource.EditDiff(downloadableControlNets, HybridModelFile.Comparer); // Load local VAE models @@ -264,15 +292,17 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient // Load Upscalers modelUpscalersSource.EditDiff( modelIndexService - .GetFromModelIndex(SharedFolderType.ESRGAN | SharedFolderType.RealESRGAN | SharedFolderType.SwinIR) + .GetFromModelIndex( + SharedFolderType.ESRGAN | SharedFolderType.RealESRGAN | SharedFolderType.SwinIR + ) .Select(m => new ComfyUpscaler(m.FileName, ComfyUpscalerType.ESRGAN)), ComfyUpscaler.Comparer ); // Remote upscalers - var remoteUpscalers = ComfyUpscaler - .DefaultDownloadableModels - .Where(u => !modelUpscalersSource.Lookup(u.Name).HasValue); + var remoteUpscalers = ComfyUpscaler.DefaultDownloadableModels.Where( + u => !modelUpscalersSource.Lookup(u.Name).HasValue + ); downloadableUpscalersSource.EditDiff(remoteUpscalers, ComfyUpscaler.Comparer); } @@ -322,7 +352,10 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient } /// - public async Task WriteImageToInputAsync(ImageSource imageSource, CancellationToken cancellationToken = default) + public async Task WriteImageToInputAsync( + ImageSource imageSource, + CancellationToken cancellationToken = default + ) { if (!IsConnected) return; diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index 0ca83169..c2409259 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -161,6 +161,10 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo var primaryScheduler = SelectedScheduler ?? throw new ValidationException("Scheduler not selected"); e.Builder.Connections.PrimaryScheduler = primaryScheduler; + // Use Temp Conditioning that may be modified by addons + var conditioning = e.Temp.Conditioning.Unwrap(); + var refinerConditioning = e.Temp.RefinerConditioning; + // Use custom sampler if SDTurbo scheduler is selected if (e.Builder.Connections.PrimaryScheduler == ComfyScheduler.SDTurbo) { @@ -196,8 +200,8 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo AddNoise = true, NoiseSeed = e.Builder.Connections.Seed, Cfg = CfgScale, - Positive = e.Temp.Conditioning?.Positive!, - Negative = e.Temp.Conditioning?.Negative!, + Positive = conditioning.Positive, + Negative = conditioning.Negative, Sampler = kSamplerSelect.Output, Sigmas = turboScheduler.Output, LatentImage = primaryLatent @@ -225,8 +229,8 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo Scheduler = primaryScheduler.Name, Steps = Steps, Cfg = CfgScale, - Positive = baseConditioning.Positive, - Negative = baseConditioning.Negative, + Positive = conditioning.Positive, + Negative = conditioning.Negative, LatentImage = primaryLatent, Denoise = DenoiseStrength, } @@ -236,9 +240,6 @@ 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 @@ -251,8 +252,8 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo Cfg = CfgScale, SamplerName = primarySampler.Name, Scheduler = primaryScheduler.Name, - Positive = baseConditioning.Positive, - Negative = baseConditioning.Negative, + Positive = conditioning.Positive, + Negative = conditioning.Negative, LatentImage = primaryLatent, StartAtStep = 0, EndAtStep = Steps, @@ -272,7 +273,7 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo Cfg = CfgScale, SamplerName = primarySampler.Name, Scheduler = primaryScheduler.Name, - Positive = refinerConditioning.Positive, + Positive = refinerConditioning!.Positive, Negative = refinerConditioning.Negative, // Connect to previous sampler LatentImage = sampler.Output,