Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.4.4 Update #135

Merged
merged 12 commits into from
Sep 18, 2023
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -5,6 +5,14 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).

## v2.4.4
### Added
- Added button to toggle automatic scrolling of console output
### Fixed
- Fixed [#130](https://github.com/LykosAI/StabilityMatrix/issues/130) ComfyUI extra_model_paths.yaml file being overwritten on each launch
- Fixed some package updates not showing any console output
- Fixed auto-close of update dialog when package update is complete

## v2.4.3
### Added
- Added "--no-download-sd-model" launch argument option for Stable Diffusion Web UI
9 changes: 9 additions & 0 deletions StabilityMatrix.Avalonia/Languages/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions StabilityMatrix.Avalonia/Languages/Resources.resx
Original file line number Diff line number Diff line change
@@ -639,4 +639,7 @@
<data name="Label_Branch" xml:space="preserve">
<value>Branch</value>
</data>
<data name="Label_AutoScrollToEnd" xml:space="preserve">
<value>Automatically scroll to end of console output</value>
</data>
</root>
24 changes: 23 additions & 1 deletion StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs
Original file line number Diff line number Diff line change
@@ -86,6 +86,9 @@ public partial class LaunchPageViewModel : PageViewModelBase, IDisposable, IAsyn
[ObservableProperty]
private BasePackage? runningPackage;

[ObservableProperty]
private bool autoScrollToEnd;

public virtual BasePackage? SelectedBasePackage =>
PackageFactory.FindPackageByName(SelectedPackage?.PackageName);

@@ -126,6 +129,12 @@ ServiceManager<ViewModelBase> dialogFactory
settings => settings.ActiveInstalledPackage
);

settingsManager.RelayPropertyFor(
this,
vm => vm.AutoScrollToEnd,
settings => settings.AutoScrollLaunchConsoleToEnd
);

EventManager.Instance.PackageLaunchRequested += OnPackageLaunchRequested;
EventManager.Instance.OneClickInstallFinished += OnOneClickInstallFinished;
EventManager.Instance.InstalledPackagesChanged += OnInstalledPackagesChanged;
@@ -161,6 +170,14 @@ private void OnPackageLaunchRequested(object? sender, Guid e)
LaunchAsync().SafeFireAndForget();
}

partial void OnAutoScrollToEndChanged(bool value)
{
if (value)
{
EventManager.Instance.OnScrollToBottomRequested();
}
}

public override void OnLoaded()
{
// Ensure active package either exists or is null
@@ -179,6 +196,7 @@ public override void OnLoaded()

// Load active package
SelectedPackage = settingsManager.Settings.ActiveInstalledPackage;
AutoScrollToEnd = settingsManager.Settings.AutoScrollLaunchConsoleToEnd;
}

[RelayCommand]
@@ -487,7 +505,11 @@ private void OnProcessExited(object? sender, int exitCode)
private void OnProcessOutputReceived(ProcessOutput output)
{
Console.Post(output);
EventManager.Instance.OnScrollToBottomRequested();

if (AutoScrollToEnd)
{
EventManager.Instance.OnScrollToBottomRequested();
}
}

private void OnOneClickInstallFinished(object? sender, bool e)
16 changes: 10 additions & 6 deletions StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
Original file line number Diff line number Diff line change
@@ -143,12 +143,16 @@ public async Task ShowInstallDialog()

EventManager.Instance.OnPackageInstallProgressAdded(runner);
await runner.ExecuteSteps(steps.ToList());
EventManager.Instance.OnInstalledPackagesChanged();
notificationService.Show(
"Package Install Complete",
$"{viewModel.InstallName} installed successfully",
NotificationType.Success
);

if (!runner.Failed)
{
EventManager.Instance.OnInstalledPackagesChanged();
notificationService.Show(
"Package Install Complete",
$"{viewModel.InstallName} installed successfully",
NotificationType.Success
);
}
}
}

Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ private void PackageModificationRunnerOnProgressChanged(object? sender, Progress
Progress.IsIndeterminate = e.IsIndeterminate;
Progress.Text = packageModificationRunner.CurrentStep?.ProgressTitle;
Name = packageModificationRunner.CurrentStep?.ProgressTitle;
Failed = packageModificationRunner.Failed;

if (string.IsNullOrWhiteSpace(e.Message) || e.Message.Contains("Downloading..."))
return;
@@ -51,12 +52,20 @@ private void PackageModificationRunnerOnProgressChanged(object? sender, Progress

if (
e is { Message: not null, Percentage: >= 100 }
&& e.Message.Contains("Package Install Complete")
&& e.Message.Contains(
packageModificationRunner.ModificationCompleteMessage ?? "Package Install Complete"
)
&& Progress.CloseWhenFinished
)
{
Dispatcher.UIThread.Post(() => dialog?.Hide());
}

if (Failed)
{
Progress.Text = "Package Modification Failed";
Name = "Package Modification Failed";
}
}

public async Task ShowProgressDialog()
15 changes: 14 additions & 1 deletion StabilityMatrix.Avalonia/Views/LaunchPageView.axaml
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
d:DataContext="{x:Static mocks:DesignData.LaunchPageViewModel}"
d:DesignHeight="450"
d:DesignWidth="700"
@@ -25,7 +26,7 @@
</controls:UserControlBase.Resources>

<Grid RowDefinitions="Auto,*,Auto">
<Grid ColumnDefinitions="Auto,*,Auto"
<Grid ColumnDefinitions="Auto,*,Auto,Auto"
Margin="0,8,0, 8">
<Grid ColumnDefinitions="0.8*,0.2*" Margin="16,8,0,0">
<!-- Use split if extra commands, otherwise normal launch button -->
@@ -145,6 +146,18 @@
<ToggleButton
Grid.Column="2"
Width="48"
Margin="8,8,0,0"
IsChecked="{Binding AutoScrollToEnd}"
ToolTip.Tip="{x:Static lang:Resources.Label_AutoScrollToEnd}"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
FontSize="16">
<avalonia:Icon Value="fa-solid fa-arrow-down-wide-short" />
</ToggleButton>

<ToggleButton
Grid.Column="3"
Width="48"
Margin="8,8,16,0"
IsChecked="{Binding ShowManualInputPrompt}"
ToolTip.Tip="{x:Static lang:Resources.Action_SendInput}"
Original file line number Diff line number Diff line change
@@ -12,4 +12,6 @@ public interface IPackageModificationRunner
List<string> ConsoleOutput { get; }
Guid Id { get; }
bool ShowDialogOnStart { get; init; }
string? ModificationCompleteMessage { get; init; }
bool Failed { get; set; }
}
Original file line number Diff line number Diff line change
@@ -21,16 +21,35 @@ public async Task ExecuteSteps(IReadOnlyList<IPackageStep> steps)
foreach (var step in steps)
{
CurrentStep = step;
await step.ExecuteAsync(progress).ConfigureAwait(false);
try
{
await step.ExecuteAsync(progress).ConfigureAwait(false);
}
catch (Exception e)
{
progress.Report(
new ProgressReport(
1f,
title: "Error modifying package",
message: $"Error: {e}",
isIndeterminate: false
)
);
Failed = true;
break;
}
}

progress.Report(
new ProgressReport(
1f,
message: ModificationCompleteMessage ?? "Package Install Complete",
isIndeterminate: false
)
);
if (!Failed)
{
progress.Report(
new ProgressReport(
1f,
message: ModificationCompleteMessage ?? "Package Install Complete",
isIndeterminate: false
)
);
}

IsRunning = false;
}
@@ -39,6 +58,7 @@ public async Task ExecuteSteps(IReadOnlyList<IPackageStep> steps)
public bool ShowDialogOnStart { get; init; }

public bool IsRunning { get; set; }
public bool Failed { get; set; }
public ProgressReport CurrentProgress { get; set; }
public IPackageStep? CurrentStep { get; set; }
public List<string> ConsoleOutput { get; } = new();
4 changes: 2 additions & 2 deletions StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
Original file line number Diff line number Diff line change
@@ -290,7 +290,7 @@ await DownloadPackage(
)
.ConfigureAwait(false);

await InstallPackage(installedPackage.FullPath, torchVersion, progress)
await InstallPackage(installedPackage.FullPath, torchVersion, progress, onConsoleOutput)
.ConfigureAwait(false);

return new InstalledPackageVersion { InstalledReleaseVersion = latestRelease.TagName };
@@ -312,7 +312,7 @@ await DownloadPackage(
progress
)
.ConfigureAwait(false);
await InstallPackage(installedPackage.FullPath, torchVersion, progress)
await InstallPackage(installedPackage.FullPath, torchVersion, progress, onConsoleOutput)
.ConfigureAwait(false);

return new InstalledPackageVersion
108 changes: 79 additions & 29 deletions StabilityMatrix.Core/Models/Packages/ComfyUI.cs
Original file line number Diff line number Diff line change
@@ -9,8 +9,10 @@
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python;
using StabilityMatrix.Core.Services;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.TypeInspectors;

namespace StabilityMatrix.Core.Models.Packages;

@@ -233,46 +235,94 @@ SharedFolderMethod sharedFolderMethod
var extraPathsYamlPath = installDirectory + "extra_model_paths.yaml";
var modelsDir = SettingsManager.ModelsDirectory;

var deserializer = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();

var exists = File.Exists(extraPathsYamlPath);
if (!exists)
{
Logger.Info("Creating extra_model_paths.yaml");
File.WriteAllText(extraPathsYamlPath, string.Empty);
}
var yaml = File.ReadAllText(extraPathsYamlPath);
var comfyModelPaths =
deserializer.Deserialize<ComfyModelPathsYaml>(yaml)
??
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
// cuz it can actually be null lol
new ComfyModelPathsYaml();

comfyModelPaths.StabilityMatrix ??= new ComfyModelPathsYaml.SmData();
comfyModelPaths.StabilityMatrix.Checkpoints = Path.Combine(modelsDir, "StableDiffusion");
comfyModelPaths.StabilityMatrix.Vae = Path.Combine(modelsDir, "VAE");
comfyModelPaths.StabilityMatrix.Loras =
$"{Path.Combine(modelsDir, "Lora")}\n" + $"{Path.Combine(modelsDir, "LyCORIS")}";
comfyModelPaths.StabilityMatrix.UpscaleModels =
$"{Path.Combine(modelsDir, "ESRGAN")}\n"
+ $"{Path.Combine(modelsDir, "RealESRGAN")}\n"
+ $"{Path.Combine(modelsDir, "SwinIR")}";
comfyModelPaths.StabilityMatrix.Embeddings = Path.Combine(modelsDir, "TextualInversion");
comfyModelPaths.StabilityMatrix.Hypernetworks = Path.Combine(modelsDir, "Hypernetwork");
comfyModelPaths.StabilityMatrix.Controlnet = Path.Combine(modelsDir, "ControlNet");
comfyModelPaths.StabilityMatrix.Clip = Path.Combine(modelsDir, "CLIP");
comfyModelPaths.StabilityMatrix.Diffusers = Path.Combine(modelsDir, "Diffusers");
comfyModelPaths.StabilityMatrix.Gligen = Path.Combine(modelsDir, "GLIGEN");
comfyModelPaths.StabilityMatrix.VaeApprox = Path.Combine(modelsDir, "ApproxVAE");
using var sr = new StringReader(yaml);
var yamlStream = new YamlStream();
yamlStream.Load(sr);

if (!yamlStream.Documents.Any())
{
yamlStream.Documents.Add(new YamlDocument(new YamlMappingNode()));
}

var root = yamlStream.Documents[0].RootNode;
if (root is not YamlMappingNode mappingNode)
{
throw new Exception("Invalid extra_model_paths.yaml");
}
// check if we have a child called "stability_matrix"
var stabilityMatrixNode = mappingNode.Children.FirstOrDefault(
c => c.Key.ToString() == "stability_matrix"
);

if (stabilityMatrixNode.Key != null)
{
if (stabilityMatrixNode.Value is not YamlMappingNode nodeValue)
return Task.CompletedTask;

nodeValue.Children["checkpoints"] = Path.Combine(modelsDir, "StableDiffusion");
nodeValue.Children["vae"] = Path.Combine(modelsDir, "VAE");
nodeValue.Children["loras"] =
$"{Path.Combine(modelsDir, "Lora")}\n" + $"{Path.Combine(modelsDir, "LyCORIS")}";
nodeValue.Children["upscale_models"] =
$"{Path.Combine(modelsDir, "ESRGAN")}\n"
+ $"{Path.Combine(modelsDir, "RealESRGAN")}\n"
+ $"{Path.Combine(modelsDir, "SwinIR")}";
nodeValue.Children["embeddings"] = Path.Combine(modelsDir, "TextualInversion");
nodeValue.Children["hypernetworks"] = Path.Combine(modelsDir, "Hypernetwork");
nodeValue.Children["controlnet"] = Path.Combine(modelsDir, "ControlNet");
nodeValue.Children["clip"] = Path.Combine(modelsDir, "CLIP");
nodeValue.Children["diffusers"] = Path.Combine(modelsDir, "Diffusers");
nodeValue.Children["gligen"] = Path.Combine(modelsDir, "GLIGEN");
nodeValue.Children["vae_approx"] = Path.Combine(modelsDir, "ApproxVAE");
}
else
{
stabilityMatrixNode = new KeyValuePair<YamlNode, YamlNode>(
new YamlScalarNode("stability_matrix"),
new YamlMappingNode
{
{ "checkpoints", Path.Combine(modelsDir, "StableDiffusion") },
{ "vae", Path.Combine(modelsDir, "VAE") },
{
"loras",
$"{Path.Combine(modelsDir, "Lora")}\n{Path.Combine(modelsDir, "LyCORIS")}"
},
{
"upscale_models",
$"{Path.Combine(modelsDir, "ESRGAN")}\n{Path.Combine(modelsDir, "RealESRGAN")}\n{Path.Combine(modelsDir, "SwinIR")}"
},
{ "embeddings", Path.Combine(modelsDir, "TextualInversion") },
{ "hypernetworks", Path.Combine(modelsDir, "Hypernetwork") },
{ "controlnet", Path.Combine(modelsDir, "ControlNet") },
{ "clip", Path.Combine(modelsDir, "CLIP") },
{ "diffusers", Path.Combine(modelsDir, "Diffusers") },
{ "gligen", Path.Combine(modelsDir, "GLIGEN") },
{ "vae_approx", Path.Combine(modelsDir, "ApproxVAE") }
}
);
}

var newRootNode = new YamlMappingNode();
foreach (
var child in mappingNode.Children.Where(c => c.Key.ToString() != "stability_matrix")
)
{
newRootNode.Children.Add(child);
}

newRootNode.Children.Add(stabilityMatrixNode);

var serializer = new SerializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.Build();
var yamlData = serializer.Serialize(comfyModelPaths);
var yamlData = serializer.Serialize(newRootNode);
File.WriteAllText(extraPathsYamlPath, yamlData);

return Task.CompletedTask;
Loading