Browse Source

Added SharedFolderMethod & TorchVersion options to Advanced Install Options

pull/117/head
JT 1 year ago
parent
commit
bb686a581f
  1. 6
      StabilityMatrix.Avalonia/App.axaml.cs
  2. 6
      StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs
  3. 26
      StabilityMatrix.Avalonia/ViewModels/Base/ContentDialogProgressViewModelBase.cs
  4. 3
      StabilityMatrix.Avalonia/ViewModels/Base/ContentDialogViewModelBase.cs
  5. 1
      StabilityMatrix.Avalonia/ViewModels/Dialogs/EnvVarsViewModel.cs
  6. 222
      StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs
  7. 1
      StabilityMatrix.Avalonia/ViewModels/Dialogs/LaunchOptionsViewModel.cs
  8. 17
      StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs
  9. 8
      StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs
  10. 60
      StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageModificationDialogViewModel.cs
  11. 1
      StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs
  12. 1
      StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
  13. 1
      StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs
  14. 3
      StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs
  15. 7
      StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs
  16. 33
      StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
  17. 234
      StabilityMatrix.Avalonia/Views/Dialogs/InstallerDialog.axaml
  18. 41
      StabilityMatrix.Avalonia/Views/Dialogs/PackageModificationDialog.axaml
  19. 49
      StabilityMatrix.Avalonia/Views/Dialogs/PackageModificationDialog.axaml.cs
  20. 5
      StabilityMatrix.Core/Helper/SharedFolders.cs
  21. 15
      StabilityMatrix.Core/Models/InstalledPackage.cs
  22. 26
      StabilityMatrix.Core/Models/PackageModification/AddInstalledPackageStep.cs
  23. 24
      StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs
  24. 12
      StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs
  25. 33
      StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs
  26. 31
      StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs
  27. 9
      StabilityMatrix.Core/Models/PackageModification/PackageStep.cs
  28. 28
      StabilityMatrix.Core/Models/PackageModification/SetupModelFoldersStep.cs
  29. 43
      StabilityMatrix.Core/Models/PackageModification/SetupPrerequisitesStep.cs
  30. 1
      StabilityMatrix.Core/Models/PackageVersion.cs
  31. 97
      StabilityMatrix.Core/Models/Packages/A3WebUI.cs
  32. 45
      StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
  33. 93
      StabilityMatrix.Core/Models/Packages/BasePackage.cs
  34. 124
      StabilityMatrix.Core/Models/Packages/ComfyUI.cs
  35. 13
      StabilityMatrix.Core/Models/Packages/DankDiffusion.cs
  36. 68
      StabilityMatrix.Core/Models/Packages/Fooocus.cs
  37. 120
      StabilityMatrix.Core/Models/Packages/InvokeAI.cs
  38. 26
      StabilityMatrix.Core/Models/Packages/UnknownPackage.cs
  39. 151
      StabilityMatrix.Core/Models/Packages/VladAutomatic.cs
  40. 34
      StabilityMatrix.Core/Models/Packages/VoltaML.cs
  41. 2
      StabilityMatrix.Core/Models/SharedFolderMethod.cs
  42. 11
      StabilityMatrix.Core/Models/TorchVersion.cs
  43. 1
      StabilityMatrix.Core/StabilityMatrix.Core.csproj

6
StabilityMatrix.Avalonia/App.axaml.cs

@ -53,6 +53,7 @@ using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Helper.Factory;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Configs;
using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Models.Settings;
using StabilityMatrix.Core.Python;
@ -322,6 +323,7 @@ public sealed class App : Application
services.AddSingleton<BasePackage, VoltaML>();
services.AddSingleton<BasePackage, InvokeAI>();
services.AddSingleton<BasePackage, Fooocus>();
//services.AddSingleton<BasePackage, KohyaSs>();
}
private static IServiceCollection ConfigureServices()
@ -346,6 +348,7 @@ public sealed class App : Application
services.AddSingleton<IPyRunner, PyRunner>();
services.AddSingleton<IUpdateHelper, UpdateHelper>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IPackageModificationRunner, PackageModificationRunner>();
services.AddSingleton<ITrackedDownloadService, TrackedDownloadService>();
services.AddSingleton<IDisposable>(provider =>
@ -391,7 +394,8 @@ public sealed class App : Application
// if (string.IsNullOrWhiteSpace(githubApiKey))
// return client;
//
// client.Credentials = new Credentials(githubApiKey);
// client.Credentials =
// new Credentials("");
return client;
});

6
StabilityMatrix.Avalonia/Controls/BetterContentDialog.cs

@ -156,6 +156,12 @@ public class BetterContentDialog : ContentDialog
viewModel.SecondaryButtonClick += OnDialogButtonClick;
viewModel.CloseButtonClick += OnDialogButtonClick;
}
else if ((Content as Control)?.DataContext is ContentDialogProgressViewModelBase progressViewModel)
{
progressViewModel.PrimaryButtonClick += OnDialogButtonClick;
progressViewModel.SecondaryButtonClick += OnDialogButtonClick;
progressViewModel.CloseButtonClick += OnDialogButtonClick;
}
// If commands provided, bind OnCanExecuteChanged to hide buttons
// otherwise link visibility to IsEnabled

26
StabilityMatrix.Avalonia/ViewModels/Base/ContentDialogProgressViewModelBase.cs

@ -0,0 +1,26 @@
using System;
using FluentAvalonia.UI.Controls;
namespace StabilityMatrix.Avalonia.ViewModels.Base;
public class ContentDialogProgressViewModelBase : ProgressViewModel
{
public event EventHandler<ContentDialogResult>? PrimaryButtonClick;
public event EventHandler<ContentDialogResult>? SecondaryButtonClick;
public event EventHandler<ContentDialogResult>? CloseButtonClick;
public virtual void OnPrimaryButtonClick()
{
PrimaryButtonClick?.Invoke(this, ContentDialogResult.Primary);
}
public virtual void OnSecondaryButtonClick()
{
SecondaryButtonClick?.Invoke(this, ContentDialogResult.Secondary);
}
public virtual void OnCloseButtonClick()
{
CloseButtonClick?.Invoke(this, ContentDialogResult.None);
}
}

3
StabilityMatrix.Avalonia/ViewModels/Dialogs/ContentDialogViewModelBase.cs → StabilityMatrix.Avalonia/ViewModels/Base/ContentDialogViewModelBase.cs

@ -1,8 +1,7 @@
using System;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.ViewModels.Base;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
namespace StabilityMatrix.Avalonia.ViewModels.Base;
public class ContentDialogViewModelBase : ViewModelBase
{

1
StabilityMatrix.Avalonia/ViewModels/Dialogs/EnvVarsViewModel.cs

@ -4,6 +4,7 @@ using System.Diagnostics;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;

222
StabilityMatrix.Avalonia/ViewModels/Dialogs/InstallerViewModel.cs

@ -17,10 +17,12 @@ using FluentAvalonia.UI.Controls;
using NLog;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Factory;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
@ -49,6 +51,13 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
[ObservableProperty] private string? releaseNotes;
[ObservableProperty] private string latestVersionText = string.Empty;
[ObservableProperty] private bool isAdvancedMode;
[ObservableProperty] private bool showDuplicateWarning;
[ObservableProperty] private string? installName;
[ObservableProperty] private SharedFolderMethod selectedSharedFolderMethod;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ShowTorchVersionOptions))]
private TorchVersion selectedTorchVersion;
// Version types (release or commit)
[ObservableProperty]
@ -60,20 +69,19 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
[NotifyPropertyChangedFor(nameof(IsReleaseModeAvailable))]
private PackageVersionType availableVersionTypes =
PackageVersionType.GithubRelease | PackageVersionType.Commit;
public string ReleaseLabelText => IsReleaseMode ? "Version" : "Branch";
public bool IsReleaseMode
{
get => SelectedVersionType == PackageVersionType.GithubRelease;
set => SelectedVersionType = value ? PackageVersionType.GithubRelease : PackageVersionType.Commit;
}
public bool IsReleaseModeAvailable => AvailableVersionTypes.HasFlag(PackageVersionType.GithubRelease);
public bool ShowTorchVersionOptions => SelectedTorchVersion != TorchVersion.None;
[ObservableProperty] private bool showDuplicateWarning;
[ObservableProperty] private string? installName;
public Base.ProgressViewModel InstallProgress { get; } = new();
public ProgressViewModel InstallProgress { get; } = new();
public IEnumerable<IPackageStep> Steps { get; set; }
public InstallerViewModel(
ISettingsManager settingsManager,
@ -113,7 +121,7 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
new ObservableCollection<PackageVersion>(versionOptions.AvailableVersions);
if (!AvailableVersions.Any()) return;
SelectedVersion = AvailableVersions[0];
SelectedVersion = AvailableVersions.First(x => !x.IsPrerelease);
}
else
{
@ -136,9 +144,6 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
var result = await notificationService.TryAsync(ActuallyInstall(), "Could not install package");
if (result.IsSuccessful)
{
notificationService.Show(new Notification(
$"Package {SelectedPackage.Name} installed successfully!",
"Success", NotificationType.Success));
OnPrimaryButtonClick();
}
else
@ -156,83 +161,72 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
}
}
private async Task ActuallyInstall()
private Task ActuallyInstall()
{
if (string.IsNullOrWhiteSpace(InstallName))
{
notificationService.Show(new Notification("Package name is empty",
"Please enter a name for the package", NotificationType.Error));
return;
return Task.CompletedTask;
}
try
var installLocation = Path.Combine(settingsManager.LibraryDir, "Packages", InstallName);
var prereqStep = new SetupPrerequisitesStep(prerequisiteHelper, pyRunner);
var downloadOptions = new DownloadPackageVersionOptions();
var installedVersion = new InstalledPackageVersion();
if (IsReleaseMode)
{
await InstallGitIfNecessary();
var installLocation = Path.Combine(settingsManager.LibraryDir, "Packages", InstallName);
if (!PyRunner.PipInstalled || !PyRunner.VenvInstalled)
{
InstallProgress.Text = "Installing dependencies...";
InstallProgress.IsIndeterminate = true;
await pyRunner.Initialize();
if (!PyRunner.PipInstalled)
{
await pyRunner.SetupPip();
}
if (!PyRunner.VenvInstalled)
{
await pyRunner.InstallPackage("virtualenv");
}
}
downloadOptions.VersionTag = SelectedVersion?.TagName ??
throw new NullReferenceException("Selected version is null");
installedVersion.InstalledReleaseVersion = downloadOptions.VersionTag;
}
else
{
downloadOptions.CommitHash = SelectedCommit?.Sha ??
throw new NullReferenceException("Selected commit is null");
installedVersion.InstalledBranch = SelectedVersion?.TagName ??
throw new NullReferenceException("Selected version is null");
installedVersion.InstalledCommitSha = downloadOptions.CommitHash;
}
var downloadOptions = new DownloadPackageVersionOptions();
var installedVersion = new InstalledPackageVersion();
if (IsReleaseMode)
{
downloadOptions.VersionTag = SelectedVersion?.TagName ??
throw new NullReferenceException("Selected version is null");
installedVersion.InstalledReleaseVersion = downloadOptions.VersionTag;
}
else
{
downloadOptions.CommitHash = SelectedCommit?.Sha ??
throw new NullReferenceException("Selected commit is null");
installedVersion.InstalledBranch = SelectedVersion?.TagName ??
throw new NullReferenceException("Selected version is null");
installedVersion.InstalledCommitSha = downloadOptions.CommitHash;
}
await DownloadPackage(installLocation, downloadOptions);
await InstallPackage(installLocation);
var downloadStep =
new DownloadPackageVersionStep(SelectedPackage, installLocation, downloadOptions);
var installStep = new InstallPackageStep(SelectedPackage, SelectedTorchVersion, installLocation);
var setupModelFoldersStep = new SetupModelFoldersStep(SelectedPackage,
SelectedSharedFolderMethod, installLocation);
InstallProgress.Text = "Setting up shared folder links...";
await SelectedPackage.SetupModelFolders(installLocation);
InstallProgress.Text = "Done";
InstallProgress.IsIndeterminate = false;
InstallProgress.Value = 100;
EventManager.Instance.OnGlobalProgressChanged(100);
var package = new InstalledPackage
{
DisplayName = InstallName,
LibraryPath = Path.Combine("Packages", InstallName),
Id = Guid.NewGuid(),
PackageName = SelectedPackage.Name,
Version = installedVersion,
LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now,
PreferredTorchVersion = SelectedTorchVersion,
PreferredSharedFolderMethod = SelectedSharedFolderMethod
};
var package = new InstalledPackage
{
DisplayName = InstallName,
LibraryPath = Path.Combine("Packages", InstallName),
Id = Guid.NewGuid(),
PackageName = SelectedPackage.Name,
Version = installedVersion,
LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now
};
await using var st = settingsManager.BeginTransaction();
st.Settings.InstalledPackages.Add(package);
st.Settings.ActiveInstalledPackageId = package.Id;
}
finally
var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, package);
var steps = new List<IPackageStep>
{
InstallProgress.Value = 0;
InstallProgress.IsIndeterminate = false;
}
prereqStep,
downloadStep,
installStep,
setupModelFoldersStep,
addInstalledPackageStep
};
Steps = steps;
return Task.CompletedTask;
}
public void Cancel()
{
OnCloseButtonClick();
}
private void UpdateSelectedVersionToLatestMain()
@ -255,51 +249,6 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
}
}
private static string GetDisplayVersion(string version, string? branch)
{
return branch == null ? version : $"{branch}@{version[..7]}";
}
private async Task DownloadPackage(string installLocation, DownloadPackageVersionOptions downloadOptions)
{
InstallProgress.Text = "Downloading package...";
var progress = new Progress<ProgressReport>(progress =>
{
InstallProgress.IsIndeterminate = progress.IsIndeterminate;
InstallProgress.Value = progress.Percentage;
EventManager.Instance.OnGlobalProgressChanged((int) progress.Percentage);
});
await SelectedPackage.DownloadPackage(installLocation, downloadOptions, progress);
}
private async Task InstallPackage(string installLocation)
{
InstallProgress.Text = "Installing package...";
SelectedPackage.ConsoleOutput += SelectedPackageOnConsoleOutput;
try
{
var progress = new Progress<ProgressReport>(progress =>
{
InstallProgress.IsIndeterminate = progress.IsIndeterminate;
InstallProgress.Value = progress.Percentage;
EventManager.Instance.OnGlobalProgressChanged((int) progress.Percentage);
});
await SelectedPackage.InstallPackage(installLocation, progress);
}
finally
{
SelectedPackage.ConsoleOutput -= SelectedPackageOnConsoleOutput;
}
}
private void SelectedPackageOnConsoleOutput(object? sender, ProcessOutput e)
{
InstallProgress.Description = e.Text;
}
[RelayCommand]
private async Task ShowPreview()
{
@ -350,6 +299,9 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
? PackageVersionType.Commit
: PackageVersionType.GithubRelease | PackageVersionType.Commit;
SelectedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod;
SelectedTorchVersion = SelectedPackage.GetRecommendedTorchVersion();
if (Design.IsDesignMode) return;
Dispatcher.UIThread.InvokeAsync(async () =>
@ -361,7 +313,7 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
? new ObservableCollection<PackageVersion>(versionOptions.AvailableVersions)
: new ObservableCollection<PackageVersion>(versionOptions.AvailableBranches);
SelectedVersion = AvailableVersions[0];
SelectedVersion = AvailableVersions.First(x => !x.IsPrerelease);
ReleaseNotes = SelectedVersion.ReleaseNotesMarkdown;
Logger.Debug($"Loaded release notes for {ReleaseNotes}");
@ -383,34 +335,6 @@ public partial class InstallerViewModel : ContentDialogViewModelBase
}).SafeFireAndForget();
}
private async Task InstallGitIfNecessary()
{
var progressHandler = new Progress<ProgressReport>(progress =>
{
if (progress.Message != null && progress.Message.Contains("Downloading"))
{
InstallProgress.Text = $"Downloading prerequisites... {progress.Percentage:N0}%";
}
else if (progress.Type == ProgressType.Extract)
{
InstallProgress.Text = $"Installing git... {progress.Percentage:N0}%";
}
else if (progress.Title != null && progress.Title.Contains("Unpacking"))
{
InstallProgress.Text = $"Unpacking resources... {progress.Percentage:N0}%";
}
else
{
InstallProgress.Text = progress.Message;
}
InstallProgress.IsIndeterminate = progress.IsIndeterminate;
InstallProgress.Value = Convert.ToInt32(progress.Percentage);
});
await prerequisiteHelper.InstallAllIfNecessary(progressHandler);
}
partial void OnInstallNameChanged(string? value)
{
ShowDuplicateWarning =

1
StabilityMatrix.Avalonia/ViewModels/Dialogs/LaunchOptionsViewModel.cs

@ -8,6 +8,7 @@ using System.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using FuzzySharp;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper.Cache;

17
StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs

@ -126,11 +126,14 @@ public partial class OneClickInstallViewModel : ViewModelBase
installedVersion.InstalledBranch = downloadVersion.BranchName;
}
await DownloadPackage(installLocation, downloadVersion);
await InstallPackage(installLocation);
var torchVersion = SelectedPackage.GetRecommendedTorchVersion();
await DownloadPackage(installLocation, downloadVersion);
await InstallPackage(installLocation, torchVersion);
SubHeaderText = "Setting up shared folder links...";
await SelectedPackage.SetupModelFolders(installLocation);
var recommendedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod;
await SelectedPackage.SetupModelFolders(installLocation, recommendedSharedFolderMethod);
var installedPackage = new InstalledPackage
{
@ -140,7 +143,9 @@ public partial class OneClickInstallViewModel : ViewModelBase
PackageName = SelectedPackage.Name,
Version = installedVersion,
LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now
LastUpdateCheck = DateTimeOffset.Now,
PreferredTorchVersion = torchVersion,
PreferredSharedFolderMethod = recommendedSharedFolderMethod
};
await using var st = settingsManager.BeginTransaction();
st.Settings.InstalledPackages.Add(installedPackage);
@ -177,7 +182,7 @@ public partial class OneClickInstallViewModel : ViewModelBase
OneClickInstallProgress = 100;
}
private async Task InstallPackage(string installLocation)
private async Task InstallPackage(string installLocation, TorchVersion torchVersion)
{
SelectedPackage.ConsoleOutput += (_, output) => SubSubHeaderText = output.Text;
SubHeaderText = "Downloading and installing package requirements...";
@ -190,6 +195,6 @@ public partial class OneClickInstallViewModel : ViewModelBase
EventManager.Instance.OnGlobalProgressChanged(OneClickInstallProgress);
});
await SelectedPackage.InstallPackage(installLocation, progress);
await SelectedPackage.InstallPackage(installLocation, torchVersion, progress);
}
}

8
StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageImportViewModel.cs

@ -10,6 +10,7 @@ using Avalonia.Controls;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using NLog;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper.Factory;
@ -200,6 +201,8 @@ public partial class PackageImportViewModel : ContentDialogViewModelBase
"Selected commit is null");
}
var torchVersion = SelectedBasePackage.GetRecommendedTorchVersion();
var sharedFolderRecommendation = SelectedBasePackage.RecommendedSharedFolderMethod;
var package = new InstalledPackage
{
Id = Guid.NewGuid(),
@ -209,6 +212,8 @@ public partial class PackageImportViewModel : ContentDialogViewModelBase
Version = version,
LaunchCommand = SelectedBasePackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now,
PreferredTorchVersion = torchVersion,
PreferredSharedFolderMethod = sharedFolderRecommendation
};
// Recreate venv if it's a BaseGitPackage
@ -218,7 +223,8 @@ public partial class PackageImportViewModel : ContentDialogViewModelBase
}
// Reconfigure shared links
await SelectedBasePackage.UpdateModelFolders(PackagePath);
var recommendedSharedFolderMethod = SelectedBasePackage.RecommendedSharedFolderMethod;
await SelectedBasePackage.UpdateModelFolders(PackagePath, recommendedSharedFolderMethod);
settingsManager.Transaction(s => s.InstalledPackages.Add(package));
}

60
StabilityMatrix.Avalonia/ViewModels/Dialogs/PackageModificationDialogViewModel.cs

@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Notifications;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
public class PackageModificationDialogViewModel : ContentDialogProgressViewModelBase
{
private readonly IPackageModificationRunner packageModificationRunner;
private readonly INotificationService notificationService;
private readonly IEnumerable<IPackageStep> steps;
public PackageModificationDialogViewModel(IPackageModificationRunner packageModificationRunner,
INotificationService notificationService, IEnumerable<IPackageStep> steps)
{
this.packageModificationRunner = packageModificationRunner;
this.notificationService = notificationService;
this.steps = steps;
}
public ConsoleViewModel Console { get; } = new();
public override async Task OnLoadedAsync()
{
// idk why this is getting called twice
if (!packageModificationRunner.IsRunning)
{
packageModificationRunner.ProgressChanged += PackageModificationRunnerOnProgressChanged;
await packageModificationRunner.ExecuteSteps(steps.ToList());
notificationService.Show("Package Install Completed",
"Package install completed successfully.", NotificationType.Success);
OnCloseButtonClick();
}
}
private void PackageModificationRunnerOnProgressChanged(object? sender, ProgressReport e)
{
Text = string.IsNullOrWhiteSpace(e.Title)
? packageModificationRunner.CurrentStep?.ProgressTitle
: e.Title;
Value = e.Percentage;
Description = e.Message;
IsIndeterminate = e.IsIndeterminate;
if (string.IsNullOrWhiteSpace(e.Message) || e.Message.Equals("Downloading..."))
return;
Console.PostLine(e.Message);
EventManager.Instance.OnScrollToBottomRequested();
}
}

1
StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectDataDirectoryViewModel.cs

@ -9,6 +9,7 @@ using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NLog;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;

1
StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs

@ -9,6 +9,7 @@ using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;

1
StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;

3
StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs

@ -233,7 +233,8 @@ public partial class LaunchPageViewModel : PageViewModelBase, IDisposable, IAsyn
Console.StartUpdates();
// Update shared folder links (in case library paths changed)
await basePackage.UpdateModelFolders(packagePath);
await basePackage.UpdateModelFolders(packagePath,
activeInstall.PreferredSharedFolderMethod ?? basePackage.RecommendedSharedFolderMethod);
// Load user launch args from settings and convert to string
var userArgs = settingsManager.GetLaunchArgs(activeInstall.Id);

7
StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs

@ -180,8 +180,11 @@ public partial class PackageCardViewModel : ProgressViewModel
EventManager.Instance.OnProgressChanged(new ProgressItem(progressId,
packageName, progress));
});
var updateResult = await basePackage.Update(Package, progress);
var torchVersion = Package.PreferredTorchVersion ??
basePackage.GetRecommendedTorchVersion();
var updateResult = await basePackage.Update(Package, torchVersion, progress);
settingsManager.UpdatePackageVersionNumber(Package.Id, updateResult);
notificationService.Show("Update complete",

33
StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs

@ -21,6 +21,7 @@ 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.Services;
using Symbol = FluentIcons.Common.Symbol;
using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource;
@ -37,6 +38,8 @@ public partial class PackageManagerViewModel : PageViewModelBase
private readonly ISettingsManager settingsManager;
private readonly IPackageFactory packageFactory;
private readonly ServiceManager<ViewModelBase> dialogFactory;
private readonly IPackageModificationRunner packageModificationRunner;
private readonly INotificationService notificationService;
public override string Title => "Packages";
public override IconSource IconSource =>
@ -61,12 +64,16 @@ public partial class PackageManagerViewModel : PageViewModelBase
public PackageManagerViewModel(
ISettingsManager settingsManager,
IPackageFactory packageFactory,
ServiceManager<ViewModelBase> dialogFactory
ServiceManager<ViewModelBase> dialogFactory,
IPackageModificationRunner packageModificationRunner,
INotificationService notificationService
)
{
this.settingsManager = settingsManager;
this.packageFactory = packageFactory;
this.dialogFactory = dialogFactory;
this.packageModificationRunner = packageModificationRunner;
this.notificationService = notificationService;
EventManager.Instance.InstalledPackagesChanged += OnInstalledPackagesChanged;
@ -115,7 +122,7 @@ public partial class PackageManagerViewModel : PageViewModelBase
var dialog = new BetterContentDialog
{
MaxDialogWidth = 1100,
MaxDialogWidth = 900,
MinDialogWidth = 900,
DefaultButton = ContentDialogButton.Close,
IsPrimaryButtonEnabled = false,
@ -124,7 +131,27 @@ public partial class PackageManagerViewModel : PageViewModelBase
Content = new InstallerDialog { DataContext = viewModel }
};
await dialog.ShowAsync();
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
var steps = viewModel.Steps;
var packageModificationDialogViewModel =
new PackageModificationDialogViewModel(packageModificationRunner, notificationService, steps);
dialog = new BetterContentDialog
{
MaxDialogWidth = 900,
MinDialogWidth = 900,
DefaultButton = ContentDialogButton.Close,
IsPrimaryButtonEnabled = false,
IsSecondaryButtonEnabled = false,
IsFooterVisible = false,
Content = new PackageModificationDialog {DataContext = packageModificationDialogViewModel}
};
await dialog.ShowAsync();
}
await OnLoadedAsync();
}

234
StabilityMatrix.Avalonia/Views/Dialogs/InstallerDialog.axaml

@ -9,8 +9,6 @@
xmlns:packages="clr-namespace:StabilityMatrix.Core.Models.Packages;assembly=StabilityMatrix.Core"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core"
xmlns:database="clr-namespace:StabilityMatrix.Core.Models.Database;assembly=StabilityMatrix.Core"
xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
x:DataType="dialogs:InstallerViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="700"
d:DataContext="{x:Static mocks:DesignData.InstallerViewModel}"
@ -19,18 +17,6 @@
<Grid MaxHeight="900"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
ColumnDefinitions="*,Auto">
<Grid.Transitions>
<Transitions>
<DoubleTransition Property="Width"
Duration="00:00:00.25"
Easing="0,0 0,1" />
<DoubleTransition Property="Height"
Duration="00:00:00.25"
Easing="0,0 0,1" />
</Transitions>
</Grid.Transitions>
<!-- Title and image -->
<Grid Grid.Row="0" Grid.Column="0"
Margin="16, 0, 0, 0"
@ -40,9 +26,7 @@
Margin="0, 16, 0, 4" />
<TextBlock Grid.Row="1" Text="{Binding SelectedPackage.Blurb}"
Margin="0, 0, 0, 4" />
<TextBlock Grid.Row="2" Text="{Binding LatestVersionText}"
Margin="0, 0, 0, 4" />
<TextBlock Grid.Row="3" Text="{Binding SelectedPackage.Disclaimer}"
<TextBlock Grid.Row="2" Text="{Binding SelectedPackage.Disclaimer}"
Margin="0, 0, 0, 4"
TextWrapping="Wrap"
Foreground="{DynamicResource ThemeRedColor}"
@ -52,41 +36,34 @@
Source="{Binding SelectedPackage.PreviewImageUri}"
HorizontalAlignment="Center"
MaxHeight="300"
MaxWidth="500"
MaxWidth="600"
Stretch="UniformToFill" />
</Grid>
<!-- Display Name & Version -->
<ToggleSwitch Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1"
HorizontalAlignment="Center"
IsVisible="{Binding IsReleaseModeAvailable}"
OnContent="{x:Static lang:Resources.Label_Releases}"
OffContent="{x:Static lang:Resources.Label_Branches}"
IsChecked="{Binding IsReleaseMode, Mode=TwoWay}"/>
<Grid Grid.Column="0" Grid.Row="2"
Grid.ColumnSpan="2"
Margin="16,0,16,0"
RowDefinitions="Auto, Auto, Auto"
RowDefinitions="Auto, Auto, Auto, Auto"
HorizontalAlignment="Center"
ColumnDefinitions="*, *">
ColumnDefinitions="Auto, Auto, Auto, Auto">
<Label Grid.Row="0" Grid.Column="0"
<Label Grid.Row="1" Grid.Column="0"
Margin="8,0"
Content="Display Name" />
<TextBox Grid.Row="1" Grid.Column="0"
<TextBox Grid.Row="2" Grid.Column="0"
MinWidth="250"
Margin="8,0"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
Text="{Binding InstallName, Mode=TwoWay}" />
<StackPanel Grid.Row="2" Grid.Column="0"
<StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="4"
Orientation="Horizontal"
Margin="8"
IsVisible="{Binding ShowDuplicateWarning}">
<ui:SymbolIcon
Foreground="{DynamicResource ThemeRedColor}"
Margin="8,0"
Margin="0,0,8,0"
Symbol="Alert" />
<TextBlock
Foreground="{DynamicResource ThemeRedColor}"
@ -99,97 +76,132 @@
</StackPanel>
<!-- Version Selector -->
<Label Grid.Row="0" Grid.Column="1"
<Label Grid.Row="1" Grid.Column="1"
Content="{Binding ReleaseLabelText}" />
<DockPanel Grid.Row="1" Grid.Column="1">
<ComboBox
ItemsSource="{Binding AvailableVersions}"
MinWidth="250"
VerticalAlignment="Stretch"
SelectedItem="{Binding SelectedVersion}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:PackageVersion}">
<TextBlock
Name="NameTextBlock"
VerticalAlignment="Center"
Text="{Binding TagName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button VerticalAlignment="Top"
Margin="8,0">
<ui:SymbolIcon FontSize="16" Margin="4" Symbol="Settings" />
<Button.Flyout>
<Flyout>
<!-- Advanced Options -->
<StackPanel Orientation="Vertical"
Margin="8"
IsVisible="{Binding !IsAdvancedMode}">
<Label Content="Advanced Options"
FontSize="18"
HorizontalAlignment="Center"
Margin="8,0,8,8"/>
<Label Content="Commit"
Margin="0,0,0,4"
IsVisible="{Binding !IsReleaseMode}"/>
<ComboBox
IsVisible="{Binding !IsReleaseMode}"
ItemsSource="{Binding AvailableCommits}"
MinWidth="200"
MinHeight="38"
SelectedItem="{Binding SelectedCommit}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type database:GitCommit}">
<StackPanel Margin="8,0,0,0" VerticalAlignment="Top">
<TextBlock
Margin="0,4,0,4"
Name="NameTextBlock"
Text="{Binding ShortSha}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ui:FAComboBox Grid.Row="2" Grid.Column="1"
ItemsSource="{Binding AvailableVersions}"
MinWidth="250"
VerticalAlignment="Stretch"
SelectedItem="{Binding SelectedVersion}">
<ui:FAComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:PackageVersion}">
<TextBlock
Name="NameTextBlock"
VerticalAlignment="Center"
Text="{Binding TagName}" />
</DataTemplate>
</ui:FAComboBox.ItemTemplate>
</ui:FAComboBox>
<Label Content="Shared Model Folder Strategy"
Margin="0,8,0,4" />
<ComboBox
ItemsSource="{Binding AvailableCommits}"
MinWidth="200"
MinHeight="38"
SelectedItem="{Binding SelectedCommit}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type database:GitCommit}">
<StackPanel Margin="8,0,0,0" VerticalAlignment="Top">
<TextBlock
Margin="0,4,0,4"
Name="NameTextBlock"
Text="{Binding ShortSha}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</DockPanel>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4"
HorizontalAlignment="Center"
Orientation="Horizontal" Margin="0,8,0,8"
IsVisible="{Binding IsReleaseModeAvailable}">
<ToggleButton
Content="Releases"
IsChecked="{Binding IsReleaseMode}"
IsEnabled="{Binding IsReleaseModeAvailable}" />
<ToggleButton
Content="Branches"
IsChecked="{Binding !IsReleaseMode}"
Margin="8,0,0,0" />
</StackPanel>
<!-- Advanced Options Button -->
<Button Grid.Row="2" Grid.Column="2" VerticalAlignment="Stretch"
Margin="8,0">
<ui:SymbolIcon FontSize="16" Margin="4" Symbol="Settings" />
<Button.Flyout>
<Flyout>
<!-- Advanced Options -->
<StackPanel Orientation="Vertical"
Margin="8"
IsVisible="{Binding !IsAdvancedMode}">
<Label Content="Advanced Options"
FontSize="18"
HorizontalAlignment="Center"
Margin="8,0,8,8" />
<Label Content="Commit"
Margin="0,0,0,4"
IsVisible="{Binding !IsReleaseMode}" />
<ui:FAComboBox
IsVisible="{Binding !IsReleaseMode}"
ItemsSource="{Binding AvailableCommits}"
MinWidth="200"
MinHeight="38"
SelectedItem="{Binding SelectedCommit}">
<ui:FAComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type database:GitCommit}">
<TextBlock
Margin="8,4,0,4"
Name="NameTextBlock"
Text="{Binding ShortSha}" />
</DataTemplate>
</ui:FAComboBox.ItemTemplate>
</ui:FAComboBox>
<Label Content="Shared Model Folder Strategy"
Margin="0,8,0,4" />
<ui:FAComboBox
ItemsSource="{Binding SelectedPackage.AvailableSharedFolderMethods}"
MinWidth="200"
MinHeight="38"
SelectedItem="{Binding SelectedSharedFolderMethod}">
<ui:FAComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:SharedFolderMethod}">
<TextBlock
Margin="8,4,0,4"
Text="{Binding }" />
</DataTemplate>
</ui:FAComboBox.ItemTemplate>
</ui:FAComboBox>
<Label Content="PyTorch Version"
IsVisible="{Binding ShowTorchVersionOptions}"
Margin="0,8,0,4" />
<ui:FAComboBox
ItemsSource="{Binding SelectedPackage.AvailableTorchVersions}"
MinWidth="200"
MinHeight="38"
IsVisible="{Binding ShowTorchVersionOptions}"
SelectedItem="{Binding SelectedTorchVersion}">
<ui:FAComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:TorchVersion}">
<TextBlock
Margin="8,4,0,4"
Text="{Binding }" />
</DataTemplate>
</ui:FAComboBox.ItemTemplate>
</ui:FAComboBox>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
<!-- Install Button -->
<StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
Orientation="Vertical"
HorizontalAlignment="Center">
<UniformGrid Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
Columns="2"
Margin="0,32,0,0"
HorizontalAlignment="Center">
<Button
Content="Cancel"
Command="{Binding Cancel}"
FontSize="20"
HorizontalAlignment="Center"
Margin="8,0,4,0"
Padding="16, 8, 16, 8" />
<Button
Content="Install"
Command="{Binding InstallCommand}"
FontSize="32"
FontSize="20"
HorizontalAlignment="Center"
Classes="success"
Margin="16"
Margin="4,0,8,0"
Padding="16, 8, 16, 8" />
</StackPanel>
</UniformGrid>
<!-- Available Packages -->
<ListBox Grid.Column="1" Grid.Row="0"

41
StabilityMatrix.Avalonia/Views/Dialogs/PackageModificationDialog.axaml

@ -0,0 +1,41 @@
<controls:UserControlBase xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:dialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs"
xmlns:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="dialogs:PackageModificationDialogViewModel"
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.PackageModificationDialog">
<Grid Margin="8" RowDefinitions="Auto, Auto, Auto, *">
<TextBlock Grid.Row="0" Text="{Binding Text}"
FontSize="16"
TextAlignment="Center"
HorizontalAlignment="Center"/>
<TextBlock Grid.Row="1" Text="{Binding Description}"
Margin="4"
TextWrapping="WrapWithOverflow"
IsVisible="{Binding !#Expander.IsExpanded}"/>
<ProgressBar Grid.Row="2" Value="{Binding Value}"
Margin="8"
IsIndeterminate="{Binding IsIndeterminate}"/>
<Expander Grid.Row="3" Header="More Details" x:Name="Expander">
<avaloniaEdit:TextEditor
x:Name="Console"
Margin="8,8,16,10"
MaxHeight="400"
DataContext="{Binding Console}"
Document="{Binding Document}"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
IsReadOnly="True"
LineNumbersForeground="DarkSlateGray"
ShowLineNumbers="True"
VerticalScrollBarVisibility="Auto"
WordWrap="True" />
</Expander>
</Grid>
</controls:UserControlBase>

49
StabilityMatrix.Avalonia/Views/Dialogs/PackageModificationDialog.axaml.cs

@ -0,0 +1,49 @@
using System;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Threading;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Core.Helper;
using TextMateSharp.Grammars;
namespace StabilityMatrix.Avalonia.Views.Dialogs;
public partial class PackageModificationDialog : UserControlBase
{
public PackageModificationDialog()
{
InitializeComponent();
var editor = this.FindControl<TextEditor>("Console");
if (editor is not null)
{
var options = new RegistryOptions(ThemeName.DarkPlus);
// Config hyperlinks
editor.TextArea.Options.EnableHyperlinks = true;
editor.TextArea.Options.RequireControlModifierForHyperlinkClick = false;
editor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Coral;
var textMate = editor.InstallTextMate(options);
var scope = options.GetScopeByLanguageId("log");
if (scope is null) throw new InvalidOperationException("Scope is null");
textMate.SetGrammar(scope);
textMate.SetTheme(options.LoadTheme(ThemeName.DarkPlus));
}
EventManager.Instance.ScrollToBottomRequested += (_, _) =>
{
Dispatcher.UIThread.Invoke(() =>
{
var editor = this.FindControl<TextEditor>("Console");
if (editor?.Document == null) return;
var line = Math.Max(editor.Document.LineCount - 5, 1);
editor.ScrollToLine(line);
});
};
}
}

5
StabilityMatrix.Core/Helper/SharedFolders.cs

@ -181,7 +181,10 @@ public class SharedFolders : ISharedFolders
try
{
basePackage.RemoveModelFolderLinks(package.FullPath).GetAwaiter().GetResult();
var sharedFolderMethod = package.PreferredSharedFolderMethod ??
basePackage.RecommendedSharedFolderMethod;
basePackage.RemoveModelFolderLinks(package.FullPath, sharedFolderMethod)
.GetAwaiter().GetResult();
}
catch (Exception e)
{

15
StabilityMatrix.Core/Models/InstalledPackage.cs

@ -45,8 +45,9 @@ public class InstalledPackage : IJsonOnDeserialized
public string? LaunchCommand { get; set; }
public List<LaunchOption>? LaunchArgs { get; set; }
public DateTimeOffset? LastUpdateCheck { get; set; }
public bool UpdateAvailable { get; set; }
public TorchVersion? PreferredTorchVersion { get; set; }
public SharedFolderMethod? PreferredSharedFolderMethod { get; set; }
/// <summary>
/// Get the path as a relative sub-path of the relative path.
@ -193,29 +194,21 @@ public class InstalledPackage : IJsonOnDeserialized
if (Version != null)
return;
if (string.IsNullOrWhiteSpace(InstalledBranch))
if (string.IsNullOrWhiteSpace(InstalledBranch) && !string.IsNullOrWhiteSpace(PackageVersion))
{
// release mode
Version = new InstalledPackageVersion
{
InstalledReleaseVersion = PackageVersion
};
PackageVersion = null;
DisplayVersion = null;
InstalledBranch = null;
}
else
else if (!string.IsNullOrWhiteSpace(PackageVersion))
{
Version = new InstalledPackageVersion
{
InstalledBranch = InstalledBranch,
InstalledCommitSha = PackageVersion
};
PackageVersion = null;
DisplayVersion = null;
InstalledBranch = null;
}
}
#pragma warning restore CS0618 // Type or member is obsolete

26
StabilityMatrix.Core/Models/PackageModification/AddInstalledPackageStep.cs

@ -0,0 +1,26 @@
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Core.Models.PackageModification;
public class AddInstalledPackageStep : IPackageStep
{
private readonly ISettingsManager settingsManager;
private readonly InstalledPackage newInstalledPackage;
public AddInstalledPackageStep(ISettingsManager settingsManager,
InstalledPackage newInstalledPackage)
{
this.settingsManager = settingsManager;
this.newInstalledPackage = newInstalledPackage;
}
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
await using var transaction = settingsManager.BeginTransaction();
transaction.Settings.InstalledPackages.Add(newInstalledPackage);
transaction.Settings.ActiveInstalledPackageId = newInstalledPackage.Id;
}
public string ProgressTitle => "Finishing up...";
}

24
StabilityMatrix.Core/Models/PackageModification/DownloadPackageVersionStep.cs

@ -0,0 +1,24 @@
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public class DownloadPackageVersionStep : IPackageStep
{
private readonly BasePackage package;
private readonly string installPath;
private readonly DownloadPackageVersionOptions downloadOptions;
public DownloadPackageVersionStep(BasePackage package, string installPath,
DownloadPackageVersionOptions downloadOptions)
{
this.package = package;
this.installPath = installPath;
this.downloadOptions = downloadOptions;
}
public Task ExecuteAsync(IProgress<ProgressReport>? progress = null) =>
package.DownloadPackage(installPath, downloadOptions, progress);
public string ProgressTitle => "Downloading package...";
}

12
StabilityMatrix.Core/Models/PackageModification/IPackageModificationRunner.cs

@ -0,0 +1,12 @@
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public interface IPackageModificationRunner
{
Task ExecuteSteps(IReadOnlyList<IPackageStep> steps);
bool IsRunning { get; set; }
ProgressReport CurrentProgress { get; set; }
IPackageStep? CurrentStep { get; set; }
event EventHandler<ProgressReport>? ProgressChanged;
}

33
StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs

@ -0,0 +1,33 @@
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public class InstallPackageStep : IPackageStep
{
private readonly BasePackage package;
private readonly TorchVersion torchVersion;
private readonly string installPath;
public InstallPackageStep(BasePackage package, TorchVersion torchVersion, string installPath)
{
this.package = package;
this.torchVersion = torchVersion;
this.installPath = installPath;
}
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
package.ConsoleOutput += (sender, output) =>
{
progress?.Report(new ProgressReport
{
IsIndeterminate = true,
Message = output.Text
});
};
await package.InstallPackage(installPath, torchVersion, progress).ConfigureAwait(false);
}
public string ProgressTitle => "Installing package...";
}

31
StabilityMatrix.Core/Models/PackageModification/PackageModificationRunner.cs

@ -0,0 +1,31 @@
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public class PackageModificationRunner : IPackageModificationRunner
{
public async Task ExecuteSteps(IReadOnlyList<IPackageStep> steps)
{
var progress = new Progress<ProgressReport>(report =>
{
CurrentProgress = report;
OnProgressChanged(report);
});
IsRunning = true;
foreach (var step in steps)
{
CurrentStep = step;
await step.ExecuteAsync(progress).ConfigureAwait(false);
}
IsRunning = false;
}
public bool IsRunning { get; set; }
public ProgressReport CurrentProgress { get; set; }
public IPackageStep? CurrentStep { get; set; }
public event EventHandler<ProgressReport>? ProgressChanged;
protected virtual void OnProgressChanged(ProgressReport e) => ProgressChanged?.Invoke(this, e);
}

9
StabilityMatrix.Core/Models/PackageModification/PackageStep.cs

@ -0,0 +1,9 @@
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public interface IPackageStep
{
Task ExecuteAsync(IProgress<ProgressReport>? progress = null);
string ProgressTitle { get; }
}

28
StabilityMatrix.Core/Models/PackageModification/SetupModelFoldersStep.cs

@ -0,0 +1,28 @@
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Models.Progress;
namespace StabilityMatrix.Core.Models.PackageModification;
public class SetupModelFoldersStep : IPackageStep
{
private readonly BasePackage package;
private readonly SharedFolderMethod sharedFolderMethod;
private readonly string installPath;
public SetupModelFoldersStep(BasePackage package, SharedFolderMethod sharedFolderMethod,
string installPath)
{
this.package = package;
this.sharedFolderMethod = sharedFolderMethod;
this.installPath = installPath;
}
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Setting up shared folder links...",
isIndeterminate: true));
await package.SetupModelFolders(installPath, sharedFolderMethod).ConfigureAwait(false);
}
public string ProgressTitle => "Setting up shared folder links...";
}

43
StabilityMatrix.Core/Models/PackageModification/SetupPrerequisitesStep.cs

@ -0,0 +1,43 @@
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Python;
namespace StabilityMatrix.Core.Models.PackageModification;
public class SetupPrerequisitesStep : IPackageStep
{
private readonly IPrerequisiteHelper prerequisiteHelper;
private readonly IPyRunner pyRunner;
public SetupPrerequisitesStep(IPrerequisiteHelper prerequisiteHelper, IPyRunner pyRunner)
{
this.prerequisiteHelper = prerequisiteHelper;
this.pyRunner = pyRunner;
}
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
// git, vcredist, etc...
await prerequisiteHelper.InstallAllIfNecessary(progress).ConfigureAwait(false);
// python stuff
if (!PyRunner.PipInstalled || !PyRunner.VenvInstalled)
{
progress?.Report(new ProgressReport(-1f, "Installing Python prerequisites...",
isIndeterminate: true));
await pyRunner.Initialize().ConfigureAwait(false);
if (!PyRunner.PipInstalled)
{
await pyRunner.SetupPip().ConfigureAwait(false);
}
if (!PyRunner.VenvInstalled)
{
await pyRunner.InstallPackage("virtualenv").ConfigureAwait(false);
}
}
}
public string ProgressTitle => "Installing prerequisites...";
}

1
StabilityMatrix.Core/Models/PackageVersion.cs

@ -4,4 +4,5 @@ public record PackageVersion
{
public required string TagName { get; set; }
public string? ReleaseNotesMarkdown { get; set; }
public bool IsPrerelease { get; set; }
}

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

@ -29,6 +29,8 @@ public class A3WebUI : BaseGitPackage
new("https://github.com/AUTOMATIC1111/stable-diffusion-webui/raw/master/screenshot.png");
public string RelativeArgsDefinitionScriptPath => "modules.cmd_args";
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public A3WebUI(IGithubApiCache githubApi, ISettingsManager settingsManager, IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper) :
@ -81,7 +83,7 @@ public class A3WebUI : BaseGitPackage
Level.Medium => "--medvram",
_ => null
},
Options = new() { "--lowvram", "--medvram" }
Options = new() { "--lowvram", "--medvram", "--medvram-sdxl" }
},
new()
{
@ -121,17 +123,32 @@ public class A3WebUI : BaseGitPackage
},
LaunchOptionDefinition.Extras
};
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => new[]
{
SharedFolderMethod.Symlink,
SharedFolderMethod.None
};
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cpu,
TorchVersion.Cuda,
TorchVersion.DirectMl,
TorchVersion.Rocm
};
public override async Task<string> GetLatestVersion()
{
var release = await GetLatestRelease().ConfigureAwait(false);
return release.TagName!;
}
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null)
{
await base.InstallPackage(installLocation, progress).ConfigureAwait(false);
await base.InstallPackage(installLocation, torchVersion, progress).ConfigureAwait(false);
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));
// Setup venv
await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv"));
@ -141,45 +158,36 @@ public class A3WebUI : BaseGitPackage
await venvRunner.Setup().ConfigureAwait(false);
}
// Install torch / xformers based on gpu info
var gpus = HardwareHelper.IterGpuInfo().ToList();
if (gpus.Any(g => g.IsNvidia))
switch (torchVersion)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for CUDA", isIndeterminate: true));
Logger.Info("Starting torch install (CUDA)...");
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCuda, OnConsoleOutput)
.ConfigureAwait(false);
Logger.Info("Installing xformers...");
await venvRunner.PipInstall("xformers", OnConsoleOutput).ConfigureAwait(false);
}
else if (HardwareHelper.PreferRocm())
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for ROCm", isIndeterminate: true));
await venvRunner.PipInstall("--upgrade pip wheel", OnConsoleOutput)
.ConfigureAwait(false);
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsRocm511, OnConsoleOutput)
.ConfigureAwait(false);
}
else
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for CPU", isIndeterminate: true));
Logger.Info("Starting torch install (CPU)...");
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCpu, OnConsoleOutput).ConfigureAwait(false);
case TorchVersion.Cpu:
await InstallCpuTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.Cuda:
await InstallCudaTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.Rocm:
await InstallRocmTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.DirectMl:
await InstallDirectMlTorch(venvRunner, progress).ConfigureAwait(false);
break;
default:
throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null);
}
// Install requirements file
progress?.Report(new ProgressReport(-1f, "Installing Package Requirements", isIndeterminate: true));
progress?.Report(new ProgressReport(-1f, "Installing Package Requirements",
isIndeterminate: true));
Logger.Info("Installing requirements_versions.txt");
await venvRunner.PipInstall($"-r requirements_versions.txt", OnConsoleOutput).ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, "Installing Package Requirements", isIndeterminate: false));
await venvRunner.PipInstall($"-r requirements_versions.txt", OnConsoleOutput)
.ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, "Installing Package Requirements",
isIndeterminate: false));
progress?.Report(new ProgressReport(-1f, "Updating configuration", isIndeterminate: true));
// Create and add {"show_progress_type": "TAESD"} to config.json
// Only add if the file doesn't exist
var configPath = Path.Combine(installLocation, "config.json");
@ -216,4 +224,17 @@ public class A3WebUI : BaseGitPackage
VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit);
}
private async Task InstallRocmTorch(PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for ROCm",
isIndeterminate: true));
await venvRunner.PipInstall("--upgrade pip wheel", OnConsoleOutput)
.ConfigureAwait(false);
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsRocm511, OnConsoleOutput)
.ConfigureAwait(false);
}
}

45
StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs

@ -104,7 +104,8 @@ public abstract class BaseGitPackage : BasePackage
new PackageVersion
{
TagName = r.TagName!,
ReleaseNotesMarkdown = r.Body
ReleaseNotesMarkdown = r.Body,
IsPrerelease = r.Prerelease
});
}
@ -172,10 +173,10 @@ public abstract class BaseGitPackage : BasePackage
progress?.Report(new ProgressReport(100, message: "Download Complete"));
}
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null)
{
await UnzipPackage(installLocation, progress).ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, $"{DisplayName} installed successfully"));
File.Delete(DownloadLocation);
}
@ -210,8 +211,6 @@ public abstract class BaseGitPackage : BasePackage
progress?.Report(new ProgressReport(current: Convert.ToUInt64(currentEntry),
total: Convert.ToUInt64(totalEntries)));
}
progress?.Report(new ProgressReport(1f, $"{DisplayName} installed successfully"));
return Task.CompletedTask;
}
@ -252,10 +251,11 @@ public abstract class BaseGitPackage : BasePackage
}
public override async Task<InstalledPackageVersion> Update(InstalledPackage installedPackage,
IProgress<ProgressReport>? progress = null, bool includePrerelease = false)
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null,
bool includePrerelease = false)
{
if (installedPackage.Version == null) throw new NullReferenceException("Version is null");
if (installedPackage.Version.IsReleaseMode)
{
var releases = await GetAllReleases().ConfigureAwait(false);
@ -265,12 +265,13 @@ public abstract class BaseGitPackage : BasePackage
new DownloadPackageVersionOptions {VersionTag = latestRelease.TagName},
progress)
.ConfigureAwait(false);
await InstallPackage(installedPackage.FullPath, progress).ConfigureAwait(false);
await InstallPackage(installedPackage.FullPath, torchVersion, progress)
.ConfigureAwait(false);
return new InstalledPackageVersion
{
InstalledReleaseVersion = latestRelease.TagName
InstalledReleaseVersion = latestRelease.TagName
};
}
@ -287,37 +288,41 @@ public abstract class BaseGitPackage : BasePackage
await DownloadPackage(installedPackage.FullPath,
new DownloadPackageVersionOptions {CommitHash = latestCommit.Sha}, progress)
.ConfigureAwait(false);
await InstallPackage(installedPackage.FullPath, progress).ConfigureAwait(false);
await InstallPackage(installedPackage.FullPath, torchVersion, progress)
.ConfigureAwait(false);
return new InstalledPackageVersion
{
InstalledBranch = installedPackage.Version.InstalledBranch,
InstalledCommitSha = latestCommit.Sha
};
}
public override Task SetupModelFolders(DirectoryPath installDirectory)
public override Task SetupModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
if (SharedFolders is { } folders)
if (sharedFolderMethod == SharedFolderMethod.Symlink && SharedFolders is { } folders)
{
StabilityMatrix.Core.Helper.SharedFolders
.SetupLinks(folders, SettingsManager.ModelsDirectory, installDirectory);
}
return Task.CompletedTask;
}
public override async Task UpdateModelFolders(DirectoryPath installDirectory)
public override async Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
if (SharedFolders is not null)
if (SharedFolders is not null && sharedFolderMethod == SharedFolderMethod.Symlink)
{
await StabilityMatrix.Core.Helper.SharedFolders.UpdateLinksForPackage(this,
SettingsManager.ModelsDirectory, installDirectory).ConfigureAwait(false);
}
}
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory)
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod)
{
if (SharedFolders is not null)
if (SharedFolders is not null && sharedFolderMethod == SharedFolderMethod.Symlink)
{
StabilityMatrix.Core.Helper.SharedFolders.RemoveLinksForPackage(this, installDirectory);
}

93
StabilityMatrix.Core/Models/Packages/BasePackage.cs

@ -1,8 +1,10 @@
using Octokit;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python;
namespace StabilityMatrix.Core.Models.Packages;
@ -37,16 +39,63 @@ public abstract class BasePackage
public abstract Task DownloadPackage(string installLocation, DownloadPackageVersionOptions versionOptions,
IProgress<ProgressReport>? progress1);
public abstract Task InstallPackage(string installLocation,
public abstract Task InstallPackage(string installLocation, TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null);
public abstract Task RunPackage(string installedPackagePath, string command, string arguments);
public abstract Task<bool> CheckForUpdates(InstalledPackage package);
public abstract Task<InstalledPackageVersion> Update(InstalledPackage installedPackage,
IProgress<ProgressReport>? progress = null, bool includePrerelease = false);
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null,
bool includePrerelease = false);
public abstract Task SetupModelFolders(DirectoryPath installDirectory);
public abstract Task UpdateModelFolders(DirectoryPath installDirectory);
public abstract Task RemoveModelFolderLinks(DirectoryPath installDirectory);
public virtual IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => new[]
{
SharedFolderMethod.Symlink,
SharedFolderMethod.Configuration,
SharedFolderMethod.None
};
public abstract SharedFolderMethod RecommendedSharedFolderMethod { get; }
public abstract Task SetupModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod);
public abstract Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod);
public abstract Task RemoveModelFolderLinks(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod);
public abstract IEnumerable<TorchVersion> AvailableTorchVersions { get; }
public virtual TorchVersion GetRecommendedTorchVersion()
{
// if there's only one AvailableTorchVersion, return that
if (AvailableTorchVersions.Count() == 1)
{
return AvailableTorchVersions.First();
}
if (HardwareHelper.HasNvidiaGpu() && AvailableTorchVersions.Contains(TorchVersion.Cuda))
{
return TorchVersion.Cuda;
}
if (HardwareHelper.PreferRocm() && AvailableTorchVersions.Contains(TorchVersion.Rocm))
{
return TorchVersion.Rocm;
}
if (HardwareHelper.PreferDirectML() &&
AvailableTorchVersions.Contains(TorchVersion.DirectMl))
{
return TorchVersion.DirectMl;
}
return TorchVersion.Cpu;
}
/// <summary>
/// Shuts down the subprocess, canceling any pending streams.
@ -84,4 +133,38 @@ public abstract class BasePackage
public virtual PackageVersionType AvailableVersionTypes => ShouldIgnoreReleases
? PackageVersionType.Commit
: PackageVersionType.GithubRelease | PackageVersionType.Commit;
protected async Task InstallCudaTorch(PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for CUDA",
isIndeterminate: true));
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCuda, OnConsoleOutput)
.ConfigureAwait(false);
await venvRunner.PipInstall("xformers", OnConsoleOutput).ConfigureAwait(false);
}
protected async Task InstallDirectMlTorch(PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for DirectML",
isIndeterminate: true));
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsDirectML, OnConsoleOutput)
.ConfigureAwait(false);
}
protected async Task InstallCpuTorch(PyVenvRunner venvRunner, IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for CPU",
isIndeterminate: true));
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCpu, OnConsoleOutput)
.ConfigureAwait(false);
}
}

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

@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Drawing;
using System.Text.RegularExpressions;
using NLog;
using StabilityMatrix.Core.Helper;
@ -28,6 +29,8 @@ public class ComfyUI : BaseGitPackage
public override Uri PreviewImageUri =>
new("https://github.com/comfyanonymous/ComfyUI/raw/master/comfyui_screenshot.png");
public override bool ShouldIgnoreReleases => true;
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Configuration;
public ComfyUI(IGithubApiCache githubApi, ISettingsManager settingsManager, IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper) :
@ -89,11 +92,20 @@ public class ComfyUI : BaseGitPackage
};
public override Task<string> GetLatestVersion() => Task.FromResult("master");
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cpu,
TorchVersion.Cuda,
TorchVersion.DirectMl,
TorchVersion.Rocm
};
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null)
{
await base.InstallPackage(installLocation, progress).ConfigureAwait(false);
await base.InstallPackage(installLocation, torchVersion, progress).ConfigureAwait(false);
progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true));
// Setup venv
await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv"));
@ -104,41 +116,56 @@ public class ComfyUI : BaseGitPackage
}
// Install torch / xformers based on gpu info
switch (torchVersion)
{
case TorchVersion.Cpu:
await InstallCpuTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.Cuda:
await InstallCudaTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.Rocm:
await InstallRocmTorch(venvRunner, progress).ConfigureAwait(false);
break;
case TorchVersion.DirectMl:
await InstallDirectMlTorch(venvRunner, progress).ConfigureAwait(false);
break;
default:
throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null);
}
// Install requirements file
progress?.Report(new ProgressReport(-1, "Installing Package Requirements",
isIndeterminate: true));
Logger.Info("Installing requirements.txt");
await venvRunner.PipInstall($"-r requirements.txt", OnConsoleOutput).ConfigureAwait(false);
progress?.Report(new ProgressReport(1, "Installing Package Requirements",
isIndeterminate: false));
}
private async Task AutoDetectAndInstallTorch(PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null)
{
var gpus = HardwareHelper.IterGpuInfo().ToList();
if (gpus.Any(g => g.IsNvidia))
{
progress?.Report(new ProgressReport(-1, "Installing PyTorch for CUDA", isIndeterminate: true));
Logger.Info("Starting torch install (CUDA)...");
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCuda, OnConsoleOutput)
.ConfigureAwait(false);
Logger.Info("Installing xformers...");
await venvRunner.PipInstall("xformers", OnConsoleOutput).ConfigureAwait(false);
await InstallCudaTorch(venvRunner, progress).ConfigureAwait(false);
}
else if (HardwareHelper.PreferRocm())
{
progress?.Report(new ProgressReport(-1, "Installing PyTorch for ROCm", isIndeterminate: true));
await venvRunner
.PipInstall(PyVenvRunner.TorchPipInstallArgsRocm542, OnConsoleOutput)
.ConfigureAwait(false);
await InstallRocmTorch(venvRunner, progress).ConfigureAwait(false);
}
else if (HardwareHelper.PreferDirectML())
{
await InstallDirectMlTorch(venvRunner, progress).ConfigureAwait(false);
}
else
{
progress?.Report(new ProgressReport(-1, "Installing PyTorch for CPU", isIndeterminate: true));
Logger.Info("Starting torch install (CPU)...");
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsCpu, OnConsoleOutput)
.ConfigureAwait(false);
await InstallCpuTorch(venvRunner, progress).ConfigureAwait(false);
}
// Install requirements file
progress?.Report(new ProgressReport(-1, "Installing Package Requirements", isIndeterminate: true));
Logger.Info("Installing requirements.txt");
await venvRunner.PipInstall($"-r requirements.txt", OnConsoleOutput).ConfigureAwait(false);
progress?.Report(new ProgressReport(1, "Installing Package Requirements", isIndeterminate: false));
}
public override async Task RunPackage(string installedPackagePath, string command, string arguments)
{
await SetupVenv(installedPackagePath).ConfigureAwait(false);
@ -173,8 +200,17 @@ public class ComfyUI : BaseGitPackage
HandleExit);
}
public override Task SetupModelFolders(DirectoryPath installDirectory)
public override Task SetupModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
switch (sharedFolderMethod)
{
case SharedFolderMethod.None:
return Task.CompletedTask;
case SharedFolderMethod.Symlink:
return base.SetupModelFolders(installDirectory, sharedFolderMethod);
}
var extraPathsYamlPath = installDirectory + "extra_model_paths.yaml";
var modelsDir = SettingsManager.ModelsDirectory;
@ -220,11 +256,35 @@ public class ComfyUI : BaseGitPackage
return Task.CompletedTask;
}
public override Task UpdateModelFolders(DirectoryPath installDirectory) =>
SetupModelFolders(installDirectory);
public override Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod) =>
SetupModelFolders(installDirectory, sharedFolderMethod);
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
return sharedFolderMethod switch
{
SharedFolderMethod.Configuration => Task.CompletedTask,
SharedFolderMethod.None => Task.CompletedTask,
SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory,
sharedFolderMethod),
_ => Task.CompletedTask
};
}
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory) =>
Task.CompletedTask;
private async Task InstallRocmTorch(PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing PyTorch for ROCm",
isIndeterminate: true));
await venvRunner.PipInstall("--upgrade pip wheel", OnConsoleOutput)
.ConfigureAwait(false);
await venvRunner.PipInstall(PyVenvRunner.TorchPipInstallArgsRocm542, OnConsoleOutput)
.ConfigureAwait(false);
}
public class ComfyModelPathsYaml
{

13
StabilityMatrix.Core/Models/Packages/DankDiffusion.cs

@ -21,6 +21,8 @@ public class DankDiffusion : BaseGitPackage
"https://github.com/LykosAI/StabilityMatrix/blob/main/LICENSE";
public override string Blurb => "A dank interface for diffusion";
public override string LaunchCommand => "test";
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public override IReadOnlyList<string> ExtraLaunchCommands => new[]
{
@ -34,21 +36,26 @@ public class DankDiffusion : BaseGitPackage
throw new NotImplementedException();
}
public override Task SetupModelFolders(DirectoryPath installDirectory)
public override Task SetupModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
public override Task UpdateModelFolders(DirectoryPath installDirectory)
public override Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory)
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
public override IEnumerable<TorchVersion> AvailableTorchVersions { get; }
public override List<LaunchOptionDefinition> LaunchOptions { get; }
public override Task<string> GetLatestVersion()
{

68
StabilityMatrix.Core/Models/Packages/Fooocus.cs

@ -32,8 +32,38 @@ public class Fooocus : BaseGitPackage
public override List<LaunchOptionDefinition> LaunchOptions => new()
{
new LaunchOptionDefinition
{
Name = "Port",
Type = LaunchOptionType.String,
Description = "Sets the listen port",
Options = {"--port"}
},
new LaunchOptionDefinition
{
Name = "Share",
Type = LaunchOptionType.Bool,
Description = "Set whether to share on Gradio",
Options = {"--share"}
},
new LaunchOptionDefinition
{
Name = "Listen",
Type = LaunchOptionType.String,
Description = "Set the listen interface",
Options = {"--listen"}
},
LaunchOptionDefinition.Extras
};
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => new[]
{
SharedFolderMethod.Symlink,
SharedFolderMethod.None
};
public override Dictionary<SharedFolderType, IReadOnlyList<string>> SharedFolders => new()
{
@ -50,34 +80,46 @@ public class Fooocus : BaseGitPackage
[SharedFolderType.Hypernetwork] = new[] {"models/hypernetworks"}
};
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cpu,
TorchVersion.Cuda,
TorchVersion.Rocm
};
public override async Task<string> GetLatestVersion()
{
var release = await GetLatestRelease().ConfigureAwait(false);
return release.TagName!;
}
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null)
{
await base.InstallPackage(installLocation, progress).ConfigureAwait(false);
await base.InstallPackage(installLocation, torchVersion, progress).ConfigureAwait(false);
var venvRunner = await SetupVenv(installLocation).ConfigureAwait(false);
progress?.Report(new ProgressReport(-1f, "Installing torch...", isIndeterminate: true));
var torchVersion = "cpu";
var gpus = HardwareHelper.IterGpuInfo().ToList();
if (gpus.Any(g => g.IsNvidia))
{
torchVersion = "cu118";
}
else if (HardwareHelper.PreferRocm())
var torchVersionStr = "cpu";
switch (torchVersion)
{
torchVersion = "rocm5.4.2";
case TorchVersion.Cuda:
torchVersionStr = "cu118";
break;
case TorchVersion.Rocm:
torchVersionStr = "rocm5.4.2";
break;
case TorchVersion.Cpu:
break;
default:
throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null);
}
await venvRunner
.PipInstall(
$"torch==2.0.1 torchvision==0.15.2 --extra-index-url https://download.pytorch.org/whl/{torchVersion}",
$"torch==2.0.1 torchvision==0.15.2 --extra-index-url https://download.pytorch.org/whl/{torchVersionStr}",
OnConsoleOutput).ConfigureAwait(false);
progress?.Report(new ProgressReport(-1f, "Installing requirements...",

120
StabilityMatrix.Core/Models/Packages/InvokeAI.cs

@ -1,10 +1,8 @@
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using NLog;
using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
@ -45,6 +43,14 @@ public class InvokeAI : BaseGitPackage
public override bool ShouldIgnoreReleases => true;
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => new[]
{
SharedFolderMethod.Symlink,
SharedFolderMethod.None
};
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public InvokeAI(
IGithubApiCache githubApi,
ISettingsManager settingsManager,
@ -116,13 +122,32 @@ public class InvokeAI : BaseGitPackage
public override Task<string> GetLatestVersion() => Task.FromResult("main");
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cpu,
TorchVersion.Cuda,
TorchVersion.Rocm,
TorchVersion.Mps
};
public override TorchVersion GetRecommendedTorchVersion()
{
if (Compat.IsMacOS && Compat.IsArm)
{
return TorchVersion.Mps;
}
return base.GetRecommendedTorchVersion();
}
public override Task DownloadPackage(string installLocation,
DownloadPackageVersionOptions downloadOptions, IProgress<ProgressReport>? progress = null)
{
return Task.CompletedTask;
}
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation, TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null)
{
// Setup venv
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));
@ -132,38 +157,29 @@ public class InvokeAI : BaseGitPackage
await venvRunner.Setup().ConfigureAwait(false);
venvRunner.EnvironmentVariables = GetEnvVars(installLocation);
var gpus = HardwareHelper.IterGpuInfo().ToList();
progress?.Report(new ProgressReport(-1f, "Installing Package", isIndeterminate: true));
var pipCommandArgs =
"InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu";
// If has Nvidia Gpu, install CUDA version
if (gpus.Any(g => g.IsNvidia))
switch (torchVersion)
{
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
"InvokeAI[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu117";
}
// For AMD, Install ROCm version
else if (HardwareHelper.PreferRocm())
{
Logger.Info("Starting InvokeAI install (ROCm)...");
pipCommandArgs =
"InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.4.2";
}
// For Apple silicon, use MPS
else if (Compat.IsMacOS && Compat.IsArm)
{
Logger.Info("Starting InvokeAI install (MPS)...");
pipCommandArgs = "InvokeAI --use-pep517";
}
// CPU Version
else
{
Logger.Info("Starting InvokeAI install (CPU)...");
case TorchVersion.Cuda:
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
"InvokeAI[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu117";
break;
case TorchVersion.Rocm:
Logger.Info("Starting InvokeAI install (ROCm)...");
pipCommandArgs =
"InvokeAI --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.4.2";
break;
case TorchVersion.Mps:
Logger.Info("Starting InvokeAI install (MPS)...");
pipCommandArgs = "InvokeAI --use-pep517";
break;
}
await venvRunner.PipInstall(pipCommandArgs, OnConsoleOutput).ConfigureAwait(false);
@ -180,7 +196,8 @@ public class InvokeAI : BaseGitPackage
progress?.Report(new ProgressReport(1f, "Done!", isIndeterminate: false));
}
public override async Task<InstalledPackageVersion> Update(InstalledPackage installedPackage, IProgress<ProgressReport>? progress = null,
public override async Task<InstalledPackageVersion> Update(InstalledPackage installedPackage,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null,
bool includePrerelease = false)
{
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));
@ -208,30 +225,25 @@ public class InvokeAI : BaseGitPackage
var pipCommandArgs =
$"\"InvokeAI @ {downloadUrl}\" --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu --upgrade";
// If has Nvidia Gpu, install CUDA version
if (gpus.Any(g => g.IsNvidia))
{
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
$"\"InvokeAI[xformers] @ {downloadUrl}\" --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu117 --upgrade";
}
// For AMD, Install ROCm version
else if (gpus.Any(g => g.IsAmd))
{
Logger.Info("Starting InvokeAI install (ROCm)...");
pipCommandArgs =
$"\"InvokeAI @ {downloadUrl}\" --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.4.2 --upgrade";
}
// For Apple silicon, use MPS
else if (Compat.IsMacOS && Compat.IsArm)
{
Logger.Info("Starting InvokeAI install (MPS)...");
pipCommandArgs = $"\"InvokeAI @ {downloadUrl}\" --use-pep517 --upgrade";
}
// CPU Version
else
switch (torchVersion)
{
Logger.Info("Starting InvokeAI install (CPU)...");
// If has Nvidia Gpu, install CUDA version
case TorchVersion.Cuda:
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
$"\"InvokeAI[xformers] @ {downloadUrl}\" --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu117 --upgrade";
break;
// For AMD, Install ROCm version
case TorchVersion.Rocm:
Logger.Info("Starting InvokeAI install (ROCm)...");
pipCommandArgs =
$"\"InvokeAI @ {downloadUrl}\" --use-pep517 --extra-index-url https://download.pytorch.org/whl/rocm5.4.2 --upgrade";
break;
case TorchVersion.Mps:
// For Apple silicon, use MPS
Logger.Info("Starting InvokeAI install (MPS)...");
pipCommandArgs = $"\"InvokeAI @ {downloadUrl}\" --use-pep517 --upgrade";
break;
}
await venvRunner.PipInstall(pipCommandArgs, OnConsoleOutput).ConfigureAwait(false);

26
StabilityMatrix.Core/Models/Packages/UnknownPackage.cs

@ -26,6 +26,9 @@ public class UnknownPackage : BasePackage
"test-config",
};
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public override Task DownloadPackage(string installLocation, DownloadPackageVersionOptions versionOptions,
IProgress<ProgressReport>? progress1)
{
@ -33,7 +36,8 @@ public class UnknownPackage : BasePackage
}
/// <inheritdoc />
public override Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override Task InstallPackage(string installLocation, TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null)
{
throw new NotImplementedException();
}
@ -44,23 +48,34 @@ public class UnknownPackage : BasePackage
}
/// <inheritdoc />
public override Task SetupModelFolders(DirectoryPath installDirectory)
public override Task SetupModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public override Task UpdateModelFolders(DirectoryPath installDirectory)
public override Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory)
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod)
{
throw new NotImplementedException();
}
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cuda,
TorchVersion.Cpu,
TorchVersion.Rocm,
TorchVersion.DirectMl
};
/// <inheritdoc />
public override void Shutdown()
{
@ -80,7 +95,8 @@ public class UnknownPackage : BasePackage
}
/// <inheritdoc />
public override Task<InstalledPackageVersion> Update(InstalledPackage installedPackage, IProgress<ProgressReport>? progress = null,
public override Task<InstalledPackageVersion> Update(InstalledPackage installedPackage,
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null,
bool includePrerelease = false)
{
throw new NotImplementedException();

151
StabilityMatrix.Core/Models/Packages/VladAutomatic.cs

@ -30,6 +30,17 @@ public class VladAutomatic : BaseGitPackage
public override Uri PreviewImageUri =>
new("https://github.com/vladmandic/automatic/raw/master/html/black-orange.jpg");
public override bool ShouldIgnoreReleases => true;
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[]
{
TorchVersion.Cpu,
TorchVersion.Rocm,
TorchVersion.DirectMl,
TorchVersion.Cuda
};
public VladAutomatic(IGithubApiCache githubApi, ISettingsManager settingsManager, IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper) :
@ -139,43 +150,42 @@ public class VladAutomatic : BaseGitPackage
public override string ExtraLaunchArguments => "";
public override Task<string> GetLatestVersion() => Task.FromResult("master");
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation, TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null)
{
progress?.Report(new ProgressReport(-1f, "Installing package...", isIndeterminate: true));
// Setup venv
var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv"));
venvRunner.WorkingDirectory = installLocation;
venvRunner.EnvironmentVariables = SettingsManager.Settings.EnvironmentVariables;
await venvRunner.Setup().ConfigureAwait(false);
// Run initial install
if (HardwareHelper.HasNvidiaGpu())
{
// CUDA
await venvRunner.CustomInstall("launch.py --use-cuda --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
}
else if (HardwareHelper.PreferRocm())
{
// ROCm
await venvRunner.CustomInstall("launch.py --use-rocm --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
}
else if (HardwareHelper.PreferDirectML())
switch (torchVersion)
{
// DirectML
await venvRunner.CustomInstall("launch.py --use-directml --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
}
else
{
await venvRunner.CustomInstall("launch.py --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
// Run initial install
case TorchVersion.Cuda:
await venvRunner.CustomInstall("launch.py --use-cuda --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
break;
case TorchVersion.Rocm:
await venvRunner.CustomInstall("launch.py --use-rocm --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
break;
case TorchVersion.DirectMl:
await venvRunner
.CustomInstall("launch.py --use-directml --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
break;
default:
// CPU
await venvRunner.CustomInstall("launch.py --debug --test", OnConsoleOutput)
.ConfigureAwait(false);
break;
}
progress?.Report(new ProgressReport(1, isIndeterminate: false));
progress?.Report(new ProgressReport(1f, isIndeterminate: false));
}
public override async Task DownloadPackage(string installLocation,
@ -236,23 +246,24 @@ public class VladAutomatic : BaseGitPackage
}
public override async Task<InstalledPackageVersion> Update(InstalledPackage installedPackage,
IProgress<ProgressReport>? progress = null, bool includePrerelease = false)
TorchVersion torchVersion, IProgress<ProgressReport>? progress = null,
bool includePrerelease = false)
{
if (installedPackage.Version is null)
{
throw new Exception("Version is null");
}
progress?.Report(new ProgressReport(-1f, message: "Downloading package update...",
isIndeterminate: true, type: ProgressType.Update));
await PrerequisiteHelper.RunGit(installedPackage.FullPath, "checkout",
installedPackage.Version.InstalledBranch).ConfigureAwait(false);
var venvRunner = new PyVenvRunner(Path.Combine(installedPackage.FullPath!, "venv"));
venvRunner.WorkingDirectory = installedPackage.FullPath!;
venvRunner.EnvironmentVariables = SettingsManager.Settings.EnvironmentVariables;
await venvRunner.CustomInstall("launch.py --upgrade --test", OnConsoleOutput)
.ConfigureAwait(false);
@ -276,13 +287,87 @@ public class VladAutomatic : BaseGitPackage
}
finally
{
progress?.Report(new ProgressReport(1f, message: "Update Complete", isIndeterminate: false,
progress?.Report(new ProgressReport(1f, message: "Update Complete",
isIndeterminate: false,
type: ProgressType.Update));
}
return new InstalledPackageVersion
{
InstalledBranch = installedPackage.Version.InstalledBranch
};
}
public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod)
{
switch (sharedFolderMethod)
{
case SharedFolderMethod.Symlink:
return base.SetupModelFolders(installDirectory, sharedFolderMethod);
case SharedFolderMethod.None:
return Task.CompletedTask;
}
// Config option
var configJsonPath = installDirectory + "config.json";
var exists = File.Exists(configJsonPath);
JsonObject? configRoot;
if (exists)
{
var configJson = File.ReadAllText(configJsonPath);
try
{
configRoot = JsonSerializer.Deserialize<JsonObject>(configJson) ?? new JsonObject();
}
catch (JsonException e)
{
Logger.Error(e, "Error setting up Vlad shared model config");
return Task.CompletedTask;
}
}
else
{
configRoot = new JsonObject();
}
configRoot["ckpt_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "StableDiffusion");
configRoot["diffusers_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "Diffusers");
configRoot["vae_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "VAE");
configRoot["lora_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "Lora");
configRoot["lyco_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "LyCORIS");
configRoot["embeddings_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "TextualInversion");
configRoot["hypernetwork_dir"] = Path.Combine(SettingsManager.ModelsDirectory, "Hypernetwork");
configRoot["codeformer_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "Codeformer");
configRoot["gfpgan_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "GFPGAN");
configRoot["bsrgan_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "BSRGAN");
configRoot["esrgan_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "ESRGAN");
configRoot["realesrgan_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "RealESRGAN");
configRoot["scunet_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "ScuNET");
configRoot["swinir_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "SwinIR");
configRoot["ldsr_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "LDSR");
configRoot["clip_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "CLIP");
configRoot["control_net_models_path"] = Path.Combine(SettingsManager.ModelsDirectory, "ControlNet");
var configJsonStr = JsonSerializer.Serialize(configRoot, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(configJsonPath, configJsonStr);
return Task.CompletedTask;
}
public override Task UpdateModelFolders(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod) =>
SetupModelFolders(installDirectory, sharedFolderMethod);
public override Task RemoveModelFolderLinks(DirectoryPath installDirectory,
SharedFolderMethod sharedFolderMethod) =>
sharedFolderMethod switch
{
SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory,
sharedFolderMethod),
SharedFolderMethod.None => Task.CompletedTask,
_ => Task.CompletedTask
};
}

34
StabilityMatrix.Core/Models/Packages/VoltaML.cs

@ -44,6 +44,17 @@ public class VoltaML : BaseGitPackage
[SharedFolderType.TextualInversion] = new[] {"data/textual-inversion"},
};
public override SharedFolderMethod RecommendedSharedFolderMethod =>
SharedFolderMethod.Symlink;
public override IEnumerable<TorchVersion> AvailableTorchVersions => new[] {TorchVersion.None};
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => new[]
{
SharedFolderMethod.Symlink,
SharedFolderMethod.None
};
// https://github.com/VoltaML/voltaML-fast-stable-diffusion/blob/main/main.py#L45
public override List<LaunchOptionDefinition> LaunchOptions => new List<LaunchOptionDefinition>
{
@ -123,27 +134,30 @@ public class VoltaML : BaseGitPackage
};
public override Task<string> GetLatestVersion() => Task.FromResult("main");
public override async Task InstallPackage(string installLocation, IProgress<ProgressReport>? progress = null)
public override async Task InstallPackage(string installLocation, TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null)
{
await base.InstallPackage(installLocation, progress).ConfigureAwait(false);
await base.InstallPackage(installLocation, torchVersion, progress).ConfigureAwait(false);
// Setup venv
progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true));
await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv"));
venvRunner.WorkingDirectory = installLocation;
await venvRunner.Setup().ConfigureAwait(false);
// Install requirements
progress?.Report(new ProgressReport(-1, "Installing Package Requirements", isIndeterminate: true));
progress?.Report(new ProgressReport(-1, "Installing Package Requirements",
isIndeterminate: true));
await venvRunner
.PipInstall("rich packaging python-dotenv", OnConsoleOutput)
.ConfigureAwait(false);
progress?.Report(new ProgressReport(1, "Installing Package Requirements", isIndeterminate: false));
progress?.Report(new ProgressReport(1, "Installing Package Requirements",
isIndeterminate: false));
}
public override async Task RunPackage(string installedPackagePath, string command, string arguments)
{
await SetupVenv(installedPackagePath).ConfigureAwait(false);

2
StabilityMatrix.Core/Models/SharedFolderMethod.cs

@ -3,6 +3,6 @@
public enum SharedFolderMethod
{
Symlink,
Config,
Configuration,
None
}

11
StabilityMatrix.Core/Models/TorchVersion.cs

@ -0,0 +1,11 @@
namespace StabilityMatrix.Core.Models;
public enum TorchVersion
{
Cuda,
Rocm,
DirectMl,
Cpu,
Mps,
None
}

1
StabilityMatrix.Core/StabilityMatrix.Core.csproj

@ -40,4 +40,5 @@
<PackageReference Include="YamlDotNet" Version="13.1.1" />
</ItemGroup>
</Project>

Loading…
Cancel
Save