From abe631df134a1bb8b7e71ef2479b152cc06b69e9 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 21 Jan 2024 23:58:48 -0800 Subject: [PATCH] added non-blocking package runner option to show new dialog that doesnt exist yet also fixed env vars not being editable in release mode also added api stuff for recommended models dialog (that doesnt exist yet) --- .../DesignData/DesignData.cs | 11 +- .../StabilityMatrix.Avalonia.csproj | 1 + .../Dialogs/NewOneClickInstallViewModel.cs | 104 +++++++++++++++++- .../Dialogs/RecommendedModelsViewModel.cs | 14 +++ .../PackageInstallProgressItemViewModel.cs | 22 +++- .../Progress/ProgressManagerViewModel.cs | 19 +++- .../Dialogs/NewOneClickInstallDialog.axaml | 6 +- StabilityMatrix.Core/Api/ICivitApi.cs | 7 +- StabilityMatrix.Core/Api/ILykosAuthApi.cs | 10 +- StabilityMatrix.Core/Helper/EventManager.cs | 16 ++- .../Api/Lykos/GetRecommendedModelsResponse.cs | 7 ++ 11 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs create mode 100644 StabilityMatrix.Core/Models/Api/Lykos/GetRecommendedModelsResponse.cs diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index 72b56c78..1ae54ac7 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -404,7 +404,8 @@ public static class DesignData new PackageModificationRunner { CurrentProgress = new ProgressReport(0.5f, "Installing package...") - } + }, + new List() ) } ); @@ -493,6 +494,14 @@ public static class DesignData { vm.AddExtensions( [ + new PackageExtension + { + Author = "123", + Title = "Cool Extension", + Description = "This is an interesting extension", + Reference = new Uri("https://github.com/LykosAI/StabilityMatrix"), + Files = [new Uri("https://github.com/LykosAI/StabilityMatrix")] + }, new PackageExtension { Author = "123", diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 1e6b71d0..cd00b7c2 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -33,6 +33,7 @@ + diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs index f22cfeb2..5a9ea21e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.ComponentModel; +using System.IO; using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; @@ -7,11 +9,19 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DynamicData; using DynamicData.Binding; +using Microsoft.Extensions.Logging; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Extensions; +using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Factory; +using StabilityMatrix.Core.Models; +using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Models.PackageModification; using StabilityMatrix.Core.Models.Packages; +using StabilityMatrix.Core.Python; +using StabilityMatrix.Core.Services; namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; @@ -19,6 +29,10 @@ namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; [ManagedService] public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase { + private readonly ISettingsManager settingsManager; + private readonly IPrerequisiteHelper prerequisiteHelper; + private readonly ILogger logger; + private readonly IPyRunner pyRunner; public SourceCache AllPackagesCache { get; } = new(p => p.Author + p.Name); public IObservableCollection ShownPackages { get; set; } = @@ -27,8 +41,19 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase [ObservableProperty] private bool showIncompatiblePackages; - public NewOneClickInstallViewModel(IPackageFactory packageFactory) + public NewOneClickInstallViewModel( + IPackageFactory packageFactory, + ISettingsManager settingsManager, + IPrerequisiteHelper prerequisiteHelper, + ILogger logger, + IPyRunner pyRunner + ) { + this.settingsManager = settingsManager; + this.prerequisiteHelper = prerequisiteHelper; + this.logger = logger; + this.pyRunner = pyRunner; + var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages) .Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages)) .AsObservable(); @@ -50,12 +75,83 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase } [RelayCommand] - private async Task InstallComfyForInference() + private Task InstallComfyForInference() { var comfyPackage = ShownPackages.FirstOrDefault(x => x is ComfyUI); - if (comfyPackage != null) + return comfyPackage != null ? InstallPackage(comfyPackage) : Task.CompletedTask; + } + + [RelayCommand] + private async Task InstallPackage(BasePackage selectedPackage) + { + var steps = new List + { + new SetPackageInstallingStep(settingsManager, selectedPackage.Name), + new SetupPrerequisitesStep(prerequisiteHelper, pyRunner) + }; + + // get latest version & download & install + var installLocation = Path.Combine(settingsManager.LibraryDir, "Packages", selectedPackage.Name); + if (Directory.Exists(installLocation)) + { + var installPath = new DirectoryPath(installLocation); + await installPath.DeleteVerboseAsync(logger); + } + + var downloadVersion = await selectedPackage.GetLatestVersion(); + var installedVersion = new InstalledPackageVersion { IsPrerelease = false }; + + if (selectedPackage.ShouldIgnoreReleases) { - // install + installedVersion.InstalledBranch = downloadVersion.BranchName; + installedVersion.InstalledCommitSha = downloadVersion.CommitHash; } + else + { + installedVersion.InstalledReleaseVersion = downloadVersion.VersionTag; + } + + var torchVersion = selectedPackage.GetRecommendedTorchVersion(); + var recommendedSharedFolderMethod = selectedPackage.RecommendedSharedFolderMethod; + + var downloadStep = new DownloadPackageVersionStep(selectedPackage, installLocation, downloadVersion); + steps.Add(downloadStep); + + var installStep = new InstallPackageStep( + selectedPackage, + torchVersion, + recommendedSharedFolderMethod, + downloadVersion, + installLocation + ); + steps.Add(installStep); + + var setupModelFoldersStep = new SetupModelFoldersStep( + selectedPackage, + recommendedSharedFolderMethod, + installLocation + ); + steps.Add(setupModelFoldersStep); + + var installedPackage = new InstalledPackage + { + DisplayName = selectedPackage.DisplayName, + LibraryPath = Path.Combine("Packages", selectedPackage.Name), + Id = Guid.NewGuid(), + PackageName = selectedPackage.Name, + Version = installedVersion, + LaunchCommand = selectedPackage.LaunchCommand, + LastUpdateCheck = DateTimeOffset.Now, + PreferredTorchVersion = torchVersion, + PreferredSharedFolderMethod = recommendedSharedFolderMethod + }; + + var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, installedPackage); + steps.Add(addInstalledPackageStep); + + var runner = new PackageModificationRunner { ShowDialogOnStart = true, HideCloseButton = true, }; + EventManager.Instance.OnAddPackageInstallWithoutBlocking(this, runner, steps); + + OnPrimaryButtonClick(); } } diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs new file mode 100644 index 00000000..2a129e57 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Core.Api; + +namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; + +public class RecommendedModelsViewModel(ILykosAuthApi lykosApi, ICivitApi civitApi) + : ContentDialogViewModelBase +{ + public override async Task OnLoadedAsync() + { + var recommendedModels = await lykosApi.GetRecommendedModels(); + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs index 9cb0eb3d..7148378f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using AsyncAwaitBestPractices; +using Avalonia.Controls; using Avalonia.Threading; using FluentAvalonia.UI.Controls; using StabilityMatrix.Avalonia.Controls; @@ -15,28 +18,37 @@ namespace StabilityMatrix.Avalonia.ViewModels.Progress; public class PackageInstallProgressItemViewModel : ProgressItemViewModelBase { private readonly IPackageModificationRunner packageModificationRunner; + private readonly IReadOnlyList? packageSteps; private BetterContentDialog? dialog; public PackageInstallProgressItemViewModel( IPackageModificationRunner packageModificationRunner, - bool hideCloseButton = false + IReadOnlyList? packageSteps = null ) { this.packageModificationRunner = packageModificationRunner; + this.packageSteps = packageSteps; + Id = packageModificationRunner.Id; Name = packageModificationRunner.CurrentStep?.ProgressTitle; Progress.Value = packageModificationRunner.CurrentProgress.Percentage; Progress.Text = packageModificationRunner.ConsoleOutput.LastOrDefault(); Progress.IsIndeterminate = packageModificationRunner.CurrentProgress.IsIndeterminate; - Progress.HideCloseButton = hideCloseButton; + Progress.HideCloseButton = packageModificationRunner.HideCloseButton; + + if (Design.IsDesignMode) + return; Progress.Console.StartUpdates(); - Progress.Console.Post( - string.Join(Environment.NewLine, packageModificationRunner.ConsoleOutput) - ); + Progress.Console.Post(string.Join(Environment.NewLine, packageModificationRunner.ConsoleOutput)); packageModificationRunner.ProgressChanged += PackageModificationRunnerOnProgressChanged; + + if (packageSteps is { Count: > 0 }) + { + packageModificationRunner.ExecuteSteps(packageSteps).SafeFireAndForget(); + } } private void PackageModificationRunnerOnProgressChanged(object? sender, ProgressReport e) diff --git a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs index 90c9d5cc..671f6cf6 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Progress/ProgressManagerViewModel.cs @@ -57,8 +57,9 @@ public partial class ProgressManagerViewModel : PageViewModelBase // Attach to the event trackedDownloadService.DownloadAdded += TrackedDownloadService_OnDownloadAdded; - EventManager.Instance.PackageInstallProgressAdded += InstanceOnPackageInstallProgressAdded; EventManager.Instance.ToggleProgressFlyout += (_, _) => IsOpen = !IsOpen; + EventManager.Instance.AddPackageInstallWithoutBlocking += InstanceOnAddPackageInstallWithoutBlocking; + EventManager.Instance.PackageInstallProgressAdded += InstanceOnPackageInstallProgressAdded; } private void InstanceOnPackageInstallProgressAdded(object? sender, IPackageModificationRunner runner) @@ -66,6 +67,12 @@ public partial class ProgressManagerViewModel : PageViewModelBase AddPackageInstall(runner).SafeFireAndForget(); } + private Task InstanceOnAddPackageInstallWithoutBlocking( + object? sender, + IPackageModificationRunner runner, + IReadOnlyList steps + ) => AddPackageInstall(runner, steps); + private void TrackedDownloadService_OnDownloadAdded(object? sender, TrackedDownload e) { var vm = new DownloadProgressItemViewModel(e); @@ -165,17 +172,17 @@ public partial class ProgressManagerViewModel : PageViewModelBase } } - private Task AddPackageInstall(IPackageModificationRunner packageModificationRunner) + private Task AddPackageInstall( + IPackageModificationRunner packageModificationRunner, + IReadOnlyList? steps = null + ) { if (ProgressItems.Any(vm => vm.Id == packageModificationRunner.Id)) { return Task.CompletedTask; } - var vm = new PackageInstallProgressItemViewModel( - packageModificationRunner, - packageModificationRunner.HideCloseButton - ); + var vm = new PackageInstallProgressItemViewModel(packageModificationRunner, steps); ProgressItems.Add(vm); return packageModificationRunner.ShowDialogOnStart ? vm.ShowProgressDialog() : Task.CompletedTask; diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml index 324ff96c..eb829d80 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/NewOneClickInstallDialog.axaml @@ -16,8 +16,8 @@ x:Class="StabilityMatrix.Avalonia.Views.Dialogs.NewOneClickInstallDialog"> - - +