Browse Source

Merge pull request #447 from LykosAI/main

v2.8.2 Update
pull/457/head
Ionite 9 months ago committed by GitHub
parent
commit
a0ff4a07dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .github/workflows/backport.yml
  2. 9
      CHANGELOG.md
  3. 8
      StabilityMatrix.Avalonia/Controls/Inference/SamplerCard.axaml
  4. 77
      StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
  5. 2
      StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
  6. 44
      StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
  7. 8
      StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
  8. 28
      StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs
  9. 21
      StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs
  10. 5
      StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs
  11. 1
      StabilityMatrix.Core/Models/Packages/A3WebUI.cs
  12. 16
      StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs

6
.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:

9
CHANGELOG.md

@ -5,6 +5,15 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
## v2.8.2
### Added
- Added missing GFPGAN link to Automatic1111 packages
### 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)
- Fixed extension modification dialog not showing any progress messages
## v2.8.1
### Fixed
- Fixed model links not working in RuinedFooocus for new installations

8
StabilityMatrix.Avalonia/Controls/Inference/SamplerCard.axaml

@ -123,7 +123,13 @@
<StackPanel>
<!-- Denoise Strength -->
<StackPanel IsVisible="{Binding IsDenoiseStrengthEnabled}">
<StackPanel>
<StackPanel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="IsDenoiseStrengthEnabled"/>
<Binding Path="IsDenoiseStrengthTempEnabled"/>
</MultiBinding>
</StackPanel.IsVisible>
<Grid ColumnDefinitions="*,Auto">
<TextBlock
VerticalAlignment="Center"

77
StabilityMatrix.Avalonia/Services/InferenceClientManager.cs

@ -56,7 +56,8 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
private readonly SourceCache<HybridModelFile, string> modelsSource = new(p => p.GetId());
public IObservableCollection<HybridModelFile> Models { get; } = new ObservableCollectionExtended<HybridModelFile>();
public IObservableCollection<HybridModelFile> Models { get; } =
new ObservableCollectionExtended<HybridModelFile>();
private readonly SourceCache<HybridModelFile, string> vaeModelsSource = new(p => p.GetId());
@ -67,14 +68,16 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
private readonly SourceCache<HybridModelFile, string> controlNetModelsSource = new(p => p.GetId());
private readonly SourceCache<HybridModelFile, string> downloadableControlNetModelsSource = new(p => p.GetId());
private readonly SourceCache<HybridModelFile, string> downloadableControlNetModelsSource =
new(p => p.GetId());
public IObservableCollection<HybridModelFile> ControlNetModels { get; } =
new ObservableCollectionExtended<HybridModelFile>();
private readonly SourceCache<ComfySampler, string> samplersSource = new(p => p.Name);
public IObservableCollection<ComfySampler> Samplers { get; } = new ObservableCollectionExtended<ComfySampler>();
public IObservableCollection<ComfySampler> Samplers { get; } =
new ObservableCollectionExtended<ComfySampler>();
private readonly SourceCache<ComfyUpscaler, string> modelUpscalersSource = new(p => p.Name);
@ -82,7 +85,8 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
private readonly SourceCache<ComfyUpscaler, string> downloadableUpscalersSource = new(p => p.Name);
public IObservableCollection<ComfyUpscaler> Upscalers { get; } = new ObservableCollectionExtended<ComfyUpscaler>();
public IObservableCollection<ComfyUpscaler> Upscalers { get; } =
new ObservableCollectionExtended<ComfyUpscaler>();
private readonly SourceCache<ComfyScheduler, string> 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<HybridModelFile>.Ascending(f => f.Type).ThenByAscending(f => f.ShortDisplayName)
SortExpressionComparer<HybridModelFile>
.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
}
/// <inheritdoc />
public async Task WriteImageToInputAsync(ImageSource imageSource, CancellationToken cancellationToken = default)
public async Task WriteImageToInputAsync(
ImageSource imageSource,
CancellationToken cancellationToken = default
)
{
if (!IsConnected)
return;

2
StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj

@ -17,7 +17,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<ApplicationIcon>./Assets/Icon.ico</ApplicationIcon>
<Version>2.8.0-dev.999</Version>
<Version>2.9.0-dev.999</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

44
StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs

@ -8,6 +8,7 @@ using CommunityToolkit.Mvvm.Input;
using DynamicData;
using DynamicData.Binding;
using Microsoft.Extensions.Logging;
using Refit;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Api;
@ -86,21 +87,34 @@ public partial class RecommendedModelsViewModel : ContentDialogViewModelBase
IsLoading = true;
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
}
)
);
try
{
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
}
)
);
}
catch (ApiException e)
{
// hide dialog and show error msg
logger.LogError(e, "Failed to get recommended models");
notificationService.Show(
"Failed to get recommended models",
"Please try again later or check the Model Browser tab for more models."
);
OnCloseButtonClick();
}
IsLoading = false;
}

8
StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs

@ -114,14 +114,6 @@ public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, I
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;
});
}
/// <inheritdoc />

28
StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs

@ -42,6 +42,12 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo
[ObservableProperty]
private bool isDenoiseStrengthEnabled;
/// <summary>
/// Temporary enable for denoise strength, used for SDTurbo.
/// Denoise will be enabled if either this or <see cref="IsDenoiseStrengthEnabled"/> is true.
/// </summary>
public bool IsDenoiseStrengthTempEnabled => SelectedScheduler == ComfyScheduler.SDTurbo;
[ObservableProperty]
private double denoiseStrength = 0.7f;
@ -77,6 +83,7 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo
private bool isSchedulerSelectionEnabled;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsDenoiseStrengthTempEnabled))]
[Required]
private ComfyScheduler? selectedScheduler = ComfyScheduler.Normal;
@ -154,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)
{
@ -189,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
@ -218,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,
}
@ -229,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
@ -244,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,
@ -265,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,

21
StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs

@ -179,7 +179,12 @@ public partial class PackageExtensionBrowserViewModel : ViewModelBase, IDisposab
.Cast<IPackageStep>()
.ToArray();
var runner = new PackageModificationRunner { ShowDialogOnStart = true };
var runner = new PackageModificationRunner
{
ShowDialogOnStart = true,
ModificationCompleteTitle = "Installed Extensions",
ModificationCompleteMessage = "Finished installing extensions"
};
EventManager.Instance.OnPackageInstallProgressAdded(runner);
await runner.ExecuteSteps(steps);
@ -209,7 +214,12 @@ public partial class PackageExtensionBrowserViewModel : ViewModelBase, IDisposab
.Cast<IPackageStep>()
.ToArray();
var runner = new PackageModificationRunner { ShowDialogOnStart = true };
var runner = new PackageModificationRunner
{
ShowDialogOnStart = true,
ModificationCompleteTitle = "Updated Extensions",
ModificationCompleteMessage = "Finished updating extensions"
};
EventManager.Instance.OnPackageInstallProgressAdded(runner);
await runner.ExecuteSteps(steps);
@ -239,7 +249,12 @@ public partial class PackageExtensionBrowserViewModel : ViewModelBase, IDisposab
.Cast<IPackageStep>()
.ToArray();
var runner = new PackageModificationRunner { ShowDialogOnStart = true };
var runner = new PackageModificationRunner
{
ShowDialogOnStart = true,
ModificationCompleteTitle = "Uninstalled Extensions",
ModificationCompleteMessage = "Finished uninstalling extensions"
};
EventManager.Instance.OnPackageInstallProgressAdded(runner);
await runner.ExecuteSteps(steps);

5
StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs

@ -15,6 +15,11 @@ public class PackageModificationRunner : IPackageModificationRunner
ConsoleOutput.Add(report.Message);
}
if (!string.IsNullOrWhiteSpace(report.Title))
{
ConsoleOutput.Add(report.Title);
}
OnProgressChanged(report);
});

1
StabilityMatrix.Core/Models/Packages/A3WebUI.cs

@ -48,6 +48,7 @@ public class A3WebUI(
{
[SharedFolderType.StableDiffusion] = new[] { "models/Stable-diffusion" },
[SharedFolderType.ESRGAN] = new[] { "models/ESRGAN" },
[SharedFolderType.GFPGAN] = new[] { "models/GFPGAN" },
[SharedFolderType.RealESRGAN] = new[] { "models/RealESRGAN" },
[SharedFolderType.SwinIR] = new[] { "models/SwinIR" },
[SharedFolderType.Lora] = new[] { "models/Lora" },

16
StabilityMatrix.Core/Models/Packages/Extensions/GitPackageExtensionManager.cs

@ -155,13 +155,15 @@ public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisit
{
cancellationToken.ThrowIfCancellationRequested();
progress?.Report(new ProgressReport(0f, $"Cloning {repositoryUri}", isIndeterminate: true));
progress?.Report(
new ProgressReport(0f, message: $"Cloning {repositoryUri}", isIndeterminate: true)
);
await prerequisiteHelper
.CloneGitRepository(cloneRoot, repositoryUri.ToString(), version)
.ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, $"Cloned {repositoryUri}"));
progress?.Report(new ProgressReport(1f, message: $"Cloned {repositoryUri}"));
}
}
@ -191,7 +193,11 @@ public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisit
.ConfigureAwait(false);
progress?.Report(
new ProgressReport(0f, $"Updating git repository {repoPath.Name}", isIndeterminate: true)
new ProgressReport(
0f,
message: $"Updating git repository {repoPath.Name}",
isIndeterminate: true
)
);
// If version not provided, use current branch
@ -206,7 +212,7 @@ public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisit
.UpdateGitRepository(repoPath, remoteUrlResult.StandardOutput!.Trim(), version)
.ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, $"Updated git repository {repoPath.Name}"));
progress?.Report(new ProgressReport(1f, message: $"Updated git repository {repoPath.Name}"));
}
}
@ -233,5 +239,7 @@ public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisit
await path.DeleteAsync().ConfigureAwait(false);
}
}
progress?.Report(new ProgressReport(1f, message: "Uninstalled extension"));
}
}

Loading…
Cancel
Save