From 3ead16a139fc94463c358fdac0df8bfdba1f3dcb Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 14 Dec 2023 15:56:32 -0500 Subject: [PATCH 01/21] Add T2IAdapter path for comfy config link --- .../Models/Packages/ComfyUI.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 33888809..ac58db1f 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -10,6 +10,7 @@ using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; +using YamlDotNet.Core; using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -319,7 +320,11 @@ public class ComfyUI( + $"{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["controlnet"] = string.Join( + '\n', + Path.Combine(modelsDir, "ControlNet"), + Path.Combine(modelsDir, "T2IAdapter") + ); nodeValue.Children["clip"] = Path.Combine(modelsDir, "CLIP"); nodeValue.Children["diffusers"] = Path.Combine(modelsDir, "Diffusers"); nodeValue.Children["gligen"] = Path.Combine(modelsDir, "GLIGEN"); @@ -340,7 +345,10 @@ public class ComfyUI( }, { "embeddings", Path.Combine(modelsDir, "TextualInversion") }, { "hypernetworks", Path.Combine(modelsDir, "Hypernetwork") }, - { "controlnet", Path.Combine(modelsDir, "ControlNet") }, + { + "controlnet", + string.Join('\n', Path.Combine(modelsDir, "ControlNet"), Path.Combine(modelsDir, "T2IAdapter")) + }, { "clip", Path.Combine(modelsDir, "CLIP") }, { "diffusers", Path.Combine(modelsDir, "Diffusers") }, { "gligen", Path.Combine(modelsDir, "GLIGEN") }, @@ -357,7 +365,11 @@ public class ComfyUI( newRootNode.Children.Add(stabilityMatrixNode); - var serializer = new SerializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build(); + var serializer = new SerializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .WithDefaultScalarStyle(ScalarStyle.Literal) + .Build(); + var yamlData = serializer.Serialize(newRootNode); File.WriteAllText(extraPathsYamlPath, yamlData); From 6d9209e1b72c4f9a9c97910591fc5df2c49a4505 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 14 Dec 2023 16:52:14 -0500 Subject: [PATCH 02/21] Impl IFormattable for FileSystemPath for logging --- .../Models/FileInterfaces/FileSystemPath.cs | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs b/StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs index e9d22fa2..8fc04491 100644 --- a/StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs +++ b/StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs @@ -1,6 +1,6 @@ namespace StabilityMatrix.Core.Models.FileInterfaces; -public class FileSystemPath : IEquatable, IEquatable +public class FileSystemPath : IEquatable, IEquatable, IFormattable { public string FullPath { get; } @@ -8,27 +8,42 @@ public class FileSystemPath : IEquatable, IEquatable { FullPath = path; } - - protected FileSystemPath(FileSystemPath path) : this(path.FullPath) + + protected FileSystemPath(FileSystemPath path) + : this(path.FullPath) { } + + protected FileSystemPath(params string[] paths) + : this(Path.Combine(paths)) { } + + public override string ToString() { + return FullPath; } - protected FileSystemPath(params string[] paths) : this(Path.Combine(paths)) + /// + string IFormattable.ToString(string? format, IFormatProvider? formatProvider) { + return ToString(format, formatProvider); } - - public override string ToString() + + /// + /// Overridable IFormattable.ToString method. + /// By default, returns . + /// + protected virtual string ToString(string? format, IFormatProvider? formatProvider) { return FullPath; } public bool Equals(FileSystemPath? other) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; return FullPath == other.FullPath; } - + public bool Equals(string? other) { return string.Equals(FullPath, other); @@ -48,8 +63,9 @@ public class FileSystemPath : IEquatable, IEquatable { return FullPath.GetHashCode(); } - + // Implicit conversions to and from string public static implicit operator string(FileSystemPath path) => path.FullPath; + public static implicit operator FileSystemPath(string path) => new(path); } From 188d8abc3488f76e6cf80265db310fbdd3cdecd4 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 14 Dec 2023 16:54:45 -0500 Subject: [PATCH 03/21] Change T2IAdapter to subfolders and add migration --- .../Models/Packages/A3WebUI.cs | 23 ++++- .../Models/Packages/ComfyUI.cs | 98 ++++++++++--------- 2 files changed, 73 insertions(+), 48 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index d653da77..5a8062cf 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -56,11 +56,11 @@ public class A3WebUI( [SharedFolderType.Karlo] = new[] { "models/karlo" }, [SharedFolderType.TextualInversion] = new[] { "embeddings" }, [SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" }, - [SharedFolderType.ControlNet] = new[] { "models/ControlNet" }, + [SharedFolderType.ControlNet] = new[] { "models/controlnet/ControlNet" }, [SharedFolderType.Codeformer] = new[] { "models/Codeformer" }, [SharedFolderType.LDSR] = new[] { "models/LDSR" }, [SharedFolderType.AfterDetailer] = new[] { "models/adetailer" }, - [SharedFolderType.T2IAdapter] = new[] { "models/controlnet" }, + [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, [SharedFolderType.IpAdapter] = new[] { "models/ipadapter" } }; @@ -278,4 +278,23 @@ public class A3WebUI( ) .ConfigureAwait(false); } + + /// + public override async Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) + { + // Migration for `controlnet` -> `controlnet/ControlNet` and `controlnet/T2IAdapter` + // If the original link exists, delete it first + if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) + { + Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); + await controlnetOldLink.DeleteAsync(true).ConfigureAwait(false); + } + + // Resume base setup + await base.SetupModelFolders(installDirectory, sharedFolderMethod).ConfigureAwait(false); + } + + /// + public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => + SetupModelFolders(installDirectory, sharedFolderMethod); } diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index ac58db1f..8901d191 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -54,12 +54,12 @@ public class ComfyUI( [SharedFolderType.TextualInversion] = new[] { "models/embeddings" }, [SharedFolderType.VAE] = new[] { "models/vae" }, [SharedFolderType.ApproxVAE] = new[] { "models/vae_approx" }, - [SharedFolderType.ControlNet] = new[] { "models/controlnet" }, + [SharedFolderType.ControlNet] = new[] { "models/controlnet/ControlNet" }, [SharedFolderType.GLIGEN] = new[] { "models/gligen" }, [SharedFolderType.ESRGAN] = new[] { "models/upscale_models" }, [SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" }, [SharedFolderType.IpAdapter] = new[] { "models/ipadapter" }, - [SharedFolderType.T2IAdapter] = new[] { "models/controlnet" }, + [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, }; public override Dictionary>? SharedOutputFolders => @@ -268,26 +268,55 @@ public class ComfyUI( } } - public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) + public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => + sharedFolderMethod switch + { + SharedFolderMethod.Symlink => SetupModelFoldersSymlink(installDirectory), + SharedFolderMethod.Configuration => SetupModelFoldersConfig(installDirectory), + SharedFolderMethod.None => Task.CompletedTask, + _ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null) + }; + + public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => + SetupModelFolders(installDirectory, sharedFolderMethod); + + public override Task RemoveModelFolderLinks(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) { - switch (sharedFolderMethod) + return sharedFolderMethod switch { - case SharedFolderMethod.None: - return Task.CompletedTask; - case SharedFolderMethod.Symlink: - return base.SetupModelFolders(installDirectory, sharedFolderMethod); + SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory, sharedFolderMethod), + SharedFolderMethod.Configuration => RemoveConfigSection(installDirectory), + SharedFolderMethod.None => Task.CompletedTask, + _ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null) + }; + } + + private async Task SetupModelFoldersSymlink(DirectoryPath installDirectory) + { + // Migration for `controlnet` -> `controlnet/ControlNet` and `controlnet/T2IAdapter` + // If the original link exists, delete it first + if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) + { + Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); + await controlnetOldLink.DeleteAsync(true).ConfigureAwait(false); } - var extraPathsYamlPath = installDirectory + "extra_model_paths.yaml"; + // Resume base setup + await base.SetupModelFolders(installDirectory, SharedFolderMethod.Symlink).ConfigureAwait(false); + } + + private async Task SetupModelFoldersConfig(DirectoryPath installDirectory) + { + var extraPathsYamlPath = installDirectory.JoinFile("extra_model_paths.yaml"); var modelsDir = SettingsManager.ModelsDirectory; - var exists = File.Exists(extraPathsYamlPath); - if (!exists) + if (!extraPathsYamlPath.Exists) { Logger.Info("Creating extra_model_paths.yaml"); - File.WriteAllText(extraPathsYamlPath, string.Empty); + extraPathsYamlPath.Create(); } - var yaml = File.ReadAllText(extraPathsYamlPath); + + var yaml = await extraPathsYamlPath.ReadAllTextAsync().ConfigureAwait(false); using var sr = new StringReader(yaml); var yamlStream = new YamlStream(); yamlStream.Load(sr); @@ -308,7 +337,7 @@ public class ComfyUI( if (stabilityMatrixNode.Key != null) { if (stabilityMatrixNode.Value is not YamlMappingNode nodeValue) - return Task.CompletedTask; + return; nodeValue.Children["checkpoints"] = Path.Combine(modelsDir, "StableDiffusion"); nodeValue.Children["vae"] = Path.Combine(modelsDir, "VAE"); @@ -371,63 +400,40 @@ public class ComfyUI( .Build(); var yamlData = serializer.Serialize(newRootNode); - File.WriteAllText(extraPathsYamlPath, yamlData); - - return Task.CompletedTask; + await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false); } - public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => - sharedFolderMethod switch - { - SharedFolderMethod.Symlink => base.UpdateModelFolders(installDirectory, sharedFolderMethod), - SharedFolderMethod.Configuration => SetupModelFolders(installDirectory, sharedFolderMethod), - SharedFolderMethod.None => Task.CompletedTask, - _ => Task.CompletedTask - }; - - public override Task RemoveModelFolderLinks(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) + private static async Task RemoveConfigSection(DirectoryPath installDirectory) { - return sharedFolderMethod switch - { - SharedFolderMethod.Configuration => RemoveConfigSection(installDirectory), - SharedFolderMethod.None => Task.CompletedTask, - SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory, sharedFolderMethod), - _ => Task.CompletedTask - }; - } + var extraPathsYamlPath = installDirectory.JoinFile("extra_model_paths.yaml"); - private Task RemoveConfigSection(string installDirectory) - { - var extraPathsYamlPath = Path.Combine(installDirectory, "extra_model_paths.yaml"); - var exists = File.Exists(extraPathsYamlPath); - if (!exists) + if (!extraPathsYamlPath.Exists) { - return Task.CompletedTask; + return; } - var yaml = File.ReadAllText(extraPathsYamlPath); + var yaml = await extraPathsYamlPath.ReadAllTextAsync().ConfigureAwait(false); using var sr = new StringReader(yaml); var yamlStream = new YamlStream(); yamlStream.Load(sr); if (!yamlStream.Documents.Any()) { - return Task.CompletedTask; + return; } var root = yamlStream.Documents[0].RootNode; if (root is not YamlMappingNode mappingNode) { - return Task.CompletedTask; + return; } mappingNode.Children.Remove("stability_matrix"); var serializer = new SerializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build(); var yamlData = serializer.Serialize(mappingNode); - File.WriteAllText(extraPathsYamlPath, yamlData); - return Task.CompletedTask; + await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false); } private async Task InstallRocmTorch( From d17648e02aa39fd54dd41a36bf523d1a37074ef8 Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 14 Dec 2023 17:00:02 -0500 Subject: [PATCH 04/21] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ce75e9e..e9e283cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.7.2 +### Changed +- Changed Symlink shared folder link targets for Automatic1111 and ComfyUI. From `ControlNet -> models/controlnet` to `ControlNet -> models/controlnet/ControlNet` and `T2IAdapter -> models/controlnet/T2IAdapter`. +### Fixed +- Fixed ControlNet / T2IAdapter shared folder links for Automatic1111 conflicting with each other + ## v2.7.1 ### Added - Added Turkish UI language option, thanks to Progresor for the translation From 4ba8c0290b8ea3e8826f6344f38d7ad942547bdc Mon Sep 17 00:00:00 2001 From: Ionite Date: Thu, 14 Dec 2023 17:02:25 -0500 Subject: [PATCH 05/21] Add recursive false for safety --- StabilityMatrix.Core/Models/Packages/A3WebUI.cs | 2 +- StabilityMatrix.Core/Models/Packages/ComfyUI.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 5a8062cf..c790e49b 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -287,7 +287,7 @@ public class A3WebUI( if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) { Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); - await controlnetOldLink.DeleteAsync(true).ConfigureAwait(false); + await controlnetOldLink.DeleteAsync(false).ConfigureAwait(false); } // Resume base setup diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 8901d191..daa586cd 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -298,7 +298,7 @@ public class ComfyUI( if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) { Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); - await controlnetOldLink.DeleteAsync(true).ConfigureAwait(false); + await controlnetOldLink.DeleteAsync(false).ConfigureAwait(false); } // Resume base setup From 7a08f79e7151e68aa4d57b45ea6ba503b02f2485 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 01:46:30 -0500 Subject: [PATCH 06/21] Fix IpAdapter to controlnet sub folder --- StabilityMatrix.Core/Models/Packages/A3WebUI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index c790e49b..1954fbfb 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -61,7 +61,7 @@ public class A3WebUI( [SharedFolderType.LDSR] = new[] { "models/LDSR" }, [SharedFolderType.AfterDetailer] = new[] { "models/adetailer" }, [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, - [SharedFolderType.IpAdapter] = new[] { "models/ipadapter" } + [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" } }; public override Dictionary>? SharedOutputFolders => From 26b2982b21cf7c20363bfd2686decfe88108f668 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 04:09:48 -0500 Subject: [PATCH 07/21] Fix uri handler registration linux --- CHANGELOG.md | 1 + .../Helpers/UriHandler.cs | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e283cd..81608f40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Changed Symlink shared folder link targets for Automatic1111 and ComfyUI. From `ControlNet -> models/controlnet` to `ControlNet -> models/controlnet/ControlNet` and `T2IAdapter -> models/controlnet/T2IAdapter`. ### Fixed - Fixed ControlNet / T2IAdapter shared folder links for Automatic1111 conflicting with each other +- Fixes URIScheme registration errors on Linux ## v2.7.1 ### Added diff --git a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs index e500a1e4..75dd4a5f 100644 --- a/StabilityMatrix.Avalonia/Helpers/UriHandler.cs +++ b/StabilityMatrix.Avalonia/Helpers/UriHandler.cs @@ -56,8 +56,6 @@ public class UriHandler Environment.Exit(0); } - public void Callback() { } - public void RegisterUriScheme() { if (Compat.IsWindows) @@ -66,7 +64,17 @@ public class UriHandler } else { - RegisterUriSchemeUnix(); + // Try to register on unix but ignore errors + // Library does not support some distros + try + { + RegisterUriSchemeUnix(); + } + catch (Exception e) + { + Debug.WriteLine(e); + Console.WriteLine(e); + } } } @@ -92,11 +100,7 @@ public class UriHandler private void RegisterUriSchemeUnix() { - var service = URISchemeServiceFactory.GetURISchemeSerivce( - Scheme, - Description, - Compat.AppCurrentPath.FullPath - ); + var service = URISchemeServiceFactory.GetURISchemeSerivce(Scheme, Description, Compat.AppCurrentPath.FullPath); service.Set(); } } From cadc9a10a42f0ea365f266938884f79c695116ca Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 16:38:00 -0500 Subject: [PATCH 08/21] Switch to immutable collections in ProcessArgsBuilder --- .../Processes/ProcessArgsBuilder.cs | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs b/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs index 00a0e812..e1e9ffc5 100644 --- a/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs +++ b/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs @@ -1,6 +1,5 @@ -using System.Diagnostics; +using System.Collections.Immutable; using System.Diagnostics.Contracts; -using OneOf; namespace StabilityMatrix.Core.Processes; @@ -9,14 +8,7 @@ namespace StabilityMatrix.Core.Processes; /// public record ProcessArgsBuilder { - protected ProcessArgsBuilder() { } - - public ProcessArgsBuilder(params Argument[] arguments) - { - Arguments = arguments.ToList(); - } - - public List Arguments { get; init; } = new(); + public IImmutableList Arguments { get; init; } = ImmutableArray.Empty; private IEnumerable ToStringArgs() { @@ -34,6 +26,11 @@ public record ProcessArgsBuilder } } + public ProcessArgsBuilder(params Argument[] arguments) + { + Arguments = arguments.ToImmutableArray(); + } + /// public override string ToString() { @@ -45,8 +42,7 @@ public record ProcessArgsBuilder return ToStringArgs().ToArray(); } - public static implicit operator ProcessArgs(ProcessArgsBuilder builder) => - builder.ToProcessArgs(); + public static implicit operator ProcessArgs(ProcessArgsBuilder builder) => builder.ToProcessArgs(); } public static class ProcessArgBuilderExtensions @@ -55,7 +51,26 @@ public static class ProcessArgBuilderExtensions public static T AddArg(this T builder, Argument argument) where T : ProcessArgsBuilder { - return builder with { Arguments = builder.Arguments.Append(argument).ToList() }; + return builder with { Arguments = builder.Arguments.Add(argument) }; + } + + [Pure] + public static T UpdateArg(this T builder, string key, Argument argument) + where T : ProcessArgsBuilder + { + var oldArg = builder + .Arguments + .FirstOrDefault(x => x.Match(stringArg => stringArg == key, tupleArg => tupleArg.Item1 == key)); + + if (oldArg is null) + { + return builder.AddArg(argument); + } + + return builder with + { + Arguments = builder.Arguments.Replace(oldArg, argument) + }; } [Pure] @@ -64,15 +79,10 @@ public static class ProcessArgBuilderExtensions { return builder with { - Arguments = builder.Arguments - .Where( - x => - x.Match( - stringArg => stringArg != argumentKey, - tupleArg => tupleArg.Item1 != argumentKey - ) - ) - .ToList() + Arguments = builder + .Arguments + .Where(x => x.Match(stringArg => stringArg != argumentKey, tupleArg => tupleArg.Item1 != argumentKey)) + .ToImmutableArray() }; } } From 5e4f9e17fd44d09f21ef7e4c1732aade0e645f88 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 16:38:31 -0500 Subject: [PATCH 09/21] Add PipPackageSpecifier --- .../Python/PipPackageSpecifier.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 StabilityMatrix.Core/Python/PipPackageSpecifier.cs diff --git a/StabilityMatrix.Core/Python/PipPackageSpecifier.cs b/StabilityMatrix.Core/Python/PipPackageSpecifier.cs new file mode 100644 index 00000000..1cf8fb75 --- /dev/null +++ b/StabilityMatrix.Core/Python/PipPackageSpecifier.cs @@ -0,0 +1,84 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using StabilityMatrix.Core.Processes; + +namespace StabilityMatrix.Core.Python; + +public partial record PipPackageSpecifier +{ + public required string Name { get; init; } + + public string? Constraint { get; init; } + + public string? Version { get; init; } + + public string? VersionConstraint => Constraint is null || Version is null ? null : Constraint + Name; + + public static PipPackageSpecifier Parse(string value) + { + Debug.Assert(TryParse(value, true, out var packageSpecifier)); + return packageSpecifier; + } + + public static bool TryParse(string value, [NotNullWhen(true)] out PipPackageSpecifier? packageSpecifier) + { + return TryParse(value, false, out packageSpecifier); + } + + private static bool TryParse( + string value, + bool throwOnFailure, + [NotNullWhen(true)] out PipPackageSpecifier? packageSpecifier + ) + { + var match = PackageSpecifierRegex().Match(value); + if (!match.Success) + { + if (throwOnFailure) + { + throw new ArgumentException($"Invalid package specifier: {value}"); + } + + packageSpecifier = null; + return false; + } + + packageSpecifier = new PipPackageSpecifier + { + Name = match.Groups["package_name"].Value, + Constraint = match.Groups["version_constraint"].Value, + Version = match.Groups["version"].Value + }; + + return true; + } + + /// + public override string ToString() + { + return Name + VersionConstraint; + } + + public static implicit operator Argument(PipPackageSpecifier specifier) + { + return specifier.VersionConstraint is null + ? new Argument(specifier.Name) + : new Argument((specifier.Name, specifier.VersionConstraint)); + } + + public static implicit operator PipPackageSpecifier(string specifier) + { + return Parse(specifier); + } + + /// + /// Regex to match a pip package specifier. + /// + [GeneratedRegex( + "(?[a-zA-Z0-9_]+)(?(?==|>=|<=|>|<|~=|!=)([a-zA-Z0-9_.]+))?", + RegexOptions.CultureInvariant, + 1000 + )] + private static partial Regex PackageSpecifierRegex(); +} From 09cdf857f149ff20e957a4b0deafd7fe353b2924 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 18:54:03 -0500 Subject: [PATCH 10/21] Create output folder in RuinedFooocus install --- .../Models/Packages/RuinedFooocus.cs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index f3e54393..f4f93060 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -4,6 +4,7 @@ using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; +using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Services; namespace StabilityMatrix.Core.Models.Packages; @@ -39,13 +40,23 @@ public class RuinedFooocus( { var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); - progress?.Report(new ProgressReport(-1f, "Installing torch...", isIndeterminate: true)); - - await InstallCudaTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); var requirements = new FilePath(installLocation, "requirements_versions.txt"); + await venvRunner - .PipInstallFromRequirements(requirements, onConsoleOutput, excludes: "torch") + .PipInstall( + new PipInstallArgs() + .WithTorch("==2.0.1") + .WithTorchVision("==0.15.2") + .WithXFormers("==0.0.20") + .WithTorchExtraIndex("cu118") + .WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false), + excludePattern: "torch" + ), + onConsoleOutput + ) .ConfigureAwait(false); } else @@ -60,5 +71,9 @@ public class RuinedFooocus( ) .ConfigureAwait(false); } + + // Create output folder since it's not created by default + var outputFolder = new DirectoryPath(installLocation, OutputFolderName); + outputFolder.Create(); } } From 2cd9c8a6330ae8c8b9ef7c1c5410fe06612a6ade Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 18:54:19 -0500 Subject: [PATCH 11/21] Add Parse from requirement to PipInstallArgs --- .../Processes/ProcessArgsBuilder.cs | 7 ++++ StabilityMatrix.Core/Python/PipInstallArgs.cs | 33 +++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs b/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs index e1e9ffc5..1b0dbfa7 100644 --- a/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs +++ b/StabilityMatrix.Core/Processes/ProcessArgsBuilder.cs @@ -54,6 +54,13 @@ public static class ProcessArgBuilderExtensions return builder with { Arguments = builder.Arguments.Add(argument) }; } + [Pure] + public static T AddArgs(this T builder, params Argument[] argument) + where T : ProcessArgsBuilder + { + return builder with { Arguments = builder.Arguments.AddRange(argument) }; + } + [Pure] public static T UpdateArg(this T builder, string key, Argument argument) where T : ProcessArgsBuilder diff --git a/StabilityMatrix.Core/Python/PipInstallArgs.cs b/StabilityMatrix.Core/Python/PipInstallArgs.cs index d16aedf7..68e371f7 100644 --- a/StabilityMatrix.Core/Python/PipInstallArgs.cs +++ b/StabilityMatrix.Core/Python/PipInstallArgs.cs @@ -1,4 +1,7 @@ -using StabilityMatrix.Core.Processes; +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Processes; namespace StabilityMatrix.Core.Python; @@ -9,20 +12,36 @@ public record PipInstallArgs : ProcessArgsBuilder public PipInstallArgs WithTorch(string version = "") => this.AddArg($"torch{version}"); - public PipInstallArgs WithTorchDirectML(string version = "") => - this.AddArg($"torch-directml{version}"); + public PipInstallArgs WithTorchDirectML(string version = "") => this.AddArg($"torch-directml{version}"); - public PipInstallArgs WithTorchVision(string version = "") => - this.AddArg($"torchvision{version}"); + public PipInstallArgs WithTorchVision(string version = "") => this.AddArg($"torchvision{version}"); public PipInstallArgs WithXFormers(string version = "") => this.AddArg($"xformers{version}"); - public PipInstallArgs WithExtraIndex(string indexUrl) => - this.AddArg(("--extra-index-url", indexUrl)); + public PipInstallArgs WithExtraIndex(string indexUrl) => this.AddArg(("--extra-index-url", indexUrl)); public PipInstallArgs WithTorchExtraIndex(string index) => this.AddArg(("--extra-index-url", $"https://download.pytorch.org/whl/{index}")); + public PipInstallArgs WithParsedFromRequirementsTxt( + string requirements, + [StringSyntax(StringSyntaxAttribute.Regex)] string? excludePattern = null + ) + { + var requirementsEntries = requirements + .SplitLines(StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .AsEnumerable(); + + if (excludePattern is not null) + { + var excludeRegex = new Regex($"^{excludePattern}$"); + + requirementsEntries = requirementsEntries.Where(s => !excludeRegex.IsMatch(s)); + } + + return this.AddArgs(requirementsEntries.Select(s => (Argument)s).ToArray()); + } + /// public override string ToString() { From 2aab1e0523a1a4f6fd1a944eedb951d088c77fcb Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 18:54:35 -0500 Subject: [PATCH 12/21] Refactor fooocus to use parse from requirements --- .../Models/Packages/Fooocus.cs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 33b05647..725e7c2a 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System.Collections.Immutable; +using System.Diagnostics; using System.Text.RegularExpressions; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; @@ -152,39 +153,38 @@ public class Fooocus( { var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); - progress?.Report(new ProgressReport(-1f, "Installing torch...", isIndeterminate: true)); + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + + var pipArgs = new PipInstallArgs(); if (torchVersion == TorchVersion.DirectMl) { - await venvRunner - .PipInstall(new PipInstallArgs().WithTorchDirectML(), onConsoleOutput) - .ConfigureAwait(false); + pipArgs = pipArgs.WithTorchDirectML(); } else { - var extraIndex = torchVersion switch - { - TorchVersion.Cpu => "cpu", - TorchVersion.Cuda => "cu121", - TorchVersion.Rocm => "rocm5.6", - _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) - }; - - await venvRunner - .PipInstall( - new PipInstallArgs() - .WithTorch("==2.1.0") - .WithTorchVision("==0.16.0") - .WithTorchExtraIndex(extraIndex), - onConsoleOutput - ) - .ConfigureAwait(false); + pipArgs = pipArgs + .WithTorch("==2.1.0") + .WithTorchVision("==0.16.0") + .WithTorchExtraIndex( + torchVersion switch + { + TorchVersion.Cpu => "cpu", + TorchVersion.Cuda => "cu121", + TorchVersion.Rocm => "rocm5.6", + _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) + } + ); } var requirements = new FilePath(installLocation, "requirements_versions.txt"); - await venvRunner - .PipInstallFromRequirements(requirements, onConsoleOutput, excludes: "torch") - .ConfigureAwait(false); + + pipArgs = pipArgs.WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false), + excludePattern: "torch" + ); + + await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false); } public override async Task RunPackage( From e476b8153ad74d3e85d140551769fcc4f95dc4ed Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 19:03:56 -0500 Subject: [PATCH 13/21] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81608f40..df586b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Changed Symlink shared folder link targets for Automatic1111 and ComfyUI. From `ControlNet -> models/controlnet` to `ControlNet -> models/controlnet/ControlNet` and `T2IAdapter -> models/controlnet/T2IAdapter`. ### Fixed - Fixed ControlNet / T2IAdapter shared folder links for Automatic1111 conflicting with each other -- Fixes URIScheme registration errors on Linux +- Fixed URIScheme registration errors on Linux +- Fixed RuinedFooocus missing output folder on startup ## v2.7.1 ### Added From af13261184eac83aed95619fa4a391eccb5e261c Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 19:15:33 -0500 Subject: [PATCH 14/21] Update A3WebUI to use requirement parse install --- .../Models/Packages/A3WebUI.cs | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 1954fbfb..c5794f10 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -183,39 +183,44 @@ public class A3WebUI( ) { progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); - // Setup venv - await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); - venvRunner.WorkingDirectory = installLocation; - await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); - switch (torchVersion) + var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); + + await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); + + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + + var requirements = new FilePath(installLocation, "requirements_versions.txt"); + + var pipArgs = new PipInstallArgs() + .WithTorch("==2.0.1") + .WithTorchVision("==0.15.2") + .WithTorchExtraIndex( + torchVersion switch + { + TorchVersion.Cpu => "cpu", + TorchVersion.Cuda => "cu118", + TorchVersion.Rocm => "rocm5.1.1", + _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) + } + ) + .WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false), + excludePattern: "torch" + ); + + if (torchVersion == TorchVersion.Cuda) { - case TorchVersion.Cpu: - await InstallCpuTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); - break; - case TorchVersion.Cuda: - await InstallCudaTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); - break; - case TorchVersion.Rocm: - await InstallRocmTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); - break; - default: - throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null); + pipArgs = pipArgs.WithXFormers("==0.0.20"); } + // v1.6.0 needs a httpx qualifier to fix a gradio issue if (versionOptions.VersionTag?.Contains("1.6.0") ?? false) { - await venvRunner.PipInstall("httpx==0.24.1", onConsoleOutput); + pipArgs = pipArgs.AddArg("httpx==0.24.1"); } - // Install requirements file - progress?.Report(new ProgressReport(-1f, "Installing Package Requirements", isIndeterminate: true)); - Logger.Info("Installing requirements_versions.txt"); - - var requirements = new FilePath(installLocation, "requirements_versions.txt"); - await venvRunner - .PipInstallFromRequirements(requirements, onConsoleOutput, excludes: "torch") - .ConfigureAwait(false); + await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false); progress?.Report(new ProgressReport(-1f, "Updating configuration", isIndeterminate: true)); @@ -261,24 +266,6 @@ public class A3WebUI( VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); } - private async Task InstallRocmTorch( - PyVenvRunner venvRunner, - IProgress? progress = null, - Action? onConsoleOutput = null - ) - { - progress?.Report(new ProgressReport(-1f, "Installing PyTorch for ROCm", isIndeterminate: true)); - - await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); - - await venvRunner - .PipInstall( - new PipInstallArgs().WithTorch("==2.0.1").WithTorchVision().WithTorchExtraIndex("rocm5.1.1"), - onConsoleOutput - ) - .ConfigureAwait(false); - } - /// public override async Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) { From 894d230a06401c964d9c17c4f8ac703d2c90b079 Mon Sep 17 00:00:00 2001 From: Ionite Date: Fri, 15 Dec 2023 19:34:37 -0500 Subject: [PATCH 15/21] Update Comfy to use requirement parse install --- .../Models/Packages/ComfyUI.cs | 120 +++++------------- 1 file changed, 35 insertions(+), 85 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index daa586cd..1b221a62 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -156,80 +156,48 @@ public class ComfyUI( venvRunner.WorkingDirectory = installLocation; await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); - // Install torch / xformers based on gpu info - switch (torchVersion) + await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); + + progress?.Report(new ProgressReport(-1f, "Installing Package Requirements...", isIndeterminate: true)); + + var pipArgs = new PipInstallArgs(); + + pipArgs = torchVersion switch { - case TorchVersion.Cpu: - await InstallCpuTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); - break; - case TorchVersion.Cuda: - await venvRunner - .PipInstall( - new PipInstallArgs() - .WithTorch("~=2.1.0") - .WithTorchVision() - .WithXFormers("==0.0.22.post4") - .AddArg("--upgrade") - .WithTorchExtraIndex("cu121"), - onConsoleOutput + TorchVersion.DirectMl => pipArgs.WithTorchDirectML(), + TorchVersion.Mps + => pipArgs.AddArg("--pre").WithTorch().WithTorchVision().WithTorchExtraIndex("nightly/cpu"), + _ + => pipArgs + .AddArg("--upgrade") + .WithTorch("~=2.1.0") + .WithTorchVision() + .WithTorchExtraIndex( + torchVersion switch + { + TorchVersion.Cpu => "cpu", + TorchVersion.Cuda => "cu121", + TorchVersion.Rocm => "rocm5.6", + _ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null) + } ) - .ConfigureAwait(false); - break; - case TorchVersion.DirectMl: - await venvRunner - .PipInstall(new PipInstallArgs().WithTorchDirectML(), onConsoleOutput) - .ConfigureAwait(false); - break; - case TorchVersion.Rocm: - await InstallRocmTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false); - break; - case TorchVersion.Mps: - await venvRunner - .PipInstall( - new PipInstallArgs() - .AddArg("--pre") - .WithTorch() - .WithTorchVision() - .WithTorchExtraIndex("nightly/cpu"), - onConsoleOutput - ) - .ConfigureAwait(false); - break; - default: - throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null); + }; + + if (torchVersion == TorchVersion.Cuda) + { + pipArgs = pipArgs.WithXFormers("==0.0.22.post4"); } - // Install requirements file (skip torch) - progress?.Report(new ProgressReport(-1, "Installing Package Requirements", isIndeterminate: true)); + var requirements = new FilePath(installLocation, "requirements.txt"); - var requirementsFile = new FilePath(installLocation, "requirements.txt"); + pipArgs = pipArgs.WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false), + excludePattern: "torch" + ); - await venvRunner - .PipInstallFromRequirements(requirementsFile, onConsoleOutput, excludes: "torch") - .ConfigureAwait(false); + await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false); - progress?.Report(new ProgressReport(1, "Installing Package Requirements", isIndeterminate: false)); - } - - private async Task AutoDetectAndInstallTorch(PyVenvRunner venvRunner, IProgress? progress = null) - { - var gpus = HardwareHelper.IterGpuInfo().ToList(); - if (gpus.Any(g => g.IsNvidia)) - { - await InstallCudaTorch(venvRunner, progress).ConfigureAwait(false); - } - else if (HardwareHelper.PreferRocm()) - { - await InstallRocmTorch(venvRunner, progress).ConfigureAwait(false); - } - else if (HardwareHelper.PreferDirectML()) - { - await InstallDirectMlTorch(venvRunner, progress).ConfigureAwait(false); - } - else - { - await InstallCpuTorch(venvRunner, progress).ConfigureAwait(false); - } + progress?.Report(new ProgressReport(1, "Installed Package Requirements", isIndeterminate: false)); } public override async Task RunPackage( @@ -435,22 +403,4 @@ public class ComfyUI( await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false); } - - private async Task InstallRocmTorch( - PyVenvRunner venvRunner, - IProgress? progress = null, - Action? onConsoleOutput = null - ) - { - progress?.Report(new ProgressReport(-1f, "Installing PyTorch for ROCm", isIndeterminate: true)); - - await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); - - await venvRunner - .PipInstall( - new PipInstallArgs().WithTorch("==2.0.1").WithTorchVision().WithTorchExtraIndex("rocm5.6"), - onConsoleOutput - ) - .ConfigureAwait(false); - } } From e50c6a3d15cc81c949029634fb367ab0cd6d2545 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 15 Dec 2023 21:37:03 -0800 Subject: [PATCH 16/21] Fixed Fooocus vram args --- .../Models/Packages/Fooocus.cs | 6 +- .../Models/Packages/RuinedFooocus.cs | 74 +++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 725e7c2a..698c9f1a 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -77,11 +77,11 @@ public class Fooocus( Type = LaunchOptionType.Bool, InitialValue = HardwareHelper.IterGpuInfo().Select(gpu => gpu.MemoryLevel).Max() switch { - MemoryLevel.Low => "--lowvram", - MemoryLevel.Medium => "--normalvram", + MemoryLevel.Low => "--always-low-vram", + MemoryLevel.Medium => "--always-normal-vram", _ => null }, - Options = { "--highvram", "--normalvram", "--lowvram", "--novram" } + Options = { "--always-high-vram", "--always-normal-vram", "--always-low-vram", "--always-no-vram" } }, new LaunchOptionDefinition { diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index f4f93060..fbf2535f 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -1,6 +1,7 @@ using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; +using StabilityMatrix.Core.Helper.HardwareInfo; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; @@ -27,6 +28,79 @@ public class RuinedFooocus( new("https://raw.githubusercontent.com/runew0lf/pmmconfigs/main/RuinedFooocus_ss.png"); public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Expert; + public override List LaunchOptions => + new() + { + new LaunchOptionDefinition + { + Name = "Preset", + Type = LaunchOptionType.Bool, + Options = { "--preset anime", "--preset realistic" } + }, + new LaunchOptionDefinition + { + Name = "Port", + Type = LaunchOptionType.String, + Description = "Sets the listen port", + Options = { "--port" } + }, + new LaunchOptionDefinition + { + Name = "Share", + Type = LaunchOptionType.Bool, + Description = "Set whether to share on Gradio", + Options = { "--share" } + }, + new LaunchOptionDefinition + { + Name = "Listen", + Type = LaunchOptionType.String, + Description = "Set the listen interface", + Options = { "--listen" } + }, + new LaunchOptionDefinition + { + Name = "Output Directory", + Type = LaunchOptionType.String, + Description = "Override the output directory", + Options = { "--output-directory" } + }, + new() + { + Name = "VRAM", + Type = LaunchOptionType.Bool, + InitialValue = HardwareHelper.IterGpuInfo().Select(gpu => gpu.MemoryLevel).Max() switch + { + MemoryLevel.Low => "--lowvram", + MemoryLevel.Medium => "--normalvram", + _ => null + }, + Options = { "--highvram", "--normalvram", "--lowvram", "--novram" } + }, + new LaunchOptionDefinition + { + Name = "Use DirectML", + Type = LaunchOptionType.Bool, + Description = "Use pytorch with DirectML support", + InitialValue = HardwareHelper.PreferDirectML(), + Options = { "--directml" } + }, + new LaunchOptionDefinition + { + Name = "Disable Xformers", + Type = LaunchOptionType.Bool, + InitialValue = !HardwareHelper.HasNvidiaGpu(), + Options = { "--disable-xformers" } + }, + new LaunchOptionDefinition + { + Name = "Auto-Launch", + Type = LaunchOptionType.Bool, + Options = { "--auto-launch" } + }, + LaunchOptionDefinition.Extras + }; + public override async Task InstallPackage( string installLocation, TorchVersion torchVersion, From 4e30205e616eb130511f225f8e3a27f29164c8f1 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 15 Dec 2023 21:46:54 -0800 Subject: [PATCH 17/21] also add diffusers ipadapter links --- CHANGELOG.md | 1 + StabilityMatrix.Core/Models/Packages/A3WebUI.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df586b33..724c8b67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Fixed ControlNet / T2IAdapter shared folder links for Automatic1111 conflicting with each other - Fixed URIScheme registration errors on Linux - Fixed RuinedFooocus missing output folder on startup +- Fixed incorrect Fooocus VRAM launch arguments ## v2.7.1 ### Added diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index c5794f10..6f3efd8d 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -61,7 +61,9 @@ public class A3WebUI( [SharedFolderType.LDSR] = new[] { "models/LDSR" }, [SharedFolderType.AfterDetailer] = new[] { "models/adetailer" }, [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, - [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" } + [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" }, + [SharedFolderType.InvokeIpAdapters15] = new[] { "models/controlnet/DiffusersIpAdapters" }, + [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/controlnet/DiffusersIpAdaptersXL" } }; public override Dictionary>? SharedOutputFolders => From 0f459bb1987e6cf86855c835bd27f4ae40781e57 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 01:09:26 -0500 Subject: [PATCH 18/21] Fix debug assert for release mode --- StabilityMatrix.Core/Python/PipPackageSpecifier.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/StabilityMatrix.Core/Python/PipPackageSpecifier.cs b/StabilityMatrix.Core/Python/PipPackageSpecifier.cs index 1cf8fb75..5dc58356 100644 --- a/StabilityMatrix.Core/Python/PipPackageSpecifier.cs +++ b/StabilityMatrix.Core/Python/PipPackageSpecifier.cs @@ -17,8 +17,11 @@ public partial record PipPackageSpecifier public static PipPackageSpecifier Parse(string value) { - Debug.Assert(TryParse(value, true, out var packageSpecifier)); - return packageSpecifier; + var result = TryParse(value, true, out var packageSpecifier); + + Debug.Assert(result); + + return packageSpecifier!; } public static bool TryParse(string value, [NotNullWhen(true)] out PipPackageSpecifier? packageSpecifier) From b0e65fec84f23e9a85abbc6a0aa2e14574b5c093 Mon Sep 17 00:00:00 2001 From: Ionite Date: Sat, 16 Dec 2023 01:28:08 -0500 Subject: [PATCH 19/21] Fix null reference when update before main window --- .../Views/MainWindow.axaml.cs | 84 +++++++++---------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs index 971d7c9a..c1263426 100644 --- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs @@ -89,9 +89,7 @@ public partial class MainWindow : AppWindowBase { base.OnApplyTemplate(e); - navigationService.SetFrame( - FrameView ?? throw new NullReferenceException("Frame not found") - ); + navigationService.SetFrame(FrameView ?? throw new NullReferenceException("Frame not found")); } protected override void OnOpened(EventArgs e) @@ -134,16 +132,15 @@ public partial class MainWindow : AppWindowBase return; // Navigate to first page - Dispatcher.UIThread.Post( - () => - navigationService.NavigateTo( - vm.Pages[0], - new BetterSlideNavigationTransition - { - Effect = SlideNavigationTransitionEffect.FromBottom - } - ) - ); + Dispatcher + .UIThread + .Post( + () => + navigationService.NavigateTo( + vm.Pages[0], + new BetterSlideNavigationTransition { Effect = SlideNavigationTransitionEffect.FromBottom } + ) + ); // Check show update teaching tip if (vm.UpdateViewModel.IsUpdateAvailable) @@ -167,27 +164,28 @@ public partial class MainWindow : AppWindowBase { var mainViewModel = (MainWindowViewModel)DataContext!; - mainViewModel.SelectedCategory = mainViewModel.Pages + mainViewModel.SelectedCategory = mainViewModel + .Pages .Concat(mainViewModel.FooterPages) .FirstOrDefault(x => x.GetType() == e.ViewModelType); } private void OnUpdateAvailable(object? sender, UpdateInfo? updateInfo) { - Dispatcher.UIThread.Post(() => - { - var vm = DataContext as MainWindowViewModel; - - if (vm!.ShouldShowUpdateAvailableTeachingTip(updateInfo)) + Dispatcher + .UIThread + .Post(() => { - var target = this.FindControl("FooterUpdateItem")!; - var tip = this.FindControl("UpdateAvailableTeachingTip")!; + if (DataContext is MainWindowViewModel vm && vm.ShouldShowUpdateAvailableTeachingTip(updateInfo)) + { + var target = this.FindControl("FooterUpdateItem")!; + var tip = this.FindControl("UpdateAvailableTeachingTip")!; - tip.Target = target; - tip.Subtitle = $"{Compat.AppVersion.ToDisplayString()} -> {updateInfo.Version}"; - tip.IsOpen = true; - } - }); + tip.Target = target; + tip.Subtitle = $"{Compat.AppVersion.ToDisplayString()} -> {updateInfo.Version}"; + tip.IsOpen = true; + } + }); } public void SetDefaultFonts() @@ -284,16 +282,18 @@ public partial class MainWindow : AppWindowBase private void OnImageLoadFailed(object? sender, ImageLoadFailedEventArgs e) { - Dispatcher.UIThread.Post(() => - { - var fileName = Path.GetFileName(e.Url); - var displayName = string.IsNullOrEmpty(fileName) ? e.Url : fileName; - notificationService.ShowPersistent( - "Failed to load image", - $"Could not load '{displayName}'\n({e.Exception.Message})", - NotificationType.Warning - ); - }); + Dispatcher + .UIThread + .Post(() => + { + var fileName = Path.GetFileName(e.Url); + var displayName = string.IsNullOrEmpty(fileName) ? e.Url : fileName; + notificationService.ShowPersistent( + "Failed to load image", + $"Could not load '{displayName}'\n({e.Exception.Message})", + NotificationType.Warning + ); + }); } private void TryEnableMicaEffect() @@ -308,11 +308,7 @@ public partial class MainWindow : AppWindowBase if (ActualThemeVariant == ThemeVariant.Dark) { - var color = this.TryFindResource( - "SolidBackgroundFillColorBase", - ThemeVariant.Dark, - out var value - ) + var color = this.TryFindResource("SolidBackgroundFillColorBase", ThemeVariant.Dark, out var value) ? (Color2)(Color)value! : new Color2(30, 31, 34); @@ -323,11 +319,7 @@ public partial class MainWindow : AppWindowBase else if (ActualThemeVariant == ThemeVariant.Light) { // Similar effect here - var color = this.TryFindResource( - "SolidBackgroundFillColorBase", - ThemeVariant.Light, - out var value - ) + var color = this.TryFindResource("SolidBackgroundFillColorBase", ThemeVariant.Light, out var value) ? (Color2)(Color)value! : new Color2(243, 243, 243); From 3ae60f4a21d96c5e48846a928277937fbb2f6d62 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 15 Dec 2023 23:40:08 -0800 Subject: [PATCH 20/21] changed FreeU defaults to match recommended SD1.5 defaults & changed denoiseStrength default to 0.7 from 1.0 --- CHANGELOG.md | 2 ++ .../ViewModels/Inference/FreeUCardViewModel.cs | 4 ++-- .../ViewModels/Inference/SamplerCardViewModel.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 724c8b67..cd5995d4 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.7.2 ### Changed - Changed Symlink shared folder link targets for Automatic1111 and ComfyUI. From `ControlNet -> models/controlnet` to `ControlNet -> models/controlnet/ControlNet` and `T2IAdapter -> models/controlnet/T2IAdapter`. +- Changed FreeU defaults to match recommended SD1.5 defaults +- Changed default denoise strength from 1.0 to 0.7 ### Fixed - Fixed ControlNet / T2IAdapter shared folder links for Automatic1111 conflicting with each other - Fixed URIScheme registration errors on Linux diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs index 4080af7a..7f909d0e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs @@ -16,12 +16,12 @@ public partial class FreeUCardViewModel : LoadableViewModelBase [ObservableProperty] [Required] [Range(0D, 10D)] - private double b1 = 1.1; + private double b1 = 1.5; [ObservableProperty] [Required] [Range(0D, 10D)] - private double b2 = 1.2; + private double b2 = 1.6; [ObservableProperty] [Required] diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs index eeaf4a25..32640d8e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs @@ -42,7 +42,7 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo private bool isDenoiseStrengthEnabled; [ObservableProperty] - private double denoiseStrength = 1; + private double denoiseStrength = 0.7f; [ObservableProperty] [property: Category("Settings")] From cc9dfbb33f2f67fbdcd6f94aaa9063c6daa7e097 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 15 Dec 2023 23:44:08 -0800 Subject: [PATCH 21/21] also add some NotifyDataErrorInfo --- .../ViewModels/Inference/FreeUCardViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs index 7f909d0e..1aac1239 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/FreeUCardViewModel.cs @@ -14,21 +14,25 @@ public partial class FreeUCardViewModel : LoadableViewModelBase public const string ModuleKey = "FreeU"; [ObservableProperty] + [NotifyDataErrorInfo] [Required] [Range(0D, 10D)] private double b1 = 1.5; [ObservableProperty] + [NotifyDataErrorInfo] [Required] [Range(0D, 10D)] private double b2 = 1.6; [ObservableProperty] + [NotifyDataErrorInfo] [Required] [Range(0D, 10D)] private double s1 = 0.9; [ObservableProperty] + [NotifyDataErrorInfo] [Required] [Range(0D, 10D)] private double s2 = 0.2;