Browse Source

Merge pull request #406 from ionite34/shared-folder-fixes

pull/333/head
Ionite 11 months ago committed by GitHub
parent
commit
c8aa8bafbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      CHANGELOG.md
  2. 36
      StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs
  3. 25
      StabilityMatrix.Core/Models/Packages/A3WebUI.cs
  4. 116
      StabilityMatrix.Core/Models/Packages/ComfyUI.cs

6
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/), 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). 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 ## v2.7.1
### Added ### Added
- Added Turkish UI language option, thanks to Progresor for the translation - Added Turkish UI language option, thanks to Progresor for the translation

36
StabilityMatrix.Core/Models/FileInterfaces/FileSystemPath.cs

@ -1,6 +1,6 @@
namespace StabilityMatrix.Core.Models.FileInterfaces; namespace StabilityMatrix.Core.Models.FileInterfaces;
public class FileSystemPath : IEquatable<FileSystemPath>, IEquatable<string> public class FileSystemPath : IEquatable<FileSystemPath>, IEquatable<string>, IFormattable
{ {
public string FullPath { get; } public string FullPath { get; }
@ -8,27 +8,42 @@ public class FileSystemPath : IEquatable<FileSystemPath>, IEquatable<string>
{ {
FullPath = path; 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)) /// <inheritdoc />
string IFormattable.ToString(string? format, IFormatProvider? formatProvider)
{ {
return ToString(format, formatProvider);
} }
public override string ToString() /// <summary>
/// Overridable IFormattable.ToString method.
/// By default, returns <see cref="FullPath"/>.
/// </summary>
protected virtual string ToString(string? format, IFormatProvider? formatProvider)
{ {
return FullPath; return FullPath;
} }
public bool Equals(FileSystemPath? other) public bool Equals(FileSystemPath? other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other))
if (ReferenceEquals(this, other)) return true; return false;
if (ReferenceEquals(this, other))
return true;
return FullPath == other.FullPath; return FullPath == other.FullPath;
} }
public bool Equals(string? other) public bool Equals(string? other)
{ {
return string.Equals(FullPath, other); return string.Equals(FullPath, other);
@ -48,8 +63,9 @@ public class FileSystemPath : IEquatable<FileSystemPath>, IEquatable<string>
{ {
return FullPath.GetHashCode(); return FullPath.GetHashCode();
} }
// Implicit conversions to and from string // Implicit conversions to and from string
public static implicit operator string(FileSystemPath path) => path.FullPath; public static implicit operator string(FileSystemPath path) => path.FullPath;
public static implicit operator FileSystemPath(string path) => new(path); public static implicit operator FileSystemPath(string path) => new(path);
} }

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

@ -56,12 +56,12 @@ public class A3WebUI(
[SharedFolderType.Karlo] = new[] { "models/karlo" }, [SharedFolderType.Karlo] = new[] { "models/karlo" },
[SharedFolderType.TextualInversion] = new[] { "embeddings" }, [SharedFolderType.TextualInversion] = new[] { "embeddings" },
[SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" }, [SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" },
[SharedFolderType.ControlNet] = new[] { "models/ControlNet" }, [SharedFolderType.ControlNet] = new[] { "models/controlnet/ControlNet" },
[SharedFolderType.Codeformer] = new[] { "models/Codeformer" }, [SharedFolderType.Codeformer] = new[] { "models/Codeformer" },
[SharedFolderType.LDSR] = new[] { "models/LDSR" }, [SharedFolderType.LDSR] = new[] { "models/LDSR" },
[SharedFolderType.AfterDetailer] = new[] { "models/adetailer" }, [SharedFolderType.AfterDetailer] = new[] { "models/adetailer" },
[SharedFolderType.T2IAdapter] = new[] { "models/controlnet" }, [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" },
[SharedFolderType.IpAdapter] = new[] { "models/ipadapter" } [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" }
}; };
public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders => public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders =>
@ -278,4 +278,23 @@ public class A3WebUI(
) )
.ConfigureAwait(false); .ConfigureAwait(false);
} }
/// <inheritdoc />
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(false).ConfigureAwait(false);
}
// Resume base setup
await base.SetupModelFolders(installDirectory, sharedFolderMethod).ConfigureAwait(false);
}
/// <inheritdoc />
public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) =>
SetupModelFolders(installDirectory, sharedFolderMethod);
} }

116
StabilityMatrix.Core/Models/Packages/ComfyUI.cs

@ -10,6 +10,7 @@ using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Python;
using StabilityMatrix.Core.Services; using StabilityMatrix.Core.Services;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel; using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NamingConventions;
@ -53,12 +54,12 @@ public class ComfyUI(
[SharedFolderType.TextualInversion] = new[] { "models/embeddings" }, [SharedFolderType.TextualInversion] = new[] { "models/embeddings" },
[SharedFolderType.VAE] = new[] { "models/vae" }, [SharedFolderType.VAE] = new[] { "models/vae" },
[SharedFolderType.ApproxVAE] = new[] { "models/vae_approx" }, [SharedFolderType.ApproxVAE] = new[] { "models/vae_approx" },
[SharedFolderType.ControlNet] = new[] { "models/controlnet" }, [SharedFolderType.ControlNet] = new[] { "models/controlnet/ControlNet" },
[SharedFolderType.GLIGEN] = new[] { "models/gligen" }, [SharedFolderType.GLIGEN] = new[] { "models/gligen" },
[SharedFolderType.ESRGAN] = new[] { "models/upscale_models" }, [SharedFolderType.ESRGAN] = new[] { "models/upscale_models" },
[SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" }, [SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" },
[SharedFolderType.IpAdapter] = new[] { "models/ipadapter" }, [SharedFolderType.IpAdapter] = new[] { "models/ipadapter" },
[SharedFolderType.T2IAdapter] = new[] { "models/controlnet" }, [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" },
}; };
public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders => public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders =>
@ -267,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)
{
return sharedFolderMethod switch
{
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)
{ {
switch (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)
{ {
case SharedFolderMethod.None: Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink);
return Task.CompletedTask; await controlnetOldLink.DeleteAsync(false).ConfigureAwait(false);
case SharedFolderMethod.Symlink:
return base.SetupModelFolders(installDirectory, sharedFolderMethod);
} }
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 modelsDir = SettingsManager.ModelsDirectory;
var exists = File.Exists(extraPathsYamlPath); if (!extraPathsYamlPath.Exists)
if (!exists)
{ {
Logger.Info("Creating extra_model_paths.yaml"); 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); using var sr = new StringReader(yaml);
var yamlStream = new YamlStream(); var yamlStream = new YamlStream();
yamlStream.Load(sr); yamlStream.Load(sr);
@ -307,7 +337,7 @@ public class ComfyUI(
if (stabilityMatrixNode.Key != null) if (stabilityMatrixNode.Key != null)
{ {
if (stabilityMatrixNode.Value is not YamlMappingNode nodeValue) if (stabilityMatrixNode.Value is not YamlMappingNode nodeValue)
return Task.CompletedTask; return;
nodeValue.Children["checkpoints"] = Path.Combine(modelsDir, "StableDiffusion"); nodeValue.Children["checkpoints"] = Path.Combine(modelsDir, "StableDiffusion");
nodeValue.Children["vae"] = Path.Combine(modelsDir, "VAE"); nodeValue.Children["vae"] = Path.Combine(modelsDir, "VAE");
@ -319,7 +349,11 @@ public class ComfyUI(
+ $"{Path.Combine(modelsDir, "SwinIR")}"; + $"{Path.Combine(modelsDir, "SwinIR")}";
nodeValue.Children["embeddings"] = Path.Combine(modelsDir, "TextualInversion"); nodeValue.Children["embeddings"] = Path.Combine(modelsDir, "TextualInversion");
nodeValue.Children["hypernetworks"] = Path.Combine(modelsDir, "Hypernetwork"); 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["clip"] = Path.Combine(modelsDir, "CLIP");
nodeValue.Children["diffusers"] = Path.Combine(modelsDir, "Diffusers"); nodeValue.Children["diffusers"] = Path.Combine(modelsDir, "Diffusers");
nodeValue.Children["gligen"] = Path.Combine(modelsDir, "GLIGEN"); nodeValue.Children["gligen"] = Path.Combine(modelsDir, "GLIGEN");
@ -340,7 +374,10 @@ public class ComfyUI(
}, },
{ "embeddings", Path.Combine(modelsDir, "TextualInversion") }, { "embeddings", Path.Combine(modelsDir, "TextualInversion") },
{ "hypernetworks", Path.Combine(modelsDir, "Hypernetwork") }, { "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") }, { "clip", Path.Combine(modelsDir, "CLIP") },
{ "diffusers", Path.Combine(modelsDir, "Diffusers") }, { "diffusers", Path.Combine(modelsDir, "Diffusers") },
{ "gligen", Path.Combine(modelsDir, "GLIGEN") }, { "gligen", Path.Combine(modelsDir, "GLIGEN") },
@ -357,65 +394,46 @@ public class ComfyUI(
newRootNode.Children.Add(stabilityMatrixNode); newRootNode.Children.Add(stabilityMatrixNode);
var serializer = new SerializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build(); var serializer = new SerializerBuilder()
var yamlData = serializer.Serialize(newRootNode); .WithNamingConvention(UnderscoredNamingConvention.Instance)
File.WriteAllText(extraPathsYamlPath, yamlData); .WithDefaultScalarStyle(ScalarStyle.Literal)
.Build();
return Task.CompletedTask; var yamlData = serializer.Serialize(newRootNode);
await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false);
} }
public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => private static async Task RemoveConfigSection(DirectoryPath installDirectory)
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)
{ {
return sharedFolderMethod switch var extraPathsYamlPath = installDirectory.JoinFile("extra_model_paths.yaml");
{
SharedFolderMethod.Configuration => RemoveConfigSection(installDirectory),
SharedFolderMethod.None => Task.CompletedTask,
SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory, sharedFolderMethod),
_ => Task.CompletedTask
};
}
private Task RemoveConfigSection(string installDirectory) if (!extraPathsYamlPath.Exists)
{
var extraPathsYamlPath = Path.Combine(installDirectory, "extra_model_paths.yaml");
var exists = File.Exists(extraPathsYamlPath);
if (!exists)
{ {
return Task.CompletedTask; return;
} }
var yaml = File.ReadAllText(extraPathsYamlPath); var yaml = await extraPathsYamlPath.ReadAllTextAsync().ConfigureAwait(false);
using var sr = new StringReader(yaml); using var sr = new StringReader(yaml);
var yamlStream = new YamlStream(); var yamlStream = new YamlStream();
yamlStream.Load(sr); yamlStream.Load(sr);
if (!yamlStream.Documents.Any()) if (!yamlStream.Documents.Any())
{ {
return Task.CompletedTask; return;
} }
var root = yamlStream.Documents[0].RootNode; var root = yamlStream.Documents[0].RootNode;
if (root is not YamlMappingNode mappingNode) if (root is not YamlMappingNode mappingNode)
{ {
return Task.CompletedTask; return;
} }
mappingNode.Children.Remove("stability_matrix"); mappingNode.Children.Remove("stability_matrix");
var serializer = new SerializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build(); var serializer = new SerializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build();
var yamlData = serializer.Serialize(mappingNode); var yamlData = serializer.Serialize(mappingNode);
File.WriteAllText(extraPathsYamlPath, yamlData);
return Task.CompletedTask; await extraPathsYamlPath.WriteAllTextAsync(yamlData).ConfigureAwait(false);
} }
private async Task InstallRocmTorch( private async Task InstallRocmTorch(

Loading…
Cancel
Save