diff --git a/CHANGELOG.md b/CHANGELOG.md index 5008a001..de54570a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ 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.11.8 +### Added +- Added Flux & AuraFlow types to CivitAI Browser +- Added unet folder links for ComfyUI thanks to jeremydk +- Added CLIP folder links for Forge +### Changed +- Updated Brazilian Portuguese translations thanks to thiagojramos +### Fixed +- Fixed [#840](https://github.com/LykosAI/StabilityMatrix/issues/840) - CivitAI model browser not loading search results +- Fixed SwarmUI settings being overwritten on launch +- Fixed [#832](https://github.com/LykosAI/StabilityMatrix/issues/832) [#847](https://github.com/LykosAI/StabilityMatrix/issues/847) - Forge output folder links pointing to the incorrect folder +- Fixed errors when downloading models with invalid characters in the file name +- Fixed error when installing RuinedFooocus on nvidia GPUs +### Supporters +#### Pioneers +- A big shoutout to our Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, and **Szir777**! We deeply appreciate your ongoing support! + ## v2.11.7 ### Changed - Forge will use the recommended pytorch version 2.3.1 the next time it is updated diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index d2cbce9c..95fde650 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -345,8 +345,8 @@ public static void Initialize() FileMetadata = new CivitFileMetadata { Format = CivitModelFormat.SafeTensor, - Fp = CivitModelFpType.fp16, - Size = CivitModelSize.pruned, + Fp = "fp16", + Size = "pruned", }, TrainedWords = ["aurora", "lightning"] } @@ -634,8 +634,8 @@ public static UpdateSettingsViewModel UpdateSettingsViewModel Metadata = new CivitFileMetadata { Format = CivitModelFormat.SafeTensor, - Fp = CivitModelFpType.fp16, - Size = CivitModelSize.pruned + Fp = "fp16", + Size = "pruned" } }, new() @@ -645,8 +645,8 @@ public static UpdateSettingsViewModel UpdateSettingsViewModel Metadata = new CivitFileMetadata { Format = CivitModelFormat.SafeTensor, - Fp = CivitModelFpType.fp32, - Size = CivitModelSize.full + Fp = "fp32", + Size = "full" }, Hashes = new CivitFileHashes { BLAKE3 = "ABCD" } } diff --git a/StabilityMatrix.Avalonia/Services/IModelImportService.cs b/StabilityMatrix.Avalonia/Services/IModelImportService.cs index 4ac50341..1898a9eb 100644 --- a/StabilityMatrix.Avalonia/Services/IModelImportService.cs +++ b/StabilityMatrix.Avalonia/Services/IModelImportService.cs @@ -23,6 +23,7 @@ Task DoImport( CivitFile? selectedFile = null, IProgress? progress = null, Func? onImportComplete = null, + Func? onImportCanceled = null, Func? onImportFailed = null ); } diff --git a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs index e893f30d..1ebb8652 100644 --- a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs +++ b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs @@ -25,8 +25,7 @@ public class ModelDownloadLinkHandler( ICivitApi civitApi, INotificationService notificationService, ISettingsManager settingsManager, - IDownloadService downloadService, - ITrackedDownloadService trackedDownloadService + IModelImportService modelImportService ) : IAsyncDisposable, IModelDownloadLinkHandler { private IAsyncDisposable? uriHandlerSubscription; @@ -127,14 +126,16 @@ private void UriReceivedHandler(Uri receivedUri) x => x.Type == civitFileType && x.Metadata.Format == civitFormat ); - if (!string.IsNullOrWhiteSpace(fp) && Enum.TryParse(fp, out var fpType)) + if (!string.IsNullOrWhiteSpace(fp)) { - possibleFiles = possibleFiles?.Where(x => x.Metadata.Fp == fpType); + possibleFiles = possibleFiles?.Where( + x => x.Metadata.Fp != null && x.Metadata.Fp.Equals(fp, StringComparison.OrdinalIgnoreCase) + ); } - if (!string.IsNullOrWhiteSpace(size) && Enum.TryParse(size, out var modelSize)) + if (!string.IsNullOrWhiteSpace(size)) { - possibleFiles = possibleFiles?.Where(x => x.Metadata.Size == modelSize); + possibleFiles = possibleFiles?.Where(x => x.Metadata.Size != null && x.Metadata.Size == size); } possibleFiles = possibleFiles?.ToList(); @@ -159,93 +160,21 @@ private void UriReceivedHandler(Uri receivedUri) var rootModelsDirectory = new DirectoryPath(settingsManager.ModelsDirectory); var downloadDirectory = rootModelsDirectory.JoinDir( - selectedFile.Type == CivitFileType.VAE + selectedFile?.Type == CivitFileType.VAE ? SharedFolderType.VAE.GetStringValue() : model.Type.ConvertTo().GetStringValue() ); - downloadDirectory.Create(); - var downloadPath = downloadDirectory.JoinFile(selectedFile.Name); - - // Create tracked download - var download = trackedDownloadService.NewDownload(selectedFile.DownloadUrl, downloadPath); - - // Download model info and preview first - var saveCmInfoTask = SaveCmInfo(model, modelVersion, selectedFile, downloadDirectory); - var savePreviewImageTask = SavePreviewImage(modelVersion, downloadPath); - - Task.WaitAll([saveCmInfoTask, savePreviewImageTask]); - - var cmInfoPath = saveCmInfoTask.Result; - var previewImagePath = savePreviewImageTask.Result; - - // Add hash info - download.ExpectedHashSha256 = selectedFile.Hashes.SHA256; - - // Add files to cleanup list - download.ExtraCleanupFileNames.Add(cmInfoPath); - if (previewImagePath is not null) - { - download.ExtraCleanupFileNames.Add(previewImagePath); - } - - // Add hash context action - download.ContextAction = CivitPostDownloadContextAction.FromCivitFile(selectedFile); - - download.Start(); + var importTask = modelImportService.DoImport( + model, + downloadDirectory, + selectedVersion: modelVersion, + selectedFile: selectedFile + ); + importTask.Wait(); Dispatcher.UIThread.Post( () => notificationService.Show("Download Started", $"Downloading {selectedFile.Name}") ); } - - private static async Task SaveCmInfo( - CivitModel model, - CivitModelVersion modelVersion, - CivitFile modelFile, - DirectoryPath downloadDirectory - ) - { - var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Name); - var modelInfo = new ConnectedModelInfo(model, modelVersion, modelFile, DateTime.UtcNow); - - await modelInfo.SaveJsonToDirectory(downloadDirectory, modelFileName); - - var jsonName = $"{modelFileName}.cm-info.json"; - return downloadDirectory.JoinFile(jsonName); - } - - /// - /// Saves the preview image to the same directory as the model file - /// - /// - /// - /// The file path of the saved preview image - private async Task SavePreviewImage(CivitModelVersion modelVersion, FilePath modelFilePath) - { - // Skip if model has no images - if (modelVersion.Images == null || modelVersion.Images.Count == 0) - { - return null; - } - - var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image"); - if (image is null) - return null; - - var imageExtension = Path.GetExtension(image.Url).TrimStart('.'); - if (imageExtension is "jpg" or "jpeg" or "png") - { - var imageDownloadPath = modelFilePath.Directory!.JoinFile( - $"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" - ); - - var imageTask = downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); - await notificationService.TryAsync(imageTask, "Could not download preview image"); - - return imageDownloadPath; - } - - return null; - } } diff --git a/StabilityMatrix.Avalonia/Services/ModelImportService.cs b/StabilityMatrix.Avalonia/Services/ModelImportService.cs index 4d93d96c..452832af 100644 --- a/StabilityMatrix.Avalonia/Services/ModelImportService.cs +++ b/StabilityMatrix.Avalonia/Services/ModelImportService.cs @@ -77,6 +77,7 @@ public async Task DoImport( CivitFile? selectedFile = null, IProgress? progress = null, Func? onImportComplete = null, + Func? onImportCanceled = null, Func? onImportFailed = null ) { @@ -112,6 +113,10 @@ public async Task DoImport( // Folders might be missing if user didn't install any packages yet downloadFolder.Create(); + // Fix invalid chars in FileName + modelFile.Name = Path.GetInvalidFileNameChars() + .Aggregate(modelFile.Name, (current, c) => current.Replace(c, '_')); + var downloadPath = downloadFolder.JoinFile(modelFile.Name); // Download model info and preview first @@ -145,7 +150,7 @@ public async Task DoImport( } else if (e == ProgressState.Cancelled) { - // todo? + onImportCanceled?.Invoke().SafeFireAndForget(); } else if (e == ProgressState.Failed) { diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs index 6234aefa..c0110dad 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs @@ -40,6 +40,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel private readonly ServiceManager dialogFactory; private readonly INotificationService notificationService; private readonly IModelIndexService modelIndexService; + private readonly IModelImportService modelImportService; public Action? OnDownloadStart { get; set; } @@ -82,7 +83,8 @@ public CheckpointBrowserCardViewModel( ISettingsManager settingsManager, ServiceManager dialogFactory, INotificationService notificationService, - IModelIndexService modelIndexService + IModelIndexService modelIndexService, + IModelImportService modelImportService ) { this.downloadService = downloadService; @@ -91,6 +93,7 @@ IModelIndexService modelIndexService this.dialogFactory = dialogFactory; this.notificationService = notificationService; this.modelIndexService = modelIndexService; + this.modelImportService = modelImportService; // Update image when nsfw setting changes settingsManager.RegisterPropertyChangedHandler( @@ -263,56 +266,6 @@ private async Task ShowVersionDialog(CivitModel model) await DoImport(model, downloadPath, selectedVersion, selectedFile); } - private static async Task SaveCmInfo( - CivitModel model, - CivitModelVersion modelVersion, - CivitFile modelFile, - DirectoryPath downloadDirectory - ) - { - var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Name); - var modelInfo = new ConnectedModelInfo(model, modelVersion, modelFile, DateTime.UtcNow); - - await modelInfo.SaveJsonToDirectory(downloadDirectory, modelFileName); - - var jsonName = $"{modelFileName}.cm-info.json"; - return downloadDirectory.JoinFile(jsonName); - } - - /// - /// Saves the preview image to the same directory as the model file - /// - /// - /// - /// The file path of the saved preview image - private async Task SavePreviewImage(CivitModelVersion modelVersion, FilePath modelFilePath) - { - // Skip if model has no images - if (modelVersion.Images == null || modelVersion.Images.Count == 0) - { - return null; - } - - var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image"); - if (image is null) - return null; - - var imageExtension = Path.GetExtension(image.Url).TrimStart('.'); - if (imageExtension is "jpg" or "jpeg" or "png") - { - var imageDownloadPath = modelFilePath.Directory!.JoinFile( - $"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" - ); - - var imageTask = downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); - await notificationService.TryAsync(imageTask, "Could not download preview image"); - - return imageDownloadPath; - } - - return null; - } - private async Task DoImport( CivitModel model, DirectoryPath downloadFolder, @@ -356,45 +309,12 @@ private async Task DoImport( return; } - // Folders might be missing if user didn't install any packages yet - downloadFolder.Create(); - - var downloadPath = downloadFolder.JoinFile(modelFile.Name); - - // Download model info and preview first - var cmInfoPath = await SaveCmInfo(model, modelVersion, modelFile, downloadFolder); - var previewImagePath = await SavePreviewImage(modelVersion, downloadPath); - - // Create tracked download - var download = trackedDownloadService.NewDownload(modelFile.DownloadUrl, downloadPath); - - // Add hash info - download.ExpectedHashSha256 = modelFile.Hashes.SHA256; - - // Add files to cleanup list - download.ExtraCleanupFileNames.Add(cmInfoPath); - if (previewImagePath is not null) - { - download.ExtraCleanupFileNames.Add(previewImagePath); - } - - // Attach for progress updates - download.ProgressUpdate += (s, e) => - { - Value = e.Percentage; - if (e.Type == ProgressType.Hashing) - { - Text = $"Validating... {e.Percentage}%"; - } - else - { - Text = $"Downloading... {e.Percentage}%"; - } - }; - - download.ProgressStateChanged += (s, e) => - { - if (e == ProgressState.Success) + await modelImportService.DoImport( + model, + downloadFolder, + modelVersion, + modelFile, + onImportComplete: () => { Text = "Import Complete"; @@ -402,23 +322,24 @@ private async Task DoImport( Value = 100; CheckIfInstalled(); DelayedClearProgress(TimeSpan.FromMilliseconds(800)); - } - else if (e == ProgressState.Cancelled) + + return Task.CompletedTask; + }, + onImportCanceled: () => { Text = "Cancelled"; DelayedClearProgress(TimeSpan.FromMilliseconds(500)); - } - else if (e == ProgressState.Failed) + + return Task.CompletedTask; + }, + onImportFailed: () => { Text = "Download Failed"; DelayedClearProgress(TimeSpan.FromMilliseconds(800)); - } - }; - - // Add hash context action - download.ContextAction = CivitPostDownloadContextAction.FromCivitFile(modelFile); - download.Start(); + return Task.CompletedTask; + } + ); } private void DelayedClearProgress(TimeSpan delay) diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs index 5eeaeb6a..b91336c8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs @@ -34,6 +34,7 @@ public partial class RecommendedModelsViewModel : ContentDialogViewModelBase private readonly INotificationService notificationService; private readonly ITrackedDownloadService trackedDownloadService; private readonly IDownloadService downloadService; + private readonly IModelImportService modelImportService; public SourceCache CivitModels { get; } = new(p => p.ModelVersion.Id); public IObservableCollection Sd15Models { get; set; } = @@ -53,7 +54,8 @@ public RecommendedModelsViewModel( ISettingsManager settingsManager, INotificationService notificationService, ITrackedDownloadService trackedDownloadService, - IDownloadService downloadService + IDownloadService downloadService, + IModelImportService modelImportService ) { this.logger = logger; @@ -64,6 +66,7 @@ IDownloadService downloadService this.notificationService = notificationService; this.trackedDownloadService = trackedDownloadService; this.downloadService = downloadService; + this.modelImportService = modelImportService; CivitModels .Connect() @@ -142,87 +145,13 @@ private async Task DoImport() var downloadDirectory = rootModelsDirectory.JoinDir( model.CivitModel.Type.ConvertTo().GetStringValue() ); - // Folders might be missing if user didn't install any packages yet - downloadDirectory.Create(); - var downloadPath = downloadDirectory.JoinFile(modelFile.Name); - - // Download model info and preview first - var cmInfoPath = await SaveCmInfo( + await modelImportService.DoImport( model.CivitModel, + downloadDirectory, model.ModelVersion, - modelFile, - downloadDirectory + modelFile ); - var previewImagePath = await SavePreviewImage(model.ModelVersion, downloadPath); - - // Create tracked download - var download = trackedDownloadService.NewDownload(modelFile.DownloadUrl, downloadPath); - - // Add hash info - download.ExpectedHashSha256 = modelFile.Hashes.SHA256; - - // Add files to cleanup list - download.ExtraCleanupFileNames.Add(cmInfoPath); - if (previewImagePath is not null) - { - download.ExtraCleanupFileNames.Add(previewImagePath); - } - - // Add hash context action - download.ContextAction = CivitPostDownloadContextAction.FromCivitFile(modelFile); - - download.Start(); } } - - private static async Task SaveCmInfo( - CivitModel model, - CivitModelVersion modelVersion, - CivitFile modelFile, - DirectoryPath downloadDirectory - ) - { - var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Name); - var modelInfo = new ConnectedModelInfo(model, modelVersion, modelFile, DateTime.UtcNow); - - await modelInfo.SaveJsonToDirectory(downloadDirectory, modelFileName); - - var jsonName = $"{modelFileName}.cm-info.json"; - return downloadDirectory.JoinFile(jsonName); - } - - /// - /// Saves the preview image to the same directory as the model file - /// - /// - /// - /// The file path of the saved preview image - private async Task SavePreviewImage(CivitModelVersion modelVersion, FilePath modelFilePath) - { - // Skip if model has no images - if (modelVersion.Images == null || modelVersion.Images.Count == 0) - { - return null; - } - - var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image"); - if (image is null) - return null; - - var imageExtension = Path.GetExtension(image.Url).TrimStart('.'); - if (imageExtension is "jpg" or "jpeg" or "png") - { - var imageDownloadPath = modelFilePath.Directory!.JoinFile( - $"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" - ); - - var imageTask = downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); - await notificationService.TryAsync(imageTask, "Could not download preview image"); - - return imageDownloadPath; - } - - return null; - } } diff --git a/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs b/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs index 88337b0d..4417fc58 100644 --- a/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs +++ b/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs @@ -8,6 +8,15 @@ public enum CivitBaseModelType { All, + [StringValue("AuraFlow")] + AuraFlow, + + [StringValue("Flux.1 S")] + Flux1S, + + [StringValue("Flux.1 D")] + Flux1D, + [StringValue("PixArt a")] PixArtA, diff --git a/StabilityMatrix.Core/Models/Api/CivitFileMetadata.cs b/StabilityMatrix.Core/Models/Api/CivitFileMetadata.cs index 04846ff6..81d1e8c0 100644 --- a/StabilityMatrix.Core/Models/Api/CivitFileMetadata.cs +++ b/StabilityMatrix.Core/Models/Api/CivitFileMetadata.cs @@ -5,11 +5,11 @@ namespace StabilityMatrix.Core.Models.Api; public class CivitFileMetadata { [JsonPropertyName("fp")] - public CivitModelFpType? Fp { get; set; } - + public string? Fp { get; set; } + [JsonPropertyName("size")] - public CivitModelSize? Size { get; set; } - + public string? Size { get; set; } + [JsonPropertyName("format")] public CivitModelFormat? Format { get; set; } } diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 6e1a83a2..6c24b081 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -67,7 +67,8 @@ IPrerequisiteHelper prerequisiteHelper [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" }, [SharedFolderType.InvokeIpAdapters15] = new[] { "models/controlnet/DiffusersIpAdapters" }, [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/controlnet/DiffusersIpAdaptersXL" }, - [SharedFolderType.SVD] = new[] { "models/svd" } + [SharedFolderType.SVD] = new[] { "models/svd" }, + [SharedFolderType.CLIP] = new[] { "models/text_encoder" } }; public override Dictionary>? SharedOutputFolders => diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index f6def17b..086b4e41 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -124,15 +124,9 @@ public override async Task InstallPackage( await venvRunner .PipInstall( - new PipInstallArgs() - .WithTorch("==2.1.2") - .WithTorchVision("==0.16.2") - .WithXFormers("==0.0.23.post1") - .WithTorchExtraIndex("cu121") - .WithParsedFromRequirementsTxt( - await requirements.ReadAllTextAsync().ConfigureAwait(false), - excludePattern: "torch" - ), + new PipInstallArgs().WithParsedFromRequirementsTxt( + await requirements.ReadAllTextAsync().ConfigureAwait(false) + ), onConsoleOutput ) .ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index 936c6c31..08f91343 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -37,19 +37,7 @@ IPrerequisiteHelper prerequisiteHelper public override string MainBranch => "main"; public override bool ShouldIgnoreReleases => true; public override IPackageExtensionManager ExtensionManager => null; - public override string OutputFolderName => "output"; public override PackageDifficulty InstallerSortOrder => PackageDifficulty.ReallyRecommended; - public override Dictionary>? SharedOutputFolders => - new() - { - [SharedOutputType.Extras] = new[] { "output/extras-images" }, - [SharedOutputType.Saved] = new[] { "log/images" }, - [SharedOutputType.Img2Img] = new[] { "output/img2img-images" }, - [SharedOutputType.Text2Img] = new[] { "output/txt2img-images" }, - [SharedOutputType.Img2ImgGrids] = new[] { "output/img2img-grids" }, - [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" }, - [SharedOutputType.SVD] = new[] { "output/svd" } - }; public override List LaunchOptions => [ diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs index 65f6a75b..6d0b1651 100644 --- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs +++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs @@ -377,7 +377,35 @@ private Task SetupModelFoldersConfig(DirectoryPath installDirectory) if (settingsExists) { var section = FDSUtility.ReadFile(settingsPath); - existingSettings.Load(section); + var paths = section.GetSection("Paths"); + paths.Set("ModelRoot", settingsManager.ModelsDirectory); + paths.Set( + "SDModelFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.StableDiffusion.ToString()) + ); + paths.Set( + "SDLoraFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.Lora.ToString()) + ); + paths.Set( + "SDVAEFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.VAE.ToString()) + ); + paths.Set( + "SDEmbeddingFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.TextualInversion.ToString()) + ); + paths.Set( + "SDControlNetsFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.ControlNet.ToString()) + ); + paths.Set( + "SDClipVisionFolder", + Path.Combine(settingsManager.ModelsDirectory, SharedFolderType.InvokeClipVision.ToString()) + ); + section.Set("Paths", paths); + section.SaveToFile(settingsPath); + return Task.CompletedTask; } existingSettings.Paths = new StableSwarmSettings.PathsData