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(