From 9472c24238672a5439e26a16868bf7d88e45ce14 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 13 Jun 2023 16:15:49 -0400 Subject: [PATCH] Add configurable model path to settings --- StabilityMatrix/Helper/SettingsManager.cs | 15 ++++++-- StabilityMatrix/Models/Settings.cs | 16 +++++++++ StabilityMatrix/Models/SharedFolders.cs | 34 ++++++++++++++----- .../CheckpointBrowserCardViewModel.cs | 6 ++-- .../ViewModels/CheckpointBrowserViewModel.cs | 6 ++-- .../ViewModels/CheckpointManagerViewModel.cs | 14 +++++--- .../ViewModels/TextToImageViewModel.cs | 6 ++-- 7 files changed, 76 insertions(+), 21 deletions(-) diff --git a/StabilityMatrix/Helper/SettingsManager.cs b/StabilityMatrix/Helper/SettingsManager.cs index 37657019..5a1b7f99 100644 --- a/StabilityMatrix/Helper/SettingsManager.cs +++ b/StabilityMatrix/Helper/SettingsManager.cs @@ -17,8 +17,6 @@ public class SettingsManager : ISettingsManager Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StabilityMatrix", SettingsFileName); private readonly string? originalEnvPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); - - public IA3WebApi? A3WebApi { get; set; } public Settings Settings { get; private set; } = new(); @@ -189,6 +187,18 @@ public class SettingsManager : ISettingsManager SaveSettings(); } + public void SetModelsDirectory(string? directory) + { + Settings.ModelsDirectory = directory; + SaveSettings(); + } + + public void SetFirstLaunchSetupComplete(bool value) + { + Settings.FirstLaunchSetupComplete = value; + SaveSettings(); + } + private void LoadSettings() { var settingsContent = File.ReadAllText(SettingsPath); @@ -196,6 +206,7 @@ public class SettingsManager : ISettingsManager { Converters = { new JsonStringEnumConverter() } })!; + Settings.SetDefaults(); } private void SaveSettings() diff --git a/StabilityMatrix/Models/Settings.cs b/StabilityMatrix/Models/Settings.cs index 098e9761..c28f669f 100644 --- a/StabilityMatrix/Models/Settings.cs +++ b/StabilityMatrix/Models/Settings.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Linq; using Wpf.Ui.Controls.Window; @@ -7,6 +10,7 @@ namespace StabilityMatrix.Models; public class Settings { + public bool FirstLaunchSetupComplete { get; set; } public string? Theme { get; set; } public WindowBackdropType? WindowBackdropType { get; set; } public List InstalledPackages { get; set; } = new(); @@ -17,6 +21,18 @@ public class Settings public string? WebApiHost { get; set; } public string? WebApiPort { get; set; } + [NotNull] + public string? ModelsDirectory { get; set; } + + /// + /// Sets default values for settings + /// + [MemberNotNull(nameof(ModelsDirectory))] + public void SetDefaults() + { + ModelsDirectory ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StabilityMatrix", "Models"); + } + public InstalledPackage? GetActiveInstalledPackage() { return InstalledPackages.FirstOrDefault(x => x.Id == ActiveInstalledPackage); diff --git a/StabilityMatrix/Models/SharedFolders.cs b/StabilityMatrix/Models/SharedFolders.cs index 54be07e0..4e982c9a 100644 --- a/StabilityMatrix/Models/SharedFolders.cs +++ b/StabilityMatrix/Models/SharedFolders.cs @@ -3,23 +3,21 @@ using System.IO; using NCode.ReparsePoints; using NLog; using StabilityMatrix.Extensions; +using StabilityMatrix.Helper; using StabilityMatrix.Models.Packages; namespace StabilityMatrix.Models; public class SharedFolders : ISharedFolders { - private const string SharedFoldersName = "Models"; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static string SharedFoldersPath = - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StabilityMatrix", - SharedFoldersName); + private readonly ISettingsManager settingsManager; - public static string SharedFolderTypeToName(SharedFolderType folderType) + public SharedFolders(ISettingsManager settingsManager) { - return Enum.GetName(typeof(SharedFolderType), folderType)!; + this.settingsManager = settingsManager; } - + public void SetupLinksForPackage(BasePackage basePackage, string installPath) { var sharedFolders = basePackage.SharedFolders; @@ -31,7 +29,7 @@ public class SharedFolders : ISharedFolders var provider = ReparsePointFactory.Provider; foreach (var (folderType, relativePath) in sharedFolders) { - var source = Path.GetFullPath(Path.Combine(SharedFoldersPath, folderType.GetStringValue())); + var source = Path.Combine(settingsManager.Settings.ModelsDirectory, folderType.GetStringValue()); var destination = Path.GetFullPath(Path.Combine(installPath, relativePath)); // Create source folder if it doesn't exist if (!Directory.Exists(source)) @@ -64,4 +62,24 @@ public class SharedFolders : ISharedFolders provider.CreateLink(destination, source, LinkType.Junction); } } + + public void RemoveLinksForPackage(BasePackage package, string installPath) + { + var sharedFolders = package.SharedFolders; + if (sharedFolders == null) + { + return; + } + + foreach (var (_, relativePath) in sharedFolders) + { + var destination = Path.GetFullPath(Path.Combine(installPath, relativePath)); + // Delete the destination folder if it exists + if (Directory.Exists(destination)) + { + Logger.Info($"Deleting junction target {destination}"); + Directory.Delete(destination, false); + } + } + } } diff --git a/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs b/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs index 31a7a4f5..05e2c169 100644 --- a/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs +++ b/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs @@ -20,16 +20,18 @@ public partial class CheckpointBrowserCardViewModel : ProgressViewModel { private readonly IDownloadService downloadService; private readonly ISnackbarService snackbarService; + private readonly ISettingsManager settingsManager; public CivitModel CivitModel { get; init; } public BitmapImage CardImage { get; init; } public override Visibility ProgressVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed; public override Visibility TextVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed; - public CheckpointBrowserCardViewModel(CivitModel civitModel, IDownloadService downloadService, ISnackbarService snackbarService) + public CheckpointBrowserCardViewModel(CivitModel civitModel, IDownloadService downloadService, ISnackbarService snackbarService, ISettingsManager settingsManager) { this.downloadService = downloadService; this.snackbarService = snackbarService; + this.settingsManager = settingsManager; CivitModel = civitModel; if (civitModel.ModelVersions.Any() && civitModel.ModelVersions[0].Images.Any()) @@ -62,7 +64,7 @@ public partial class CheckpointBrowserCardViewModel : ProgressViewModel var latestModelFile = latestVersion.Files[0]; var fileExpectedSha256 = latestModelFile.Hashes.SHA256; - var downloadFolder = Path.Combine(SharedFolders.SharedFoldersPath, + var downloadFolder = Path.Combine(settingsManager.Settings.ModelsDirectory, model.Type.ConvertTo().GetStringValue()); // Folders might be missing if user didn't install any packages yet Directory.CreateDirectory(downloadFolder); diff --git a/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs b/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs index 3dc65ce5..48a2948b 100644 --- a/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs +++ b/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs @@ -21,6 +21,7 @@ public partial class CheckpointBrowserViewModel : ObservableObject private readonly ICivitApi civitApi; private readonly IDownloadService downloadService; private readonly ISnackbarService snackbarService; + private readonly ISettingsManager settingsManager; private const int MaxModelsPerPage = 14; [ObservableProperty] private string? searchQuery; @@ -41,11 +42,12 @@ public partial class CheckpointBrowserViewModel : ObservableObject public IEnumerable AllSortModes => Enum.GetValues(typeof(CivitSortMode)).Cast(); public IEnumerable AllModelTypes => Enum.GetValues(typeof(CivitModelType)).Cast(); - public CheckpointBrowserViewModel(ICivitApi civitApi, IDownloadService downloadService, ISnackbarService snackbarService) + public CheckpointBrowserViewModel(ICivitApi civitApi, IDownloadService downloadService, ISnackbarService snackbarService, ISettingsManager settingsManager) { this.civitApi = civitApi; this.downloadService = downloadService; this.snackbarService = snackbarService; + this.settingsManager = settingsManager; SelectedPeriod = CivitPeriod.Month; SortMode = CivitSortMode.HighestRated; @@ -90,7 +92,7 @@ public partial class CheckpointBrowserViewModel : ObservableObject CanGoToPreviousPage = CurrentPageNumber > 1; CanGoToNextPage = CurrentPageNumber < TotalPages; ModelCards = new ObservableCollection(models.Items.Select( - m => new CheckpointBrowserCardViewModel(m, downloadService, snackbarService))); + m => new CheckpointBrowserCardViewModel(m, downloadService, snackbarService, settingsManager))); Logger.Debug($"Found {models.Items.Length} models"); } catch (ApiException e) diff --git a/StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs b/StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs index d43bf014..a4261c04 100644 --- a/StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs +++ b/StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using NLog; +using StabilityMatrix.Helper; using StabilityMatrix.Models; namespace StabilityMatrix.ViewModels; @@ -13,27 +14,30 @@ public partial class CheckpointManagerViewModel : ObservableObject { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly ISharedFolders sharedFolders; + private readonly ISettingsManager settingsManager; public ObservableCollection CheckpointFolders { get; set; } = new(); - public CheckpointManagerViewModel(ISharedFolders sharedFolders) + public CheckpointManagerViewModel(ISharedFolders sharedFolders, ISettingsManager settingsManager) { this.sharedFolders = sharedFolders; + this.settingsManager = settingsManager; } public async Task OnLoaded() { + var modelsDirectory = settingsManager.Settings.ModelsDirectory; // Get all folders within the shared folder root - if (string.IsNullOrWhiteSpace(SharedFolders.SharedFoldersPath)) + if (string.IsNullOrWhiteSpace(modelsDirectory)) { return; } // Skip if the shared folder root doesn't exist - if (!Directory.Exists(SharedFolders.SharedFoldersPath)) + if (!Directory.Exists(modelsDirectory)) { - Logger.Debug($"Skipped shared folder index - {SharedFolders.SharedFoldersPath} doesn't exist"); + Logger.Debug($"Skipped shared folder index - {modelsDirectory} doesn't exist"); return; } - var folders = Directory.GetDirectories(SharedFolders.SharedFoldersPath); + var folders = Directory.GetDirectories(modelsDirectory); CheckpointFolders.Clear(); diff --git a/StabilityMatrix/ViewModels/TextToImageViewModel.cs b/StabilityMatrix/ViewModels/TextToImageViewModel.cs index f0e6542f..05790b40 100644 --- a/StabilityMatrix/ViewModels/TextToImageViewModel.cs +++ b/StabilityMatrix/ViewModels/TextToImageViewModel.cs @@ -24,6 +24,7 @@ public partial class TextToImageViewModel : ObservableObject private readonly IA3WebApiManager a3WebApiManager; private readonly ISnackbarService snackbarService; private readonly PageContentDialogService pageContentDialogService; + private readonly ISettingsManager settingsManager; private AsyncDispatcherTimer? progressQueryTimer; [ObservableProperty] @@ -72,12 +73,13 @@ public partial class TextToImageViewModel : ObservableObject "DPM++ 2M Karras" }; - public TextToImageViewModel(IA3WebApiManager a3WebApiManager, ILogger logger, ISnackbarService snackbarService, PageContentDialogService pageContentDialogService) + public TextToImageViewModel(IA3WebApiManager a3WebApiManager, ILogger logger, ISnackbarService snackbarService, PageContentDialogService pageContentDialogService, ISettingsManager settingsManager) { this.logger = logger; this.a3WebApiManager = a3WebApiManager; this.snackbarService = snackbarService; this.pageContentDialogService = pageContentDialogService; + this.settingsManager = settingsManager; positivePromptText = "Positive"; negativePromptText = "Negative"; generationSteps = 10; @@ -95,7 +97,7 @@ public partial class TextToImageViewModel : ObservableObject } // Set the diffusion checkpoint folder - var sdModelsDir = Path.Join(SharedFolders.SharedFoldersPath, SharedFolderType.StableDiffusion.GetStringValue()); + var sdModelsDir = Path.Join(settingsManager.Settings.ModelsDirectory, SharedFolderType.StableDiffusion.GetStringValue()); if (!Directory.Exists(sdModelsDir)) { logger.LogWarning("Skipped model folder index - {SdModelsDir} does not exist", sdModelsDir);