Browse Source

Rework and reduce calls to GitHub to help mitigate rate limiting. also made git pulls autostash & invokeAI should now install torch2.1/cuda12.1 for nvidia users

pull/263/head
JT 1 year ago
parent
commit
df40dc6a5b
  1. 9
      CHANGELOG.md
  2. 23
      StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs
  3. 10
      StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
  4. 2
      StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
  5. 149
      StabilityMatrix.Core/Helper/Cache/GithubApiCache.cs
  6. 11
      StabilityMatrix.Core/Helper/Cache/IGithubApiCache.cs
  7. 31
      StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
  8. 2
      StabilityMatrix.Core/Models/Packages/BasePackage.cs
  9. 60
      StabilityMatrix.Core/Models/Packages/InvokeAI.cs
  10. 8
      StabilityMatrix.Core/Models/Packages/UnknownPackage.cs

9
CHANGELOG.md

@ -5,6 +5,15 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
## v2.6.1
### Changed
- NVIDIA GPU users will be updated to use CUDA 12.1 for the InvokeAI package for a slight performance improvement
- Update will occur the next time the package is updated, or on a fresh install
- Note: CUDA 12.1 is only available on Maxwell (GTX 900 series) and newer GPUs
### Fixed
- Reduced the amount of calls to GitHub to help prevent rate limiting
- Fixed rate limit crash on startup preventing app from starting
## v2.6.0
### Added
- Added **Output Sharing** option for all packages in the three-dots menu on the Packages page

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

@ -140,30 +140,17 @@ public partial class OneClickInstallViewModel : ContentDialogViewModelBase
SelectedPackage.Name
);
var downloadVersion = new DownloadPackageVersionOptions
{
IsLatest = true,
IsPrerelease = false
};
var downloadVersion = await SelectedPackage.GetLatestVersion();
var installedVersion = new InstalledPackageVersion { IsPrerelease = false };
var versionOptions = await SelectedPackage.GetAllVersionOptions();
if (versionOptions.AvailableVersions != null && versionOptions.AvailableVersions.Any())
if (SelectedPackage.ShouldIgnoreReleases)
{
downloadVersion.VersionTag = versionOptions.AvailableVersions.First().TagName;
installedVersion.InstalledReleaseVersion = downloadVersion.VersionTag;
installedVersion.InstalledBranch = downloadVersion.BranchName;
installedVersion.InstalledCommitSha = downloadVersion.CommitHash;
}
else
{
var latestVersion = await SelectedPackage.GetLatestVersion();
downloadVersion.BranchName = latestVersion.BranchName;
downloadVersion.CommitHash =
(await SelectedPackage.GetAllCommits(downloadVersion.BranchName))
?.FirstOrDefault()
?.Sha ?? string.Empty;
installedVersion.InstalledBranch = downloadVersion.BranchName;
installedVersion.InstalledCommitSha = downloadVersion.CommitHash;
installedVersion.InstalledReleaseVersion = downloadVersion.VersionTag;
}
var torchVersion = SelectedPackage.GetRecommendedTorchVersion();

10
StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs

@ -111,7 +111,7 @@ public partial class MainWindowViewModel : ViewModelBase
var startupTime = CodeTimer.FormatTime(Program.StartupTimer.Elapsed);
Logger.Info($"App started ({startupTime})");
if (Program.Args.DebugOneClickInstall || !settingsManager.Settings.InstalledPackages.Any())
if (Program.Args.DebugOneClickInstall || settingsManager.Settings.InstalledPackages.Any())
{
var viewModel = dialogFactory.Get<OneClickInstallViewModel>();
var dialog = new BetterContentDialog
@ -180,7 +180,8 @@ public partial class MainWindowViewModel : ViewModelBase
private async Task<bool> EnsureDataDirectory()
{
// If we can't find library, show selection dialog
if (!settingsManager.TryFindLibrary())
var foundInitially = settingsManager.TryFindLibrary();
if (!foundInitially)
{
var result = await ShowSelectDataDirectoryDialog();
if (!result)
@ -194,7 +195,10 @@ public partial class MainWindowViewModel : ViewModelBase
}
// Tell LaunchPage to load any packages if they selected an existing directory
EventManager.Instance.OnInstalledPackagesChanged();
if (!foundInitially)
{
EventManager.Instance.OnInstalledPackagesChanged();
}
// Check if there are old packages, if so show migration dialog
// TODO: Migration dialog

2
StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs

@ -99,7 +99,7 @@ public partial class PackageManagerViewModel : PageViewModelBase
.Bind(PackageCards)
.Subscribe();
timer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(15), IsEnabled = true };
timer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(60), IsEnabled = true };
timer.Tick += async (_, _) => await CheckPackagesForUpdates();
}

149
StabilityMatrix.Core/Helper/Cache/GithubApiCache.cs

@ -1,4 +1,5 @@
using Octokit;
using Microsoft.Extensions.Logging;
using Octokit;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Database;
using StabilityMatrix.Core.Models.Database;
@ -10,83 +11,85 @@ public class GithubApiCache : IGithubApiCache
{
private readonly ILiteDbContext dbContext;
private readonly IGitHubClient githubApi;
private readonly ILogger<IGithubApiCache> logger;
private readonly TimeSpan cacheDuration = TimeSpan.FromMinutes(15);
public GithubApiCache(ILiteDbContext dbContext, IGitHubClient githubApi)
public GithubApiCache(
ILiteDbContext dbContext,
IGitHubClient githubApi,
ILogger<IGithubApiCache> logger
)
{
this.dbContext = dbContext;
this.githubApi = githubApi;
}
public async Task<Release?> GetLatestRelease(string username, string repository)
{
var cacheKey = $"Releases-{username}-{repository}";
var latestRelease = await dbContext.GetGithubCacheEntry(cacheKey);
if (latestRelease != null && !IsCacheExpired(latestRelease.LastUpdated))
{
return latestRelease.AllReleases.First();
}
var allReleases = await githubApi.Repository.Release.GetAll(username, repository);
if (allReleases == null)
{
return null;
}
var cacheEntry = new GithubCacheEntry
{
CacheKey = cacheKey,
AllReleases = allReleases.OrderByDescending(x => x.CreatedAt)
};
await dbContext.UpsertGithubCacheEntry(cacheEntry);
return cacheEntry.AllReleases.First();
this.logger = logger;
}
public async Task<IEnumerable<Release>> GetAllReleases(string username, string repository)
{
var cacheKey = $"Releases-{username}-{repository}";
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey);
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey).ConfigureAwait(false);
if (cacheEntry != null && !IsCacheExpired(cacheEntry.LastUpdated))
{
return cacheEntry.AllReleases.OrderByDescending(x => x.CreatedAt);
}
var allReleases = await githubApi.Repository.Release.GetAll(username, repository);
if (allReleases == null)
try
{
return new List<Release>().OrderByDescending(x => x.CreatedAt);
}
var allReleases = await githubApi.Repository.Release
.GetAll(username, repository)
.ConfigureAwait(false);
if (allReleases == null)
{
return new List<Release>();
}
var newCacheEntry = new GithubCacheEntry
{
CacheKey = cacheKey,
AllReleases = allReleases.OrderByDescending(x => x.CreatedAt)
};
await dbContext.UpsertGithubCacheEntry(newCacheEntry);
var newCacheEntry = new GithubCacheEntry
{
CacheKey = cacheKey,
AllReleases = allReleases.OrderByDescending(x => x.CreatedAt)
};
await dbContext.UpsertGithubCacheEntry(newCacheEntry).ConfigureAwait(false);
return newCacheEntry.AllReleases;
return newCacheEntry.AllReleases;
}
catch (ApiException ex)
{
logger.LogWarning(ex, "Failed to get releases from Github API.");
return cacheEntry?.AllReleases.OrderByDescending(x => x.CreatedAt)
?? Enumerable.Empty<Release>();
}
}
public async Task<IEnumerable<Branch>> GetAllBranches(string username, string repository)
{
var cacheKey = $"Branches-{username}-{repository}";
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey);
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey).ConfigureAwait(false);
if (cacheEntry != null && !IsCacheExpired(cacheEntry.LastUpdated))
{
return cacheEntry.Branches;
}
var branches = await githubApi.Repository.Branch.GetAll(username, repository);
if (branches == null)
try
{
return new List<Branch>();
}
var branches = await githubApi.Repository.Branch
.GetAll(username, repository)
.ConfigureAwait(false);
if (branches == null)
{
return new List<Branch>();
}
var newCacheEntry = new GithubCacheEntry { CacheKey = cacheKey, Branches = branches };
await dbContext.UpsertGithubCacheEntry(newCacheEntry);
var newCacheEntry = new GithubCacheEntry { CacheKey = cacheKey, Branches = branches };
await dbContext.UpsertGithubCacheEntry(newCacheEntry).ConfigureAwait(false);
return newCacheEntry.Branches;
return newCacheEntry.Branches;
}
catch (ApiException ex)
{
logger.LogWarning(ex, "Failed to get branches from Github API.");
return cacheEntry?.Branches ?? Enumerable.Empty<Branch>();
}
}
public async Task<IEnumerable<GitCommit>?> GetAllCommits(
@ -98,37 +101,47 @@ public class GithubApiCache : IGithubApiCache
)
{
var cacheKey = $"Commits-{username}-{repository}-{branch}-{page}-{perPage}";
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey);
var cacheEntry = await dbContext.GetGithubCacheEntry(cacheKey).ConfigureAwait(false);
if (cacheEntry != null && !IsCacheExpired(cacheEntry.LastUpdated))
{
return cacheEntry.Commits;
}
var commits = await githubApi.Repository.Commit.GetAll(
username,
repository,
new CommitRequest { Sha = branch },
new ApiOptions
try
{
var commits = await githubApi.Repository.Commit
.GetAll(
username,
repository,
new CommitRequest { Sha = branch },
new ApiOptions
{
PageCount = page,
PageSize = perPage,
StartPage = page
}
)
.ConfigureAwait(false);
if (commits == null)
{
PageCount = page,
PageSize = perPage,
StartPage = page
return new List<GitCommit>();
}
);
if (commits == null)
{
return new List<GitCommit>();
}
var newCacheEntry = new GithubCacheEntry
{
CacheKey = cacheKey,
Commits = commits.Select(x => new GitCommit { Sha = x.Sha })
};
await dbContext.UpsertGithubCacheEntry(newCacheEntry).ConfigureAwait(false);
var newCacheEntry = new GithubCacheEntry
return newCacheEntry.Commits;
}
catch (ApiException ex)
{
CacheKey = cacheKey,
Commits = commits.Select(x => new GitCommit { Sha = x.Sha })
};
await dbContext.UpsertGithubCacheEntry(newCacheEntry);
return newCacheEntry.Commits;
logger.LogWarning(ex, "Failed to get commits from Github API.");
return cacheEntry?.Commits ?? Enumerable.Empty<GitCommit>();
}
}
private bool IsCacheExpired(DateTimeOffset expiration) =>

11
StabilityMatrix.Core/Helper/Cache/IGithubApiCache.cs

@ -6,12 +6,15 @@ namespace StabilityMatrix.Core.Helper.Cache;
public interface IGithubApiCache
{
Task<Release?> GetLatestRelease(string username, string repository);
Task<IEnumerable<Release>> GetAllReleases(string username, string repository);
Task<IEnumerable<Branch>> GetAllBranches(string username, string repository);
Task<IEnumerable<GitCommit>?> GetAllCommits(string username, string repository, string branch, int page = 1,
[AliasAs("per_page")] int perPage = 10);
Task<IEnumerable<GitCommit>?> GetAllCommits(
string username,
string repository,
string branch,
int page = 1,
[AliasAs("per_page")] int perPage = 10
);
}

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

@ -86,31 +86,19 @@ public abstract class BaseGitPackage : BasePackage
};
}
var release = await GetLatestRelease(includePrerelease).ConfigureAwait(false);
var releases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false);
var latestRelease = includePrerelease
? releases.First()
: releases.First(x => !x.Prerelease);
return new DownloadPackageVersionOptions
{
IsLatest = true,
IsPrerelease = release.Prerelease,
VersionTag = release.TagName!
IsPrerelease = latestRelease.Prerelease,
VersionTag = latestRelease.TagName!
};
}
protected async Task<Release> GetLatestRelease(bool includePrerelease = false)
{
var releases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false);
return includePrerelease ? releases.First() : releases.First(x => !x.Prerelease);
}
public override Task<IEnumerable<Branch>> GetAllBranches()
{
return GithubApi.GetAllBranches(Author, Name);
}
public override Task<IEnumerable<Release>> GetAllReleases()
{
return GithubApi.GetAllReleases(Author, Name);
}
public override Task<IEnumerable<GitCommit>?> GetAllCommits(
string branch,
int page = 1,
@ -126,7 +114,7 @@ public abstract class BaseGitPackage : BasePackage
if (!ShouldIgnoreReleases)
{
var allReleases = await GetAllReleases().ConfigureAwait(false);
var allReleases = await GithubApi.GetAllReleases(Author, Name).ConfigureAwait(false);
var releasesList = allReleases.ToList();
if (releasesList.Any())
{
@ -143,7 +131,7 @@ public abstract class BaseGitPackage : BasePackage
}
// Branch mode
var allBranches = await GetAllBranches().ConfigureAwait(false);
var allBranches = await GithubApi.GetAllBranches(Author, Name).ConfigureAwait(false);
packageVersionOptions.AvailableBranches = allBranches.Select(
b => new PackageVersion { TagName = $"{b.Name}", ReleaseNotesMarkdown = string.Empty }
);
@ -423,6 +411,7 @@ public abstract class BaseGitPackage : BasePackage
installedPackage.FullPath!,
onConsoleOutput,
"pull",
"--autostash",
"origin",
installedPackage.Version.InstalledBranch
)

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

@ -166,8 +166,6 @@ public abstract class BasePackage
int page = 1,
int perPage = 10
);
public abstract Task<IEnumerable<Branch>> GetAllBranches();
public abstract Task<IEnumerable<Release>> GetAllReleases();
public abstract Task<DownloadPackageVersionOptions> GetLatestVersion(
bool includePrerelease = false
);

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

@ -188,14 +188,66 @@ public class InvokeAI : BaseGitPackage
var pipCommandArgs =
"-e . --use-pep517 --extra-index-url https://download.pytorch.org/whl/cpu";
var installTorch21 = versionOptions.IsLatest;
if (!string.IsNullOrWhiteSpace(versionOptions.VersionTag) && !versionOptions.IsLatest)
{
if (
Version.TryParse(versionOptions.VersionTag, out var version)
&& version >= new Version(3, 4)
)
{
installTorch21 = true;
}
}
switch (torchVersion)
{
// If has Nvidia Gpu, install CUDA version
case TorchVersion.Cuda:
await InstallCudaTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false);
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
"-e .[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu118";
if (installTorch21)
{
progress?.Report(
new ProgressReport(
-1f,
"Installing PyTorch for CUDA",
isIndeterminate: true
)
);
var args = new List<Argument>();
if (exists)
{
args.Add("--upgrade");
args.Add("--force-reinstall");
}
await venvRunner
.PipInstall(
new PipInstallArgs(
args.Any() ? args.ToArray() : Array.Empty<Argument>()
)
.WithTorch("==2.1.0")
.WithTorchVision("==0.16.0")
.WithXFormers("==0.0.22post7")
.WithTorchExtraIndex("cu121"),
onConsoleOutput
)
.ConfigureAwait(false);
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
"-e .[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu121";
}
else
{
await InstallCudaTorch(venvRunner, progress, onConsoleOutput)
.ConfigureAwait(false);
Logger.Info("Starting InvokeAI install (CUDA)...");
pipCommandArgs =
"-e .[xformers] --use-pep517 --extra-index-url https://download.pytorch.org/whl/cu118";
}
break;
// For AMD, Install ROCm version
case TorchVersion.Rocm:

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

@ -163,12 +163,4 @@ public class UnknownPackage : BasePackage
int page = 1,
int perPage = 10
) => Task.FromResult<IEnumerable<GitCommit>?>(null);
/// <inheritdoc />
public override Task<IEnumerable<Branch>> GetAllBranches() =>
Task.FromResult(Enumerable.Empty<Branch>());
/// <inheritdoc />
public override Task<IEnumerable<Release>> GetAllReleases() =>
Task.FromResult(Enumerable.Empty<Release>());
}

Loading…
Cancel
Save