From 2998ceee2122c17630e633fc611dec9df8fec6f2 Mon Sep 17 00:00:00 2001
From: JT
Date: Sat, 10 Feb 2024 22:35:50 -0800
Subject: [PATCH 001/130] Added models & refit interface for openart stuff
---
StabilityMatrix.Core/Api/IOpenArtApi.cs | 17 ++++++++
.../Models/Api/OpenArt/NodesCount.cs | 15 +++++++
.../Models/Api/OpenArt/OpenArtCreator.cs | 24 ++++++++++++
.../Api/OpenArt/OpenArtDownloadRequest.cs | 15 +++++++
.../Api/OpenArt/OpenArtDownloadResponse.cs | 12 ++++++
.../Models/Api/OpenArt/OpenArtFeedRequest.cs | 18 +++++++++
.../Api/OpenArt/OpenArtSearchRequest.cs | 18 +++++++++
.../Api/OpenArt/OpenArtSearchResponse.cs | 15 +++++++
.../Models/Api/OpenArt/OpenArtSearchResult.cs | 39 +++++++++++++++++++
.../Models/Api/OpenArt/OpenArtStats.cs | 33 ++++++++++++++++
.../Models/Api/OpenArt/OpenArtThumbnail.cs | 15 +++++++
11 files changed, 221 insertions(+)
create mode 100644 StabilityMatrix.Core/Api/IOpenArtApi.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/NodesCount.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadRequest.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadResponse.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchRequest.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResponse.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtThumbnail.cs
diff --git a/StabilityMatrix.Core/Api/IOpenArtApi.cs b/StabilityMatrix.Core/Api/IOpenArtApi.cs
new file mode 100644
index 00000000..e13c8623
--- /dev/null
+++ b/StabilityMatrix.Core/Api/IOpenArtApi.cs
@@ -0,0 +1,17 @@
+using Refit;
+using StabilityMatrix.Core.Models.Api.OpenArt;
+
+namespace StabilityMatrix.Core.Api;
+
+[Headers("User-Agent: StabilityMatrix")]
+public interface IOpenArtApi
+{
+ [Get("/feed")]
+ Task GetFeedAsync([Query] OpenArtFeedRequest request);
+
+ [Get("/list")]
+ Task SearchAsync([Query] OpenArtFeedRequest request);
+
+ [Post("/download")]
+ Task DownloadWorkflowAsync([Body] OpenArtDownloadRequest request);
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/NodesCount.cs b/StabilityMatrix.Core/Models/Api/OpenArt/NodesCount.cs
new file mode 100644
index 00000000..2509dcd7
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/NodesCount.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class NodesCount
+{
+ [JsonPropertyName("total")]
+ public long Total { get; set; }
+
+ [JsonPropertyName("primitive")]
+ public long Primitive { get; set; }
+
+ [JsonPropertyName("custom")]
+ public long Custom { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
new file mode 100644
index 00000000..1f16dc14
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
@@ -0,0 +1,24 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtCreator
+{
+ [JsonPropertyName("uid")]
+ public string Uid { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("bio")]
+ public string Bio { get; set; }
+
+ [JsonPropertyName("avatar")]
+ public Uri Avatar { get; set; }
+
+ [JsonPropertyName("username")]
+ public string Username { get; set; }
+
+ [JsonPropertyName("dev_profile_url")]
+ public Uri DevProfileUrl { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadRequest.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadRequest.cs
new file mode 100644
index 00000000..cdf07d27
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadRequest.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+using Refit;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtDownloadRequest
+{
+ [AliasAs("workflow_id")]
+ [JsonPropertyName("workflow_id")]
+ public required string WorkflowId { get; set; }
+
+ [AliasAs("version_tag")]
+ [JsonPropertyName("version_tag")]
+ public string VersionTag { get; set; } = "latest";
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadResponse.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadResponse.cs
new file mode 100644
index 00000000..3cb61d79
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDownloadResponse.cs
@@ -0,0 +1,12 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtDownloadResponse
+{
+ [JsonPropertyName("filename")]
+ public string Filename { get; set; }
+
+ [JsonPropertyName("payload")]
+ public string Payload { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
new file mode 100644
index 00000000..a3f334d9
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
@@ -0,0 +1,18 @@
+using Refit;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtFeedRequest
+{
+ [AliasAs("category")]
+ public string Category { get; set; }
+
+ [AliasAs("sort")]
+ public string Sort { get; set; }
+
+ [AliasAs("custom_node")]
+ public string CustomNode { get; set; }
+
+ [AliasAs("cursor")]
+ public string Cursor { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchRequest.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchRequest.cs
new file mode 100644
index 00000000..27d944e3
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchRequest.cs
@@ -0,0 +1,18 @@
+using Refit;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtSearchRequest
+{
+ [AliasAs("keyword")]
+ public required string Keyword { get; set; }
+
+ [AliasAs("pageSize")]
+ public int PageSize { get; set; } = 30;
+
+ ///
+ /// 0-based index of the page to retrieve
+ ///
+ [AliasAs("currentPage")]
+ public int CurrentPage { get; set; } = 0;
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResponse.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResponse.cs
new file mode 100644
index 00000000..c58e308a
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResponse.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtSearchResponse
+{
+ [JsonPropertyName("items")]
+ public IEnumerable Items { get; set; }
+
+ [JsonPropertyName("total")]
+ public int Total { get; set; }
+
+ [JsonPropertyName("nextCursor")]
+ public string? NextCursor { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
new file mode 100644
index 00000000..7db9bb4a
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
@@ -0,0 +1,39 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtSearchResult
+{
+ [JsonPropertyName("id")]
+ public string Id { get; set; }
+
+ [JsonPropertyName("creator")]
+ public OpenArtCreator Creator { get; set; }
+
+ [JsonPropertyName("updated_at")]
+ public DateTimeOffset UpdatedAt { get; set; }
+
+ [JsonPropertyName("stats")]
+ public OpenArtStats Stats { get; set; }
+
+ [JsonPropertyName("nodes_index")]
+ public IEnumerable NodesIndex { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("description")]
+ public string Description { get; set; }
+
+ [JsonPropertyName("created_at")]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ [JsonPropertyName("categories")]
+ public IEnumerable Categories { get; set; }
+
+ [JsonPropertyName("thumbnails")]
+ public IEnumerable Thumbnails { get; set; }
+
+ [JsonPropertyName("nodes_count")]
+ public NodesCount NodesCount { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
new file mode 100644
index 00000000..381db723
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
@@ -0,0 +1,33 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtStats
+{
+ [JsonPropertyName("num_shares")]
+ public int NumShares { get; set; }
+
+ [JsonPropertyName("num_bookmarks")]
+ public int NumBookmarks { get; set; }
+
+ [JsonPropertyName("num_reviews")]
+ public int NumReviews { get; set; }
+
+ [JsonPropertyName("rating")]
+ public int Rating { get; set; }
+
+ [JsonPropertyName("num_comments")]
+ public int NumComments { get; set; }
+
+ [JsonPropertyName("num_likes")]
+ public int NumLikes { get; set; }
+
+ [JsonPropertyName("num_downloads")]
+ public int NumDownloads { get; set; }
+
+ [JsonPropertyName("num_runs")]
+ public int NumRuns { get; set; }
+
+ [JsonPropertyName("num_views")]
+ public int NumViews { get; set; }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtThumbnail.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtThumbnail.cs
new file mode 100644
index 00000000..05bfc22f
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtThumbnail.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtThumbnail
+{
+ [JsonPropertyName("width")]
+ public int Width { get; set; }
+
+ [JsonPropertyName("url")]
+ public Uri Url { get; set; }
+
+ [JsonPropertyName("height")]
+ public int Height { get; set; }
+}
From c26960ce1f8457e6ed228dc6e4c687734c03c95c Mon Sep 17 00:00:00 2001
From: JT
Date: Sun, 11 Feb 2024 18:35:51 -0800
Subject: [PATCH 002/130] added basic card UI, searching, and infiniscroll
---
Avalonia.Gif/Avalonia.Gif.csproj | 2 +-
...tabilityMatrix.Avalonia.Diagnostics.csproj | 4 +-
StabilityMatrix.Avalonia/App.axaml.cs | 16 +-
.../Models/IInfinitelyScroll.cs | 8 +
.../StabilityMatrix.Avalonia.csproj | 15 +-
.../ViewModels/OpenArtBrowserViewModel.cs | 175 +++++++++
.../Views/OpenArtBrowserPage.axaml | 340 ++++++++++++++++++
.../Views/OpenArtBrowserPage.axaml.cs | 32 ++
StabilityMatrix.Core/Api/IOpenArtApi.cs | 2 +-
.../Models/Api/OpenArt/OpenArtCreator.cs | 2 +-
.../Models/Api/OpenArt/OpenArtDateTime.cs | 14 +
.../Models/Api/OpenArt/OpenArtFeedRequest.cs | 3 +
.../Models/Api/OpenArt/OpenArtSearchResult.cs | 2 +-
.../Models/Api/OpenArt/OpenArtStats.cs | 2 +-
.../Models/Packages/SDWebForge.cs | 13 +
.../StabilityMatrix.UITests.csproj | 2 +-
16 files changed, 614 insertions(+), 18 deletions(-)
create mode 100644 StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs
create mode 100644 StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
create mode 100644 StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
create mode 100644 StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
create mode 100644 StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDateTime.cs
diff --git a/Avalonia.Gif/Avalonia.Gif.csproj b/Avalonia.Gif/Avalonia.Gif.csproj
index 858b974e..6a363589 100644
--- a/Avalonia.Gif/Avalonia.Gif.csproj
+++ b/Avalonia.Gif/Avalonia.Gif.csproj
@@ -10,7 +10,7 @@
true
-
+
diff --git a/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj b/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj
index e635ad2f..71efd8bb 100644
--- a/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj
+++ b/StabilityMatrix.Avalonia.Diagnostics/StabilityMatrix.Avalonia.Diagnostics.csproj
@@ -19,8 +19,8 @@
-
-
+
+
diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs
index f1c10ddd..05e54065 100644
--- a/StabilityMatrix.Avalonia/App.axaml.cs
+++ b/StabilityMatrix.Avalonia/App.axaml.cs
@@ -333,7 +333,8 @@ public sealed class App : Application
provider.GetRequiredService(),
provider.GetRequiredService(),
provider.GetRequiredService(),
- provider.GetRequiredService()
+ provider.GetRequiredService(),
+ provider.GetRequiredService()
},
FooterPages = { provider.GetRequiredService() }
}
@@ -556,7 +557,7 @@ public sealed class App : Application
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("https://civitai.com");
- c.Timeout = TimeSpan.FromSeconds(15);
+ c.Timeout = TimeSpan.FromSeconds(30);
})
.AddPolicyHandler(retryPolicy);
@@ -565,7 +566,7 @@ public sealed class App : Application
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("https://civitai.com");
- c.Timeout = TimeSpan.FromSeconds(15);
+ c.Timeout = TimeSpan.FromSeconds(30);
})
.AddPolicyHandler(retryPolicy);
@@ -583,6 +584,15 @@ public sealed class App : Application
new TokenAuthHeaderHandler(serviceProvider.GetRequiredService())
);
+ services
+ .AddRefitClient(defaultRefitSettings)
+ .ConfigureHttpClient(c =>
+ {
+ c.BaseAddress = new Uri("https://openart.ai/api/public/workflows");
+ c.Timeout = TimeSpan.FromSeconds(30);
+ })
+ .AddPolicyHandler(retryPolicy);
+
// Add Refit client managers
services.AddHttpClient("A3Client").AddPolicyHandler(localTimeout.WrapAsync(localRetryPolicy));
diff --git a/StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs b/StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs
new file mode 100644
index 00000000..59373816
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs
@@ -0,0 +1,8 @@
+using System.Threading.Tasks;
+
+namespace StabilityMatrix.Avalonia.Models;
+
+public interface IInfinitelyScroll
+{
+ Task LoadNextPageAsync();
+}
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index 1190f686..63e08450 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -39,13 +39,14 @@
-
+
+
-
-
-
+
+
+
-
+
@@ -65,8 +66,8 @@
-
-
+
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
new file mode 100644
index 00000000..c8463037
--- /dev/null
+++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using DynamicData;
+using DynamicData.Binding;
+using FluentAvalonia.UI.Controls;
+using Refit;
+using StabilityMatrix.Avalonia.Models;
+using StabilityMatrix.Avalonia.Services;
+using StabilityMatrix.Avalonia.ViewModels.Base;
+using StabilityMatrix.Avalonia.Views;
+using StabilityMatrix.Core.Api;
+using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Models.Api.OpenArt;
+using StabilityMatrix.Core.Processes;
+using Symbol = FluentIcons.Common.Symbol;
+using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource;
+
+namespace StabilityMatrix.Avalonia.ViewModels;
+
+[View(typeof(OpenArtBrowserPage))]
+[Singleton]
+public partial class OpenArtBrowserViewModel(IOpenArtApi openArtApi, INotificationService notificationService)
+ : PageViewModelBase,
+ IInfinitelyScroll
+{
+ private const int PageSize = 20;
+
+ public override string Title => "Workflows";
+ public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Whiteboard };
+
+ private SourceCache searchResultsCache = new(x => x.Id);
+
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(PageCount), nameof(CanGoBack), nameof(CanGoForward), nameof(CanGoToEnd))]
+ private OpenArtSearchResponse? latestSearchResponse;
+
+ [ObservableProperty]
+ private IObservableCollection searchResults =
+ new ObservableCollectionExtended();
+
+ [ObservableProperty]
+ private string searchQuery = string.Empty;
+
+ [ObservableProperty]
+ private bool isLoading;
+
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(InternalPageNumber), nameof(CanGoBack))]
+ private int displayedPageNumber = 1;
+
+ public int InternalPageNumber => DisplayedPageNumber - 1;
+
+ public int PageCount =>
+ Math.Max(
+ 1,
+ Convert.ToInt32(Math.Ceiling((LatestSearchResponse?.Total ?? 0) / Convert.ToDouble(PageSize)))
+ );
+
+ public bool CanGoBack => InternalPageNumber > 0;
+
+ public bool CanGoForward => PageCount > InternalPageNumber + 1;
+
+ public bool CanGoToEnd => PageCount > InternalPageNumber + 1;
+
+ protected override void OnInitialLoaded()
+ {
+ searchResultsCache.Connect().DeferUntilLoaded().Bind(SearchResults).Subscribe();
+ }
+
+ public override async Task OnLoadedAsync()
+ {
+ if (SearchResults.Any())
+ return;
+
+ await DoSearch();
+ }
+
+ [RelayCommand]
+ private async Task FirstPage()
+ {
+ DisplayedPageNumber = 1;
+ await DoSearch();
+ }
+
+ [RelayCommand]
+ private async Task PreviousPage()
+ {
+ DisplayedPageNumber--;
+ await DoSearch(InternalPageNumber);
+ }
+
+ [RelayCommand]
+ private async Task NextPage()
+ {
+ DisplayedPageNumber++;
+ await DoSearch(InternalPageNumber);
+ }
+
+ [RelayCommand]
+ private async Task LastPage()
+ {
+ DisplayedPageNumber = PageCount;
+ await DoSearch(PageCount - 1);
+ }
+
+ [Localizable(false)]
+ [RelayCommand]
+ private void OpenModel(OpenArtSearchResult workflow)
+ {
+ ProcessRunner.OpenUrl($"https://openart.ai/workflows/{workflow.Id}");
+ }
+
+ [RelayCommand]
+ private async Task SearchButton()
+ {
+ DisplayedPageNumber = 1;
+ await DoSearch();
+ }
+
+ private async Task DoSearch(int page = 0)
+ {
+ IsLoading = true;
+
+ try
+ {
+ var response = await openArtApi.SearchAsync(
+ new OpenArtSearchRequest
+ {
+ Keyword = SearchQuery,
+ PageSize = PageSize,
+ CurrentPage = page
+ }
+ );
+
+ searchResultsCache.EditDiff(response.Items, (a, b) => a.Id == b.Id);
+ LatestSearchResponse = response;
+ }
+ catch (ApiException e)
+ {
+ notificationService.Show("Error retrieving workflows", e.Message);
+ }
+ finally
+ {
+ IsLoading = false;
+ }
+ }
+
+ public async Task LoadNextPageAsync()
+ {
+ try
+ {
+ DisplayedPageNumber++;
+ var response = await openArtApi.SearchAsync(
+ new OpenArtSearchRequest
+ {
+ Keyword = SearchQuery,
+ PageSize = PageSize,
+ CurrentPage = InternalPageNumber
+ }
+ );
+
+ searchResultsCache.AddOrUpdate(response.Items);
+ LatestSearchResponse = response;
+ }
+ catch (ApiException e)
+ {
+ notificationService.Show("Unable to load the next page", e.Message);
+ }
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
new file mode 100644
index 00000000..8e7a621e
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
new file mode 100644
index 00000000..aceb5db4
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
@@ -0,0 +1,32 @@
+using System;
+using AsyncAwaitBestPractices;
+using Avalonia.Controls;
+using StabilityMatrix.Avalonia.Controls;
+using StabilityMatrix.Avalonia.Models;
+using StabilityMatrix.Core.Attributes;
+
+namespace StabilityMatrix.Avalonia.Views;
+
+[Singleton]
+public partial class OpenArtBrowserPage : UserControlBase
+{
+ public OpenArtBrowserPage()
+ {
+ InitializeComponent();
+ }
+
+ private void ScrollViewer_OnScrollChanged(object? sender, ScrollChangedEventArgs e)
+ {
+ if (sender is not ScrollViewer scrollViewer)
+ return;
+
+ if (scrollViewer.Offset.Y == 0)
+ return;
+
+ var isAtEnd = Math.Abs(scrollViewer.Offset.Y - scrollViewer.ScrollBarMaximum.Y) < 0.1f;
+ if (isAtEnd && DataContext is IInfinitelyScroll scroll)
+ {
+ scroll.LoadNextPageAsync().SafeFireAndForget();
+ }
+ }
+}
diff --git a/StabilityMatrix.Core/Api/IOpenArtApi.cs b/StabilityMatrix.Core/Api/IOpenArtApi.cs
index e13c8623..f7e9ae19 100644
--- a/StabilityMatrix.Core/Api/IOpenArtApi.cs
+++ b/StabilityMatrix.Core/Api/IOpenArtApi.cs
@@ -10,7 +10,7 @@ public interface IOpenArtApi
Task GetFeedAsync([Query] OpenArtFeedRequest request);
[Get("/list")]
- Task SearchAsync([Query] OpenArtFeedRequest request);
+ Task SearchAsync([Query] OpenArtSearchRequest request);
[Post("/download")]
Task DownloadWorkflowAsync([Body] OpenArtDownloadRequest request);
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
index 1f16dc14..173d1cef 100644
--- a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtCreator.cs
@@ -20,5 +20,5 @@ public class OpenArtCreator
public string Username { get; set; }
[JsonPropertyName("dev_profile_url")]
- public Uri DevProfileUrl { get; set; }
+ public string DevProfileUrl { get; set; }
}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDateTime.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDateTime.cs
new file mode 100644
index 00000000..5f45a232
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtDateTime.cs
@@ -0,0 +1,14 @@
+using System.Text.Json.Serialization;
+
+namespace StabilityMatrix.Core.Models.Api.OpenArt;
+
+public class OpenArtDateTime
+{
+ [JsonPropertyName("_seconds")]
+ public long Seconds { get; set; }
+
+ public DateTimeOffset ToDateTimeOffset()
+ {
+ return DateTimeOffset.FromUnixTimeSeconds(Seconds);
+ }
+}
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
index a3f334d9..f8dd5255 100644
--- a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtFeedRequest.cs
@@ -2,6 +2,9 @@
namespace StabilityMatrix.Core.Models.Api.OpenArt;
+///
+/// Note that parameters Category, Custom Node and Sort should be used separately
+///
public class OpenArtFeedRequest
{
[AliasAs("category")]
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
index 7db9bb4a..9b007ced 100644
--- a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtSearchResult.cs
@@ -32,7 +32,7 @@ public class OpenArtSearchResult
public IEnumerable Categories { get; set; }
[JsonPropertyName("thumbnails")]
- public IEnumerable Thumbnails { get; set; }
+ public List Thumbnails { get; set; }
[JsonPropertyName("nodes_count")]
public NodesCount NodesCount { get; set; }
diff --git a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
index 381db723..4afa6118 100644
--- a/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
+++ b/StabilityMatrix.Core/Models/Api/OpenArt/OpenArtStats.cs
@@ -14,7 +14,7 @@ public class OpenArtStats
public int NumReviews { get; set; }
[JsonPropertyName("rating")]
- public int Rating { get; set; }
+ public double Rating { get; set; }
[JsonPropertyName("num_comments")]
public int NumComments { get; set; }
diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
index 1e6fd16a..b58c7ec8 100644
--- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
+++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
@@ -79,6 +79,19 @@ public class SDWebForge(
TorchVersion.Mps
};
+ public override Dictionary> SharedOutputFolders =>
+ new()
+ {
+ [SharedOutputType.Extras] = new[] { "output/extras-images" },
+ [SharedOutputType.Saved] = new[] { "log/images" },
+ [SharedOutputType.Img2Img] = new[] { "output/img2img-images" },
+ [SharedOutputType.Text2Img] = new[] { "output/txt2img-images" },
+ [SharedOutputType.Img2ImgGrids] = new[] { "output/img2img-grids" },
+ [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" }
+ };
+
+ public override string OutputFolderName => "output";
+
public override async Task InstallPackage(
string installLocation,
TorchVersion torchVersion,
diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
index 90484174..47cee6c9 100644
--- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
+++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
@@ -15,7 +15,7 @@
-
+
From e87b5032beb11e3d2d57cddbe99de5ee7aa5d48c Mon Sep 17 00:00:00 2001
From: JT
Date: Sun, 11 Feb 2024 19:24:44 -0800
Subject: [PATCH 003/130] rearrange settings & add System.Drawing.Common
reference?
---
.../StabilityMatrix.Avalonia.csproj | 1 +
.../ViewModels/OpenArtBrowserViewModel.cs | 1 -
.../Settings/MainSettingsViewModel.cs | 9 +
.../Views/OpenArtBrowserPage.axaml.cs | 2 +-
.../Views/Settings/MainSettingsPage.axaml | 188 +++++++++---------
.../Models/Settings/Settings.cs | 1 +
.../StabilityMatrix.UITests.csproj | 1 +
7 files changed, 107 insertions(+), 96 deletions(-)
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index 63e08450..fa070fbd 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -95,6 +95,7 @@
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
index c8463037..6f290e70 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
index 55b6c896..2a28e275 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
@@ -129,6 +129,9 @@ public partial class MainSettingsViewModel : PageViewModelBase
[ObservableProperty]
private HolidayMode holidayModeSetting;
+ [ObservableProperty]
+ private bool infinitelyScrollWorkflowBrowser;
+
#region System Info
private static Lazy> GpuInfosLazy { get; } =
@@ -217,6 +220,12 @@ public partial class MainSettingsViewModel : PageViewModelBase
settings => settings.HolidayModeSetting
);
+ settingsManager.RelayPropertyFor(
+ this,
+ vm => vm.InfinitelyScrollWorkflowBrowser,
+ settings => settings.IsWorkflowInfiniteScrollEnabled
+ );
+
DebugThrowAsyncExceptionCommand.WithNotificationErrorHandler(notificationService, LogLevel.Warn);
hardwareInfoUpdateTimer.Tick += OnHardwareInfoUpdateTimerTick;
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
index aceb5db4..c80793c2 100644
--- a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
@@ -23,7 +23,7 @@ public partial class OpenArtBrowserPage : UserControlBase
if (scrollViewer.Offset.Y == 0)
return;
- var isAtEnd = Math.Abs(scrollViewer.Offset.Y - scrollViewer.ScrollBarMaximum.Y) < 0.1f;
+ var isAtEnd = Math.Abs(scrollViewer.Offset.Y - scrollViewer.ScrollBarMaximum.Y) < 1f;
if (isAtEnd && DataContext is IInfinitelyScroll scroll)
{
scroll.LoadNextPageAsync().SafeFireAndForget();
diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
index 369c3f9a..2b846cc0 100644
--- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
@@ -45,77 +45,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -204,40 +195,49 @@
-
-
-
+
+
+
+ Text="{x:Static lang:Resources.Label_Appearance}" />
-
-
-
+ Margin="8,0,8,4"
+ Header="{x:Static lang:Resources.Label_Theme}"
+ IconSource="WeatherMoon">
+
+
+
-
-
-
+ Header="{x:Static lang:Resources.Label_Language}"
+ IconSource="Character">
-
+
-
+
+
diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs
index 50f34f11..fb72ac43 100644
--- a/StabilityMatrix.Core/Models/Settings/Settings.cs
+++ b/StabilityMatrix.Core/Models/Settings/Settings.cs
@@ -120,6 +120,7 @@ public class Settings
public Size InferenceImageSize { get; set; } = new(150, 190);
public Size OutputsImageSize { get; set; } = new(300, 300);
public HolidayMode HolidayModeSetting { get; set; } = HolidayMode.Automatic;
+ public bool IsWorkflowInfiniteScrollEnabled { get; set; } = true;
[JsonIgnore]
public bool IsHolidayModeActive =>
diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
index 47cee6c9..b1cc9ba9 100644
--- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
+++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
@@ -19,6 +19,7 @@
+
From 9f430ecb652c9682d040253459f8e3b98893a0e2 Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 12 Feb 2024 21:43:38 -0800
Subject: [PATCH 004/130] settings n bug fixes
---
.../Languages/Resources.Designer.cs | 27 +++++++++++++++++++
.../Languages/Resources.resx | 9 +++++++
.../ViewModels/OpenArtBrowserViewModel.cs | 3 +++
.../Settings/MainSettingsViewModel.cs | 3 ++-
.../Views/OpenArtBrowserPage.axaml.cs | 13 +++++++--
.../Views/Settings/MainSettingsPage.axaml | 18 +++++++++++++
6 files changed, 70 insertions(+), 3 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 1ff7b216..58714c39 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -1391,6 +1391,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Infinite Scrolling.
+ ///
+ public static string Label_InfiniteScrolling {
+ get {
+ return ResourceManager.GetString("Label_InfiniteScrolling", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Inner exception.
///
@@ -2408,6 +2417,24 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Workflow Browser.
+ ///
+ public static string Label_WorkflowBrowser {
+ get {
+ return ResourceManager.GetString("Label_WorkflowBrowser", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Workflows.
+ ///
+ public static string Label_Workflows {
+ get {
+ return ResourceManager.GetString("Label_Workflows", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to You're up to date.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index 45e700aa..09a64ca3 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -972,4 +972,13 @@
Select Download Location:
+
+ Workflows
+
+
+ Infinite Scrolling
+
+
+ Workflow Browser
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
index 6f290e70..c983ef94 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
@@ -151,6 +151,9 @@ public partial class OpenArtBrowserViewModel(IOpenArtApi openArtApi, INotificati
public async Task LoadNextPageAsync()
{
+ if (!CanGoForward)
+ return;
+
try
{
DisplayedPageNumber++;
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
index 2a28e275..cf46f2c6 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
@@ -223,7 +223,8 @@ public partial class MainSettingsViewModel : PageViewModelBase
settingsManager.RelayPropertyFor(
this,
vm => vm.InfinitelyScrollWorkflowBrowser,
- settings => settings.IsWorkflowInfiniteScrollEnabled
+ settings => settings.IsWorkflowInfiniteScrollEnabled,
+ true
);
DebugThrowAsyncExceptionCommand.WithNotificationErrorHandler(notificationService, LogLevel.Warn);
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
index c80793c2..b6a615f3 100644
--- a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml.cs
@@ -4,14 +4,18 @@ using Avalonia.Controls;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.Views;
[Singleton]
public partial class OpenArtBrowserPage : UserControlBase
{
- public OpenArtBrowserPage()
+ private readonly ISettingsManager settingsManager;
+
+ public OpenArtBrowserPage(ISettingsManager settingsManager)
{
+ this.settingsManager = settingsManager;
InitializeComponent();
}
@@ -24,7 +28,12 @@ public partial class OpenArtBrowserPage : UserControlBase
return;
var isAtEnd = Math.Abs(scrollViewer.Offset.Y - scrollViewer.ScrollBarMaximum.Y) < 1f;
- if (isAtEnd && DataContext is IInfinitelyScroll scroll)
+
+ if (
+ isAtEnd
+ && settingsManager.Settings.IsWorkflowInfiniteScrollEnabled
+ && DataContext is IInfinitelyScroll scroll
+ )
{
scroll.LoadNextPageAsync().SafeFireAndForget();
}
diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
index 2b846cc0..5fb2d8a4 100644
--- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
@@ -196,6 +196,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
Date: Sun, 18 Feb 2024 02:22:05 -0800
Subject: [PATCH 005/130] just put the whole json in there (for now)
---
CHANGELOG.md | 3 +
.../DesignData/DesignData.cs | 56 +
.../Languages/Resources.Designer.cs | 27 +
.../Languages/Resources.resx | 9 +
.../Models/OpenArtCustomNode.cs | 10 +
.../CheckpointBrowserCardViewModel.cs | 20 +-
.../Dialogs/OpenArtWorkflowViewModel.cs | 93 +
.../ViewModels/OpenArtBrowserViewModel.cs | 47 +-
.../Views/Dialogs/OpenArtWorkflowDialog.axaml | 100 +
.../Dialogs/OpenArtWorkflowDialog.axaml.cs | 13 +
.../Views/OpenArtBrowserPage.axaml | 14 +-
StabilityMatrix.Core/Helper/Utilities.cs | 23 +-
.../Models/Api/OpenArt/OpenArtSearchResult.cs | 6 -
StabilityMatrix.Core/Models/ComfyNodeMap.cs | 8420 +++++++++++++++++
14 files changed, 8806 insertions(+), 35 deletions(-)
create mode 100644 StabilityMatrix.Avalonia/Models/OpenArtCustomNode.cs
create mode 100644 StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs
create mode 100644 StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml
create mode 100644 StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml.cs
create mode 100644 StabilityMatrix.Core/Models/ComfyNodeMap.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e207ed4..7cefa26e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,8 +6,11 @@ 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.9.0-dev.3
+### Added
+- Added OpenArt.AI workflow browser for ComfyUI workflows
### Fixed
- Fixed StableSwarmUI not installing properly on macOS
+- Fixed output sharing for Stable Diffusion WebUI Forge
## v2.9.0-dev.2
### Added
diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
index 77d5a384..31d10d8d 100644
--- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs
+++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
@@ -36,6 +36,7 @@ using StabilityMatrix.Core.Helper.Factory;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Api.Comfy;
+using StabilityMatrix.Core.Models.Api.OpenArt;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.PackageModification;
@@ -51,6 +52,7 @@ using HuggingFacePageViewModel = StabilityMatrix.Avalonia.ViewModels.CheckpointB
namespace StabilityMatrix.Avalonia.DesignData;
+[Localizable(false)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class DesignData
{
@@ -1008,6 +1010,60 @@ The gallery images are often inpainted, but you will get something very similar
public static ControlNetCardViewModel ControlNetCardViewModel =>
DialogFactory.Get();
+ public static OpenArtWorkflowViewModel OpenArtWorkflowViewModel =>
+ new()
+ {
+ Workflow = new OpenArtSearchResult
+ {
+ Name = "Test Workflow",
+ Creator = new OpenArtCreator
+ {
+ Name = "Test Creator Name",
+ Username = "Test Creator Username"
+ },
+ Thumbnails =
+ [
+ new OpenArtThumbnail
+ {
+ Url = new Uri(
+ "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/a318ac1f-3ad0-48ac-98cc-79126febcc17/width=1500"
+ )
+ }
+ ],
+ NodesIndex =
+ [
+ "Anything Everywhere",
+ "Reroute",
+ "Note",
+ ".",
+ "ComfyUI's ControlNet Auxiliary Preprocessors",
+ "DWPreprocessor",
+ "PixelPerfectResolution",
+ "AIO_Preprocessor",
+ ",",
+ "ComfyUI",
+ "PreviewImage",
+ "CLIPTextEncode",
+ "EmptyLatentImage",
+ "SplitImageWithAlpha",
+ "ControlNetApplyAdvanced",
+ "JoinImageWithAlpha",
+ "LatentUpscaleBy",
+ "VAEEncode",
+ "LoadImage",
+ "ControlNetLoader",
+ "CLIPVisionLoader",
+ "SaveImage",
+ ",",
+ "ComfyUI Impact Pack",
+ "SAMLoader",
+ "UltralyticsDetectorProvider",
+ "FaceDetailer",
+ ","
+ ]
+ }
+ };
+
public static string CurrentDirectory => Directory.GetCurrentDirectory();
public static Indexer Types { get; } = new();
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 01451192..e96ebd24 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -374,6 +374,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Open on OpenArt.
+ ///
+ public static string Action_OpenOnOpenArt {
+ get {
+ return ResourceManager.GetString("Action_OpenOnOpenArt", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Open Project....
///
@@ -1688,6 +1697,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Node Details.
+ ///
+ public static string Label_NodeDetails {
+ get {
+ return ResourceManager.GetString("Label_NodeDetails", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to No extensions found..
///
@@ -2435,6 +2453,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Workflow Description.
+ ///
+ public static string Label_WorkflowDescription {
+ get {
+ return ResourceManager.GetString("Label_WorkflowDescription", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Workflows.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index e8f7ed3f..91666c7c 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -984,4 +984,13 @@
Config
+
+ Open on OpenArt
+
+
+ Node Details
+
+
+ Workflow Description
+
diff --git a/StabilityMatrix.Avalonia/Models/OpenArtCustomNode.cs b/StabilityMatrix.Avalonia/Models/OpenArtCustomNode.cs
new file mode 100644
index 00000000..b075758d
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Models/OpenArtCustomNode.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace StabilityMatrix.Avalonia.Models;
+
+public class OpenArtCustomNode
+{
+ public required string Title { get; set; }
+ public List Children { get; set; } = [];
+ public bool IsInstalled { get; set; }
+}
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
index 148712c0..bcb2ae62 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
@@ -19,6 +19,7 @@ using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Extensions;
+using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Database;
@@ -216,7 +217,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
MaxDialogHeight = 950,
};
- var prunedDescription = PruneDescription(model);
+ var prunedDescription = Utilities.RemoveHtml(model.Description);
var viewModel = dialogFactory.Get();
viewModel.Dialog = dialog;
@@ -263,23 +264,6 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
await DoImport(model, downloadPath, selectedVersion, selectedFile);
}
- private static string PruneDescription(CivitModel model)
- {
- var prunedDescription =
- model
- .Description?.Replace("
", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("
", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("
", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}")
- .Replace("", $"{Environment.NewLine}{Environment.NewLine}") ?? string.Empty;
- prunedDescription = HtmlRegex().Replace(prunedDescription, string.Empty);
- return prunedDescription;
- }
-
private static async Task SaveCmInfo(
CivitModel model,
CivitModelVersion modelVersion,
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs
new file mode 100644
index 00000000..94ebf773
--- /dev/null
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using CommunityToolkit.Mvvm.ComponentModel;
+using StabilityMatrix.Avalonia.Models;
+using StabilityMatrix.Avalonia.ViewModels.Base;
+using StabilityMatrix.Avalonia.Views.Dialogs;
+using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Helper;
+using StabilityMatrix.Core.Models;
+using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
+using StabilityMatrix.Core.Models.Api.OpenArt;
+
+namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
+
+[View(typeof(OpenArtWorkflowDialog))]
+[ManagedService]
+[Transient]
+public partial class OpenArtWorkflowViewModel : ContentDialogViewModelBase
+{
+ public required OpenArtSearchResult Workflow { get; init; }
+ public string? InstalledComfyPath { get; init; }
+
+ [ObservableProperty]
+ private ObservableCollection customNodes = [];
+
+ [ObservableProperty]
+ private string prunedDescription = string.Empty;
+
+ public override void OnLoaded()
+ {
+ CustomNodes = new ObservableCollection(ParseNodes(Workflow.NodesIndex.ToList()));
+ PrunedDescription = Utilities.RemoveHtml(Workflow.Description);
+ }
+
+ [Localizable(false)]
+ private List ParseNodes(List nodes)
+ {
+ var indexOfFirstDot = nodes.IndexOf(".");
+ if (indexOfFirstDot != -1)
+ {
+ nodes = nodes[(indexOfFirstDot + 1)..];
+ }
+
+ var installedNodes = new List();
+ if (!string.IsNullOrWhiteSpace(InstalledComfyPath))
+ {
+ installedNodes = Directory
+ .EnumerateDirectories(InstalledComfyPath)
+ .Select(
+ x => x.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last()
+ )
+ .Where(x => ComfyNodeMap.Lookup.Values.FirstOrDefault(y => y.EndsWith(x)) != null)
+ .ToList();
+ }
+
+ var sections = new List();
+ OpenArtCustomNode? currentSection = null;
+
+ foreach (var node in nodes)
+ {
+ if (node is "." or ",")
+ {
+ currentSection = null; // End of the current section
+ continue;
+ }
+
+ if (currentSection == null)
+ {
+ currentSection = new OpenArtCustomNode
+ {
+ Title = node,
+ IsInstalled = installedNodes.Contains(node)
+ };
+ sections.Add(currentSection);
+ }
+ else
+ {
+ currentSection.Children.Add(node);
+ }
+ }
+
+ if (sections.FirstOrDefault(x => x.Title == "ComfyUI") != null)
+ {
+ sections = sections.Where(x => x.Title != "ComfyUI").ToList();
+ }
+
+ return sections;
+ }
+}
diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
index c983ef94..6897ee23 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -8,14 +9,18 @@ using DynamicData;
using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
using Refit;
+using StabilityMatrix.Avalonia.Controls;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
+using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.Views;
using StabilityMatrix.Core.Api;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models.Api.OpenArt;
using StabilityMatrix.Core.Processes;
+using StabilityMatrix.Core.Services;
using Symbol = FluentIcons.Common.Symbol;
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource;
@@ -23,16 +28,18 @@ namespace StabilityMatrix.Avalonia.ViewModels;
[View(typeof(OpenArtBrowserPage))]
[Singleton]
-public partial class OpenArtBrowserViewModel(IOpenArtApi openArtApi, INotificationService notificationService)
- : PageViewModelBase,
- IInfinitelyScroll
+public partial class OpenArtBrowserViewModel(
+ IOpenArtApi openArtApi,
+ INotificationService notificationService,
+ ISettingsManager settingsManager
+) : PageViewModelBase, IInfinitelyScroll
{
private const int PageSize = 20;
- public override string Title => "Workflows";
+ public override string Title => Resources.Label_Workflows;
public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Whiteboard };
- private SourceCache searchResultsCache = new(x => x.Id);
+ private readonly SourceCache searchResultsCache = new(x => x.Id);
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(PageCount), nameof(CanGoBack), nameof(CanGoForward), nameof(CanGoToEnd))]
@@ -121,6 +128,36 @@ public partial class OpenArtBrowserViewModel(IOpenArtApi openArtApi, INotificati
await DoSearch();
}
+ [RelayCommand]
+ private async Task OpenWorkflow(OpenArtSearchResult workflow)
+ {
+ var existingComfy = settingsManager.Settings.InstalledPackages.FirstOrDefault(
+ x => x.PackageName is "ComfyUI"
+ );
+
+ var dialog = new BetterContentDialog
+ {
+ IsPrimaryButtonEnabled = true,
+ IsSecondaryButtonEnabled = true,
+ PrimaryButtonText = Resources.Action_Import,
+ SecondaryButtonText = Resources.Action_Cancel,
+ DefaultButton = ContentDialogButton.Primary,
+ IsFooterVisible = true,
+ MaxDialogWidth = 750,
+ MaxDialogHeight = 850,
+ CloseOnClickOutside = true,
+ Content = new OpenArtWorkflowViewModel
+ {
+ Workflow = workflow,
+ InstalledComfyPath = existingComfy is null
+ ? null
+ : Path.Combine(settingsManager.LibraryDir, existingComfy.LibraryPath!, "custom_nodes")
+ },
+ };
+
+ await dialog.ShowAsync();
+ }
+
private async Task DoSearch(int page = 0)
{
IsLoading = true;
diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml
new file mode 100644
index 00000000..af014bf1
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml.cs b/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml.cs
new file mode 100644
index 00000000..e0ed1d00
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Views/Dialogs/OpenArtWorkflowDialog.axaml.cs
@@ -0,0 +1,13 @@
+using StabilityMatrix.Avalonia.Controls;
+using StabilityMatrix.Core.Attributes;
+
+namespace StabilityMatrix.Avalonia.Views.Dialogs;
+
+[Transient]
+public partial class OpenArtWorkflowDialog : UserControlBase
+{
+ public OpenArtWorkflowDialog()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
index 8e7a621e..75a6f54c 100644
--- a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
@@ -66,6 +66,11 @@
+
+
+
-
-
-
+ CornerRadius="8"
+ Command="{StaticResource OpenWorkflowCommand}"
+ CommandParameter="{Binding }">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
index d1460a42..999625ac 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
@@ -12,12 +12,13 @@
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
- mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ xmlns:markupExtensions="clr-namespace:StabilityMatrix.Avalonia.MarkupExtensions"
+ mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="450"
x:DataType="viewModels:PackageManagerViewModel"
x:CompileBindings="True"
d:DataContext="{x:Static designData:DesignData.PackageManagerViewModel}"
x:Class="StabilityMatrix.Avalonia.Views.PackageManagerPage">
-
+
@@ -32,216 +33,34 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
@@ -252,114 +71,328 @@
TextWrapping="Wrap"
Text="{x:Static lang:Resources.Label_UnknownPackage}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+ IsVisible="{Binding IsProgressVisible}"
+ RowDefinitions="Auto, *">
+ !string.IsNullOrWhiteSpace(VersionTag) ? VersionTag : $"{BranchName}@{CommitHash?[..7]}";
}
From d329f37e9d5cc66c893eba3cbfc394890d205b8e Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sat, 2 Mar 2024 14:55:21 -0500
Subject: [PATCH 029/130] Add version requirements for nodes
---
.../Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
index f408dd96..b54547f4 100644
--- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
+++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
@@ -332,7 +332,7 @@ public class ComfyNodeBuilder
[TypedNodeOptions(
Name = "Inference_Core_PromptExpansion",
- RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes"]
+ RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes >= 0.2.0"]
)]
public record PromptExpansion : ComfyTypedNodeBase
{
@@ -344,7 +344,7 @@ public class ComfyNodeBuilder
[TypedNodeOptions(
Name = "Inference_Core_AIO_Preprocessor",
- RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes"]
+ RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes >= 0.2.0"]
)]
public record AIOPreprocessor : ComfyTypedNodeBase
{
From 96c30f5d407f18abb291b999021ea85a0ff32f93 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sat, 2 Mar 2024 14:56:07 -0500
Subject: [PATCH 030/130] Add out of date extension checks
---
.../Base/InferenceGenerationViewModelBase.cs | 69 +++++++++++++++----
1 file changed, 55 insertions(+), 14 deletions(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
index 2d70b02e..63622a72 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
@@ -17,9 +17,9 @@ using CommunityToolkit.Mvvm.Input;
using ExifLibrary;
using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.DependencyInjection;
-using Nito.Disposables.Internals;
using NLog;
using Refit;
+using Semver;
using SkiaSharp;
using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Helpers;
@@ -643,12 +643,10 @@ public abstract partial class InferenceGenerationViewModelBase
{
// Get prompt required extensions
// Just static for now but could do manifest lookup when we support custom workflows
- var requiredExtensions = nodeDictionary
- .ClassTypeRequiredExtensions.Values.SelectMany(x => x)
- .ToHashSet();
+ var requiredExtensionSpecifiers = nodeDictionary.RequiredExtensions.ToList();
// Skip if no extensions required
- if (requiredExtensions.Count == 0)
+ if (requiredExtensionSpecifiers.Count == 0)
{
return true;
}
@@ -661,20 +659,63 @@ public abstract partial class InferenceGenerationViewModelBase
await ((GitPackageExtensionManager)manager).GetInstalledExtensionsLiteAsync(
localPackagePair.InstalledPackage
)
- ).ToImmutableArray();
+ ).ToList();
+
+ var localExtensionsByGitUrl = localExtensions
+ .Where(ext => ext.GitRepositoryUrl is not null)
+ .ToDictionary(ext => ext.GitRepositoryUrl!, ext => ext);
+
+ var requiredExtensionReferences = requiredExtensionSpecifiers
+ .Select(specifier => specifier.Name)
+ .ToHashSet();
+
+ var missingExtensions = new List();
+ var outOfDateExtensions =
+ new List<(ExtensionSpecifier Specifier, InstalledPackageExtension Installed)>();
+
+ // Check missing extensions and out of date extensions
+ foreach (var specifier in requiredExtensionSpecifiers)
+ {
+ if (!localExtensionsByGitUrl.TryGetValue(specifier.Name, out var localExtension))
+ {
+ missingExtensions.Add(specifier);
+ continue;
+ }
- var missingExtensions = requiredExtensions
- .Except(localExtensions.Select(ext => ext.GitRepositoryUrl).WhereNotNull())
- .ToImmutableArray();
+ // Check if constraint is specified
+ if (specifier.Constraint is not null && specifier.TryGetSemVersionRange(out var semVersionRange))
+ {
+ // Get version to compare
+ localExtension = await manager.GetInstalledExtensionInfoAsync(localExtension);
+
+ // Try to parse local tag to semver
+ if (
+ localExtension.Version?.Tag is not null
+ && SemVersion.TryParse(
+ localExtension.Version.Tag,
+ SemVersionStyles.AllowV,
+ out var localSemVersion
+ )
+ )
+ {
+ // Check if not satisfied
+ if (!semVersionRange.Contains(localSemVersion))
+ {
+ outOfDateExtensions.Add((specifier, localExtension));
+ }
+ }
+ }
+ }
- if (missingExtensions.Length == 0)
+ if (missingExtensions.Count == 0 && outOfDateExtensions.Count == 0)
{
return true;
}
var dialog = DialogHelper.CreateMarkdownDialog(
$"#### The following extensions are required for this workflow:\n"
- + $"{string.Join("\n- ", missingExtensions)}",
+ + $"{string.Join("\n- ", missingExtensions.Select(ext => ext.Name))}"
+ + $"{string.Join("\n- ", outOfDateExtensions.Select(pair => $"{pair.Item1.Name} {pair.Specifier.Constraint} {pair.Specifier.Version} (Current Version: {pair.Installed.Version?.Tag})"))}",
"Install Required Extensions?"
);
@@ -692,13 +733,13 @@ public abstract partial class InferenceGenerationViewModelBase
var steps = new List();
- foreach (var missingExtensionUrl in missingExtensions)
+ foreach (var missingExtension in missingExtensions)
{
- if (!manifestExtensionsMap.TryGetValue(missingExtensionUrl, out var extension))
+ if (!manifestExtensionsMap.TryGetValue(missingExtension.Name, out var extension))
{
Logger.Warn(
"Extension {MissingExtensionUrl} not found in manifests",
- missingExtensionUrl
+ missingExtension.Name
);
continue;
}
From 842ab35e7d9f9eef0e39d393ff97142618f2f4c3 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sat, 2 Mar 2024 22:41:57 -0500
Subject: [PATCH 031/130] Add Inference ControlNet preprocessor dimensions
---
.../Controls/Inference/ControlNetCard.axaml | 43 ++++++++++++++++++-
.../Inference/ControlNetCardViewModel.cs | 26 ++++++++++-
.../Inference/Modules/ControlNetModule.cs | 4 +-
3 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
index cb3b8567..b376b780 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
+++ b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
@@ -36,12 +36,12 @@
+
+
+
+
+
+
+
+
();
+
+ // Update our width and height when the image changes
+ SelectImageCardViewModel
+ .WhenPropertyChanged(card => card.CurrentBitmapSize)
+ .Subscribe(propertyValue =>
+ {
+ if (!propertyValue.Value.IsEmpty)
+ {
+ Width = propertyValue.Value.Width;
+ Height = propertyValue.Value.Height;
+ }
+ });
}
[RelayCommand]
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
index f681f053..e4845fc6 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
@@ -56,7 +56,9 @@ public class ControlNetModule : ModuleBase
{
Name = e.Nodes.GetUniqueName("ControlNet_Preprocessor"),
Image = image,
- Preprocessor = preprocessor.RelativePath
+ Preprocessor = preprocessor.RelativePath,
+ // Use width if valid, else default of 512
+ Resolution = card.Width is <= 2048 and > 0 ? card.Width : 512
}
);
From 8f53c281b3abde9fcc061881443429f9addf921b Mon Sep 17 00:00:00 2001
From: JT
Date: Sun, 3 Mar 2024 02:25:49 -0800
Subject: [PATCH 032/130] updated one-click stuff & confirm exit dialog for
multi-package
---
.../Languages/Resources.Designer.cs | 36 +++++++++++++++
.../Languages/Resources.resx | 12 +++++
.../Base/InferenceGenerationViewModelBase.cs | 12 ++---
.../Base/InferenceTabViewModelBase.cs | 16 ++-----
.../InferenceImageToImageViewModel.cs | 20 +++++---
.../InferenceImageToVideoViewModel.cs | 5 +-
.../InferenceImageUpscaleViewModel.cs | 15 ++++--
.../InferenceTextToImageViewModel.cs | 5 +-
.../ViewModels/MainWindowViewModel.cs | 8 ----
.../ViewModels/PackageManagerViewModel.cs | 12 ++---
.../Views/MainWindow.axaml.cs | 46 +++++++++++++++++--
.../Views/PackageManagerPage.axaml | 26 ++++++++++-
.../Views/PackageManagerPage.axaml.cs | 33 ++++++++++++-
13 files changed, 194 insertions(+), 52 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index c56d773b..4802a3a5 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -959,6 +959,24 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Confirm Exit.
+ ///
+ public static string Label_ConfirmExit {
+ get {
+ return ResourceManager.GetString("Label_ConfirmExit", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Are you sure you want to exit? This will also close any currently running packages..
+ ///
+ public static string Label_ConfirmExitDetail {
+ get {
+ return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Confirm Password.
///
@@ -1004,6 +1022,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Console.
+ ///
+ public static string Label_Console {
+ get {
+ return ResourceManager.GetString("Label_Console", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to This will move all generated images from the selected packages to the Consolidated directory of the shared outputs folder. This action cannot be undone..
///
@@ -2399,6 +2426,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Web UI.
+ ///
+ public static string Label_WebUi {
+ get {
+ return ResourceManager.GetString("Label_WebUi", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Width.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index a2129eaf..83430fee 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -978,4 +978,16 @@
Auto-Scroll to End
+
+ Confirm Exit
+
+
+ Are you sure you want to exit? This will also close any currently running packages.
+
+
+ Console
+
+
+ Web UI
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
index 2d70b02e..9fe9cb40 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
@@ -59,6 +59,7 @@ public abstract partial class InferenceGenerationViewModelBase
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ISettingsManager settingsManager;
+ private readonly RunningPackageService runningPackageService;
private readonly INotificationService notificationService;
private readonly ServiceManager vmFactory;
@@ -79,12 +80,14 @@ public abstract partial class InferenceGenerationViewModelBase
ServiceManager vmFactory,
IInferenceClientManager inferenceClientManager,
INotificationService notificationService,
- ISettingsManager settingsManager
+ ISettingsManager settingsManager,
+ RunningPackageService runningPackageService
)
: base(notificationService)
{
this.notificationService = notificationService;
this.settingsManager = settingsManager;
+ this.runningPackageService = runningPackageService;
this.vmFactory = vmFactory;
ClientManager = inferenceClientManager;
@@ -722,15 +725,12 @@ public abstract partial class InferenceGenerationViewModelBase
return;
// Restart Package
- // TODO: This should be handled by some DI package manager service
- var launchPage = App.Services.GetRequiredService();
-
try
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
- await launchPage.Stop();
- await launchPage.LaunchAsync();
+ await runningPackageService.StopPackage(localPackagePair.InstalledPackage.Id);
+ await runningPackageService.StartPackage(localPackagePair.InstalledPackage);
});
}
catch (Exception e)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs
index 63e5b131..57e6bf47 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs
@@ -98,11 +98,7 @@ public abstract partial class InferenceTabViewModelBase
protected async Task SaveViewState()
{
var eventArgs = new SaveViewStateEventArgs();
- saveViewStateRequestedEventManager?.RaiseEvent(
- this,
- eventArgs,
- nameof(SaveViewStateRequested)
- );
+ saveViewStateRequestedEventManager?.RaiseEvent(this, eventArgs, nameof(SaveViewStateRequested));
if (eventArgs.StateTask is not { } stateTask)
{
@@ -128,7 +124,7 @@ public abstract partial class InferenceTabViewModelBase
// TODO: Dock reset not working, using this hack for now to get a new view
var navService = App.Services.GetRequiredService>();
- navService.NavigateTo(new SuppressNavigationTransitionInfo());
+ navService.NavigateTo(new SuppressNavigationTransitionInfo());
((IPersistentViewProvider)this).AttachedPersistentView = null;
navService.NavigateTo(new BetterEntranceNavigationTransition());
}
@@ -157,9 +153,7 @@ public abstract partial class InferenceTabViewModelBase
if (result == ContentDialogResult.Primary && textFields[0].Text is { } json)
{
- LoadViewState(
- new LoadViewStateEventArgs { State = new ViewState { DockLayout = json } }
- );
+ LoadViewState(new LoadViewStateEventArgs { State = new ViewState { DockLayout = json } });
}
}
@@ -226,9 +220,7 @@ public abstract partial class InferenceTabViewModelBase
if (this is IParametersLoadableState paramsLoadableVm)
{
- Dispatcher.UIThread.Invoke(
- () => paramsLoadableVm.LoadStateFromParameters(parameters)
- );
+ Dispatcher.UIThread.Invoke(() => paramsLoadableVm.LoadStateFromParameters(parameters));
}
else
{
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
index 50c4734f..77c5230f 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
@@ -27,9 +27,17 @@ public class InferenceImageToImageViewModel : InferenceTextToImageViewModel
IInferenceClientManager inferenceClientManager,
INotificationService notificationService,
ISettingsManager settingsManager,
- IModelIndexService modelIndexService
+ IModelIndexService modelIndexService,
+ RunningPackageService runningPackageService
)
- : base(notificationService, inferenceClientManager, settingsManager, vmFactory, modelIndexService)
+ : base(
+ notificationService,
+ inferenceClientManager,
+ settingsManager,
+ vmFactory,
+ modelIndexService,
+ runningPackageService
+ )
{
SelectImageCardViewModel = vmFactory.Get();
@@ -77,12 +85,12 @@ public class InferenceImageToImageViewModel : InferenceTextToImageViewModel
var mainImages = SelectImageCardViewModel.GetInputImages();
var samplerImages = SamplerCardViewModel
- .ModulesCardViewModel
- .Cards
- .OfType()
+ .ModulesCardViewModel.Cards.OfType()
.SelectMany(m => m.GetInputImages());
- var moduleImages = ModulesCardViewModel.Cards.OfType().SelectMany(m => m.GetInputImages());
+ var moduleImages = ModulesCardViewModel
+ .Cards.OfType()
+ .SelectMany(m => m.GetInputImages());
return mainImages.Concat(samplerImages).Concat(moduleImages);
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
index b57e3406..035774c1 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
@@ -65,9 +65,10 @@ public partial class InferenceImageToVideoViewModel
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
ServiceManager vmFactory,
- IModelIndexService modelIndexService
+ IModelIndexService modelIndexService,
+ RunningPackageService runningPackageService
)
- : base(vmFactory, inferenceClientManager, notificationService, settingsManager)
+ : base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
this.modelIndexService = modelIndexService;
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
index 2ca1dbd8..540de0d9 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
@@ -59,9 +59,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
INotificationService notificationService,
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
- ServiceManager vmFactory
+ ServiceManager vmFactory,
+ RunningPackageService runningPackageService
)
- : base(vmFactory, inferenceClientManager, notificationService, settingsManager)
+ : base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
@@ -142,7 +143,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
}
///
- protected override async Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
+ protected override async Task GenerateImageImpl(
+ GenerateOverrides overrides,
+ CancellationToken cancellationToken
+ )
{
if (!ClientManager.IsConnected)
{
@@ -169,7 +173,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
Client = ClientManager.Client,
Nodes = buildPromptArgs.Builder.ToNodeDictionary(),
OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(),
- Parameters = new GenerationParameters { ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name, },
+ Parameters = new GenerationParameters
+ {
+ ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name,
+ },
Project = InferenceProjectDocument.FromLoadable(this)
};
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
index 12d0d5fc..a1924559 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
@@ -59,9 +59,10 @@ public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, I
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
ServiceManager vmFactory,
- IModelIndexService modelIndexService
+ IModelIndexService modelIndexService,
+ RunningPackageService runningPackageService
)
- : base(vmFactory, inferenceClientManager, notificationService, settingsManager)
+ : base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
this.modelIndexService = modelIndexService;
diff --git a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
index 5aec5637..718cd574 100644
--- a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
@@ -139,14 +139,6 @@ public partial class MainWindowViewModel : ViewModelBase
Content = new NewOneClickInstallDialog { DataContext = viewModel },
};
- EventManager.Instance.OneClickInstallFinished += (_, skipped) =>
- {
- if (skipped)
- return;
-
- EventManager.Instance.OnTeachingTooltipNeeded();
- };
-
var firstDialogResult = await dialog.ShowAsync(App.TopLevel);
if (firstDialogResult != ContentDialogResult.Primary)
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
index 6066fd02..df3c33a8 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
@@ -6,8 +6,6 @@ using System.Linq;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
-using Avalonia.Controls.Notifications;
-using Avalonia.Controls.Primitives;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.Input;
using DynamicData;
@@ -15,18 +13,14 @@ using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Animations;
-using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
-using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.ViewModels.PackageManager;
using StabilityMatrix.Avalonia.Views;
-using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.FileInterfaces;
-using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Services;
using Symbol = FluentIcons.Common.Symbol;
@@ -84,6 +78,7 @@ public partial class PackageManagerViewModel : PageViewModelBase
this.logger = logger;
EventManager.Instance.InstalledPackagesChanged += OnInstalledPackagesChanged;
+ EventManager.Instance.OneClickInstallFinished += OnOneClickInstallFinished;
var installed = installedPackages.Connect();
var unknown = unknownInstalledPackages.Connect();
@@ -107,6 +102,11 @@ public partial class PackageManagerViewModel : PageViewModelBase
timer.Tick += async (_, _) => await CheckPackagesForUpdates();
}
+ private void OnOneClickInstallFinished(object? sender, bool e)
+ {
+ OnLoadedAsync().SafeFireAndForget();
+ }
+
public void SetPackages(IEnumerable packages)
{
installedPackages.Edit(s => s.Load(packages));
diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
index 614754a6..c720f37b 100644
--- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
+using AsyncAwaitBestPractices;
using AsyncImageLoader;
using Avalonia;
using Avalonia.Controls;
@@ -193,13 +194,52 @@ public partial class MainWindow : AppWindowBase
protected override void OnClosing(WindowClosingEventArgs e)
{
// Show confirmation if package running
- var launchPageViewModel = App.Services.GetRequiredService();
-
- launchPageViewModel.OnMainWindowClosing(e);
+ var runningPackageService = App.Services.GetRequiredService();
+ if (
+ runningPackageService.RunningPackages.Count > 0
+ && e.CloseReason is WindowCloseReason.WindowClosing
+ )
+ {
+ e.Cancel = true;
+
+ var dialog = CreateExitConfirmDialog();
+ Dispatcher
+ .UIThread.InvokeAsync(async () =>
+ {
+ if (
+ (TaskDialogStandardResult)await dialog.ShowAsync(true) == TaskDialogStandardResult.Yes
+ )
+ {
+ App.Services.GetRequiredService().Hide();
+ App.Shutdown();
+ }
+ })
+ .SafeFireAndForget();
+ }
base.OnClosing(e);
}
+ private static TaskDialog CreateExitConfirmDialog()
+ {
+ var dialog = DialogHelper.CreateTaskDialog(
+ Languages.Resources.Label_ConfirmExit,
+ Languages.Resources.Label_ConfirmExitDetail
+ );
+
+ dialog.ShowProgressBar = false;
+ dialog.FooterVisibility = TaskDialogFooterVisibility.Never;
+
+ dialog.Buttons = new List
+ {
+ new("Exit", TaskDialogStandardResult.Yes),
+ TaskDialogButton.CancelButton
+ };
+ dialog.Buttons[0].IsDefault = true;
+
+ return dialog;
+ }
+
///
protected override void OnClosed(EventArgs e)
{
diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
index 999625ac..81c912e6 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
@@ -26,6 +26,7 @@
@@ -284,6 +285,17 @@
+
+
+
@@ -344,7 +357,7 @@
-
+
-
+
+
+
+ {
+ var target = this.FindDescendantOfType()
+ ?.GetVisualChildren()
+ .OfType()
+ .FirstOrDefault(x => x is { Name: "LaunchButton" });
+
+ if (target == null)
+ return;
+
+ var teachingTip = this.FindControl("LaunchTeachingTip");
+ if (teachingTip == null)
+ return;
+
+ teachingTip.Target = target;
+ teachingTip.IsOpen = true;
+ });
}
private void InitializeComponent()
From 685662302dcc8aef773c77f7c6706576f86f3507 Mon Sep 17 00:00:00 2001
From: JT
Date: Sun, 3 Mar 2024 02:58:27 -0800
Subject: [PATCH 033/130] update localizations
---
.../Languages/Resources.Designer.cs | 72 +++++++++++++++++++
.../Languages/Resources.resx | 24 +++++++
.../ViewModels/CheckpointBrowserViewModel.cs | 3 +-
.../ViewModels/CheckpointsPageViewModel.cs | 3 +-
.../ViewModels/FirstLaunchSetupViewModel.cs | 9 ++-
.../ViewModels/InferenceViewModel.cs | 5 +-
.../ViewModels/NewCheckpointsPageViewModel.cs | 3 +-
.../ViewModels/NewPackageManagerViewModel.cs | 3 +-
.../ViewModels/OutputsPageViewModel.cs | 8 +--
.../ViewModels/PackageManagerViewModel.cs | 3 +-
10 files changed, 117 insertions(+), 16 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 4802a3a5..693fbe6b 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -671,6 +671,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to This action cannot be undone..
+ ///
+ public static string Label_ActionCannotBeUndone {
+ get {
+ return ResourceManager.GetString("Label_ActionCannotBeUndone", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Addons.
///
@@ -743,6 +752,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Are you sure you want to delete {0} images?.
+ ///
+ public static string Label_AreYouSureDeleteImages {
+ get {
+ return ResourceManager.GetString("Label_AreYouSureDeleteImages", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Augmentation Level.
///
@@ -851,6 +869,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to We're checking some hardware specifications to determine compatibility..
+ ///
+ public static string Label_CheckingHardware {
+ get {
+ return ResourceManager.GetString("Label_CheckingHardware", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Checkpoint Manager.
///
@@ -860,6 +887,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Checkpoints.
+ ///
+ public static string Label_Checkpoints {
+ get {
+ return ResourceManager.GetString("Label_Checkpoints", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to CivitAI.
///
@@ -1256,6 +1292,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Everything looks good!.
+ ///
+ public static string Label_EverythingLooksGood {
+ get {
+ return ResourceManager.GetString("Label_EverythingLooksGood", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to You may encounter errors when using a FAT32 or exFAT drive. Select a different drive for a smoother experience..
///
@@ -1616,6 +1661,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Model Browser.
+ ///
+ public static string Label_ModelBrowser {
+ get {
+ return ResourceManager.GetString("Label_ModelBrowser", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Model Description.
///
@@ -1742,6 +1796,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to We recommend a GPU with CUDA support for the best experience. You can continue without one, but some packages may not work, and inference may be slower..
+ ///
+ public static string Label_NvidiaGpuRecommended {
+ get {
+ return ResourceManager.GetString("Label_NvidiaGpuRecommended", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to 1 image selected.
///
@@ -1805,6 +1868,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Packages.
+ ///
+ public static string Label_Packages {
+ get {
+ return ResourceManager.GetString("Label_Packages", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Package Type.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index 83430fee..a22000a4 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -990,4 +990,28 @@
Web UI
+
+ Packages
+
+
+ This action cannot be undone.
+
+
+ Are you sure you want to delete {0} images?
+
+
+ We're checking some hardware specifications to determine compatibility.
+
+
+ Everything looks good!
+
+
+ We recommend a GPU with CUDA support for the best experience. You can continue without one, but some packages may not work, and inference may be slower.
+
+
+ Checkpoints
+
+
+ Model Browser
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs
index fd2ccc1f..743d242e 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs
@@ -6,6 +6,7 @@ using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser;
using StabilityMatrix.Avalonia.Views;
@@ -20,7 +21,7 @@ namespace StabilityMatrix.Avalonia.ViewModels;
[Singleton]
public partial class CheckpointBrowserViewModel : PageViewModelBase
{
- public override string Title => "Model Browser";
+ public override string Title => Resources.Label_ModelBrowser;
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.BrainCircuit, IsFilled = true };
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
index f5bc68b9..a3720751 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
@@ -25,6 +25,7 @@ using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Services;
+using Resources = StabilityMatrix.Avalonia.Languages.Resources;
using Symbol = FluentIcons.Common.Symbol;
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource;
using TeachingTip = StabilityMatrix.Core.Models.Settings.TeachingTip;
@@ -43,7 +44,7 @@ public partial class CheckpointsPageViewModel : PageViewModelBase
private readonly INotificationService notificationService;
private readonly IMetadataImportService metadataImportService;
- public override string Title => "Checkpoints";
+ public override string Title => Resources.Label_Checkpoints;
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.Notebook, IsFilled = true };
diff --git a/StabilityMatrix.Avalonia/ViewModels/FirstLaunchSetupViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/FirstLaunchSetupViewModel.cs
index 46815f62..080c29fa 100644
--- a/StabilityMatrix.Avalonia/ViewModels/FirstLaunchSetupViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/FirstLaunchSetupViewModel.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using CommunityToolkit.Mvvm.ComponentModel;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Styles;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views;
@@ -27,11 +28,9 @@ public partial class FirstLaunchSetupViewModel : ViewModelBase
private RefreshBadgeViewModel checkHardwareBadge =
new()
{
- WorkingToolTipText = "We're checking some hardware specifications to determine compatibility.",
- SuccessToolTipText = "Everything looks good!",
- FailToolTipText =
- "We recommend a GPU with CUDA support for the best experience. "
- + "You can continue without one, but some packages may not work, and inference may be slower.",
+ WorkingToolTipText = Resources.Label_CheckingHardware,
+ SuccessToolTipText = Resources.Label_EverythingLooksGood,
+ FailToolTipText = Resources.Label_NvidiaGpuRecommended,
FailColorBrush = ThemeColors.ThemeYellow,
};
diff --git a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs
index 42378ce2..fe596697 100644
--- a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs
@@ -18,6 +18,7 @@ using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using NLog;
using StabilityMatrix.Avalonia.Extensions;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
@@ -56,7 +57,7 @@ public partial class InferenceViewModel : PageViewModelBase, IAsyncDisposable
private readonly RunningPackageService runningPackageService;
private Guid? selectedPackageId;
- public override string Title => "Inference";
+ public override string Title => Resources.Label_Inference;
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.AppGeneric, IsFilled = true };
@@ -66,7 +67,7 @@ public partial class InferenceViewModel : PageViewModelBase, IAsyncDisposable
State = ProgressState.Failed,
FailToolTipText = "Not connected",
FailIcon = FluentAvalonia.UI.Controls.Symbol.Refresh,
- SuccessToolTipText = "Connected",
+ SuccessToolTipText = Resources.Label_Connected,
};
public IInferenceClientManager ClientManager { get; }
diff --git a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs
index 45ea5ed0..ba95645c 100644
--- a/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/NewCheckpointsPageViewModel.cs
@@ -14,6 +14,7 @@ using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.Logging;
using Refit;
using StabilityMatrix.Avalonia.Controls;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.CheckpointManager;
@@ -47,7 +48,7 @@ public partial class NewCheckpointsPageViewModel(
IMetadataImportService metadataImportService
) : PageViewModelBase
{
- public override string Title => "Checkpoint Manager";
+ public override string Title => Resources.Label_CheckpointManager;
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.Cellular5g, IsFilled = true };
diff --git a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs
index 2170f6bf..d96dac06 100644
--- a/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/NewPackageManagerViewModel.cs
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using FluentAvalonia.UI.Controls;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
@@ -18,7 +19,7 @@ namespace StabilityMatrix.Avalonia.ViewModels;
[Singleton]
public partial class NewPackageManagerViewModel : PageViewModelBase
{
- public override string Title => "Packages";
+ public override string Title => Resources.Label_Packages;
public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Box, IsFilled = true };
public IReadOnlyList SubPages { get; }
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index ecb81a55..39b711d6 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -273,8 +273,8 @@ public partial class OutputsPageViewModel : PageViewModelBase
var confirmationDialog = new BetterContentDialog
{
- Title = "Are you sure you want to delete this image?",
- Content = "This action cannot be undone.",
+ Title = Resources.Label_AreYouSure,
+ Content = Resources.Label_ActionCannotBeUndone,
PrimaryButtonText = Resources.Action_Delete,
SecondaryButtonText = Resources.Action_Cancel,
DefaultButton = ContentDialogButton.Primary,
@@ -352,8 +352,8 @@ public partial class OutputsPageViewModel : PageViewModelBase
{
var confirmationDialog = new BetterContentDialog
{
- Title = $"Are you sure you want to delete {NumItemsSelected} images?",
- Content = "This action cannot be undone.",
+ Title = string.Format(Resources.Label_AreYouSureDeleteImages, NumItemsSelected),
+ Content = Resources.Label_ActionCannotBeUndone,
PrimaryButtonText = Resources.Action_Delete,
SecondaryButtonText = Resources.Action_Cancel,
DefaultButton = ContentDialogButton.Primary,
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
index df3c33a8..dfe8757a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
@@ -13,6 +13,7 @@ using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Animations;
+using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.PackageManager;
@@ -42,7 +43,7 @@ public partial class PackageManagerViewModel : PageViewModelBase
private readonly INavigationService packageNavigationService;
private readonly ILogger logger;
- public override string Title => "Packages";
+ public override string Title => Resources.Label_Packages;
public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Box, IsFilled = true };
///
From c2e62926f31a9a386086d3008c7dc2c7cd2a0c9b Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sun, 3 Mar 2024 14:54:47 -0500
Subject: [PATCH 034/130] Made RemoteName public to fix ControlNet preprocessor
loading
---
StabilityMatrix.Core/Models/HybridModelFile.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/StabilityMatrix.Core/Models/HybridModelFile.cs b/StabilityMatrix.Core/Models/HybridModelFile.cs
index 5e0d7275..d5e5efd2 100644
--- a/StabilityMatrix.Core/Models/HybridModelFile.cs
+++ b/StabilityMatrix.Core/Models/HybridModelFile.cs
@@ -20,7 +20,7 @@ public record HybridModelFile
///
public static HybridModelFile None { get; } = FromRemote("@none");
- private string? RemoteName { get; init; }
+ public string? RemoteName { get; init; }
public LocalModelFile? Local { get; init; }
From e94760b5ceb532ec211567a591c37232330f8eca Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sun, 3 Mar 2024 15:32:44 -0500
Subject: [PATCH 035/130] Improve ControlNet preprocessor serialization and non
connected loading
---
.../Controls/Inference/ControlNetCard.axaml | 4 +-
.../DesignData/MockInferenceClientManager.cs | 4 +-
.../Services/IInferenceClientManager.cs | 2 +-
.../Services/InferenceClientManager.cs | 15 ++-
.../Inference/ControlNetCardViewModel.cs | 3 +-
.../Inference/Modules/ControlNetModule.cs | 5 +-
.../Models/Api/Comfy/ComfyAuxPreprocessor.cs | 124 ++++++++++++++++++
7 files changed, 142 insertions(+), 15 deletions(-)
create mode 100644 StabilityMatrix.Core/Models/Api/Comfy/ComfyAuxPreprocessor.cs
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
index b376b780..3dbf04cd 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
+++ b/StabilityMatrix.Avalonia/Controls/Inference/ControlNetCard.axaml
@@ -54,9 +54,9 @@
Margin="0,0,0,4"
SelectedItem="{Binding SelectedPreprocessor}"
ItemsSource="{Binding ClientManager.Preprocessors}"
+ DisplayMemberBinding="{Binding DisplayName}"
HorizontalAlignment="Stretch"
- Header="{x:Static lang:Resources.Label_Preprocessor}"
- Theme="{StaticResource FAComboBoxHybridModelTheme}"/>
+ Header="{x:Static lang:Resources.Label_Preprocessor}"/>
Schedulers { get; } =
new ObservableCollectionExtended(ComfyScheduler.Defaults);
- public IObservableCollection Preprocessors { get; } =
- new ObservableCollectionExtended();
+ public IObservableCollection Preprocessors { get; } =
+ new ObservableCollectionExtended(ComfyAuxPreprocessor.Defaults);
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanUserConnect))]
diff --git a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs
index c4b990b3..75f83447 100644
--- a/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs
+++ b/StabilityMatrix.Avalonia/Services/IInferenceClientManager.cs
@@ -44,7 +44,7 @@ public interface IInferenceClientManager : IDisposable, INotifyPropertyChanged,
IObservableCollection Samplers { get; }
IObservableCollection Upscalers { get; }
IObservableCollection Schedulers { get; }
- IObservableCollection Preprocessors { get; }
+ IObservableCollection Preprocessors { get; }
Task CopyImageToInputAsync(FilePath imageFile, CancellationToken cancellationToken = default);
diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
index 892031bf..22782abb 100644
--- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
+++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
@@ -14,6 +14,7 @@ using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Models.TagCompletion;
using StabilityMatrix.Core.Api;
using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Inference;
using StabilityMatrix.Core.Models;
@@ -101,10 +102,10 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
public IObservableCollection Schedulers { get; } =
new ObservableCollectionExtended();
- public IObservableCollection Preprocessors { get; } =
- new ObservableCollectionExtended();
+ public IObservableCollection Preprocessors { get; } =
+ new ObservableCollectionExtended();
- private readonly SourceCache preprocessorsSource = new(p => p.GetId());
+ private readonly SourceCache preprocessorsSource = new(p => p.Value);
public InferenceClientManager(
ILogger logger,
@@ -284,10 +285,7 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
{ } preprocessorNames
)
{
- preprocessorsSource.EditDiff(
- preprocessorNames.Select(HybridModelFile.FromRemote),
- HybridModelFile.Comparer
- );
+ preprocessorsSource.EditDiff(preprocessorNames.Select(n => new ComfyAuxPreprocessor(n)));
}
}
@@ -361,6 +359,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
u => !modelUpscalersSource.Lookup(u.Name).HasValue
);
downloadableUpscalersSource.EditDiff(remoteUpscalers, ComfyUpscaler.Comparer);
+
+ // Default Preprocessors
+ preprocessorsSource.EditDiff(ComfyAuxPreprocessor.Defaults);
}
///
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
index 6321d1bc..bd7e7c05 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
@@ -11,6 +11,7 @@ using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;
+using StabilityMatrix.Core.Models.Api.Comfy;
namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@@ -29,7 +30,7 @@ public partial class ControlNetCardViewModel : LoadableViewModelBase
[ObservableProperty]
[Required]
- private HybridModelFile? selectedPreprocessor;
+ private ComfyAuxPreprocessor? selectedPreprocessor;
[ObservableProperty]
[Required]
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
index e4845fc6..116e1cdf 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
@@ -6,6 +6,7 @@ using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Models.Api.Comfy;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules;
@@ -49,14 +50,14 @@ public class ControlNetModule : ModuleBase
}
).Output1;
- if (card.SelectedPreprocessor is { } preprocessor && preprocessor.RelativePath != "none")
+ if (card.SelectedPreprocessor is { } preprocessor && preprocessor != ComfyAuxPreprocessor.None)
{
var aioPreprocessor = e.Nodes.AddTypedNode(
new ComfyNodeBuilder.AIOPreprocessor
{
Name = e.Nodes.GetUniqueName("ControlNet_Preprocessor"),
Image = image,
- Preprocessor = preprocessor.RelativePath,
+ Preprocessor = preprocessor.ToString(),
// Use width if valid, else default of 512
Resolution = card.Width is <= 2048 and > 0 ? card.Width : 512
}
diff --git a/StabilityMatrix.Core/Models/Api/Comfy/ComfyAuxPreprocessor.cs b/StabilityMatrix.Core/Models/Api/Comfy/ComfyAuxPreprocessor.cs
new file mode 100644
index 00000000..0b93427f
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Api/Comfy/ComfyAuxPreprocessor.cs
@@ -0,0 +1,124 @@
+using System.Diagnostics.CodeAnalysis;
+using JetBrains.Annotations;
+
+namespace StabilityMatrix.Core.Models.Api.Comfy;
+
+///
+/// Collection of preprocessors included in
+///
+///
+[PublicAPI]
+[SuppressMessage("ReSharper", "InconsistentNaming")]
+public record ComfyAuxPreprocessor(string Value) : StringValue(Value)
+{
+ public static ComfyAuxPreprocessor None { get; } = new("none");
+ public static ComfyAuxPreprocessor AnimeFaceSemSegPreprocessor { get; } =
+ new("AnimeFace_SemSegPreprocessor");
+ public static ComfyAuxPreprocessor BinaryPreprocessor { get; } = new("BinaryPreprocessor");
+ public static ComfyAuxPreprocessor CannyEdgePreprocessor { get; } = new("CannyEdgePreprocessor");
+ public static ComfyAuxPreprocessor ColorPreprocessor { get; } = new("ColorPreprocessor");
+ public static ComfyAuxPreprocessor DensePosePreprocessor { get; } = new("DensePosePreprocessor");
+ public static ComfyAuxPreprocessor DepthAnythingPreprocessor { get; } = new("DepthAnythingPreprocessor");
+ public static ComfyAuxPreprocessor ZoeDepthAnythingPreprocessor { get; } =
+ new("Zoe_DepthAnythingPreprocessor");
+ public static ComfyAuxPreprocessor DiffusionEdgePreprocessor { get; } = new("DiffusionEdge_Preprocessor");
+ public static ComfyAuxPreprocessor DWPreprocessor { get; } = new("DWPreprocessor");
+ public static ComfyAuxPreprocessor AnimalPosePreprocessor { get; } = new("AnimalPosePreprocessor");
+ public static ComfyAuxPreprocessor HEDPreprocessor { get; } = new("HEDPreprocessor");
+ public static ComfyAuxPreprocessor FakeScribblePreprocessor { get; } = new("FakeScribblePreprocessor");
+ public static ComfyAuxPreprocessor LeReSDepthMapPreprocessor { get; } = new("LeReS-DepthMapPreprocessor");
+ public static ComfyAuxPreprocessor LineArtPreprocessor { get; } = new("LineArtPreprocessor");
+ public static ComfyAuxPreprocessor AnimeLineArtPreprocessor { get; } = new("AnimeLineArtPreprocessor");
+ public static ComfyAuxPreprocessor LineartStandardPreprocessor { get; } =
+ new("LineartStandardPreprocessor");
+ public static ComfyAuxPreprocessor Manga2AnimeLineArtPreprocessor { get; } =
+ new("Manga2Anime_LineArt_Preprocessor");
+ public static ComfyAuxPreprocessor MediaPipeFaceMeshPreprocessor { get; } =
+ new("MediaPipe-FaceMeshPreprocessor");
+ public static ComfyAuxPreprocessor MeshGraphormerDepthMapPreprocessor { get; } =
+ new("MeshGraphormer-DepthMapPreprocessor");
+ public static ComfyAuxPreprocessor MiDaSNormalMapPreprocessor { get; } =
+ new("MiDaS-NormalMapPreprocessor");
+ public static ComfyAuxPreprocessor MiDaSDepthMapPreprocessor { get; } = new("MiDaS-DepthMapPreprocessor");
+ public static ComfyAuxPreprocessor MLSDPreprocessor { get; } = new("M-LSDPreprocessor");
+ public static ComfyAuxPreprocessor BAENormalMapPreprocessor { get; } = new("BAE-NormalMapPreprocessor");
+ public static ComfyAuxPreprocessor OneFormerCOCOSemSegPreprocessor { get; } =
+ new("OneFormer-COCO-SemSegPreprocessor");
+ public static ComfyAuxPreprocessor OneFormerADE20KSemSegPreprocessor { get; } =
+ new("OneFormer-ADE20K-SemSegPreprocessor");
+ public static ComfyAuxPreprocessor OpenposePreprocessor { get; } = new("OpenposePreprocessor");
+ public static ComfyAuxPreprocessor PiDiNetPreprocessor { get; } = new("PiDiNetPreprocessor");
+ public static ComfyAuxPreprocessor SavePoseKpsAsJsonFile { get; } = new("SavePoseKpsAsJsonFile");
+ public static ComfyAuxPreprocessor FacialPartColoringFromPoseKps { get; } =
+ new("FacialPartColoringFromPoseKps");
+ public static ComfyAuxPreprocessor ImageLuminanceDetector { get; } = new("ImageLuminanceDetector");
+ public static ComfyAuxPreprocessor ImageIntensityDetector { get; } = new("ImageIntensityDetector");
+ public static ComfyAuxPreprocessor ScribblePreprocessor { get; } = new("ScribblePreprocessor");
+ public static ComfyAuxPreprocessor ScribbleXDoGPreprocessor { get; } = new("Scribble_XDoG_Preprocessor");
+ public static ComfyAuxPreprocessor SAMPreprocessor { get; } = new("SAMPreprocessor");
+ public static ComfyAuxPreprocessor ShufflePreprocessor { get; } = new("ShufflePreprocessor");
+ public static ComfyAuxPreprocessor TEEDPreprocessor { get; } = new("TEEDPreprocessor");
+ public static ComfyAuxPreprocessor TilePreprocessor { get; } = new("TilePreprocessor");
+ public static ComfyAuxPreprocessor UniFormerSemSegPreprocessor { get; } =
+ new("UniFormer-SemSegPreprocessor");
+ public static ComfyAuxPreprocessor SemSegPreprocessor { get; } = new("SemSegPreprocessor");
+ public static ComfyAuxPreprocessor UnimatchOptFlowPreprocessor { get; } =
+ new("Unimatch_OptFlowPreprocessor");
+ public static ComfyAuxPreprocessor MaskOptFlow { get; } = new("MaskOptFlow");
+ public static ComfyAuxPreprocessor ZoeDepthMapPreprocessor { get; } = new("Zoe-DepthMapPreprocessor");
+
+ private static Dictionary DisplayNamesMapping { get; } =
+ new()
+ {
+ [None] = "None",
+ [AnimeFaceSemSegPreprocessor] = "Anime Face SemSeg Preprocessor",
+ [BinaryPreprocessor] = "Binary Preprocessor",
+ [CannyEdgePreprocessor] = "Canny Edge Preprocessor",
+ [ColorPreprocessor] = "Color Preprocessor",
+ [DensePosePreprocessor] = "DensePose Preprocessor",
+ [DepthAnythingPreprocessor] = "Depth Anything Preprocessor",
+ [ZoeDepthAnythingPreprocessor] = "Zoe Depth Anything Preprocessor",
+ [DiffusionEdgePreprocessor] = "Diffusion Edge Preprocessor",
+ [DWPreprocessor] = "DW Preprocessor",
+ [AnimalPosePreprocessor] = "Animal Pose Preprocessor",
+ [HEDPreprocessor] = "HED Preprocessor",
+ [FakeScribblePreprocessor] = "Fake Scribble Preprocessor",
+ [LeReSDepthMapPreprocessor] = "LeReS-DepthMap Preprocessor",
+ [LineArtPreprocessor] = "LineArt Preprocessor",
+ [AnimeLineArtPreprocessor] = "Anime LineArt Preprocessor",
+ [LineartStandardPreprocessor] = "Lineart Standard Preprocessor",
+ [Manga2AnimeLineArtPreprocessor] = "Manga2Anime LineArt Preprocessor",
+ [MediaPipeFaceMeshPreprocessor] = "MediaPipe FaceMesh Preprocessor",
+ [MeshGraphormerDepthMapPreprocessor] = "MeshGraphormer DepthMap Preprocessor",
+ [MiDaSNormalMapPreprocessor] = "MiDaS NormalMap Preprocessor",
+ [MiDaSDepthMapPreprocessor] = "MiDaS DepthMap Preprocessor",
+ [MLSDPreprocessor] = "M-LSD Preprocessor",
+ [BAENormalMapPreprocessor] = "BAE NormalMap Preprocessor",
+ [OneFormerCOCOSemSegPreprocessor] = "OneFormer COCO SemSeg Preprocessor",
+ [OneFormerADE20KSemSegPreprocessor] = "OneFormer ADE20K SemSeg Preprocessor",
+ [OpenposePreprocessor] = "Openpose Preprocessor",
+ [PiDiNetPreprocessor] = "PiDiNet Preprocessor",
+ [SavePoseKpsAsJsonFile] = "Save Pose Kps As Json File",
+ [FacialPartColoringFromPoseKps] = "Facial Part Coloring From Pose Kps",
+ [ImageLuminanceDetector] = "Image Luminance Detector",
+ [ImageIntensityDetector] = "Image Intensity Detector",
+ [ScribblePreprocessor] = "Scribble Preprocessor",
+ [ScribbleXDoGPreprocessor] = "Scribble XDoG Preprocessor",
+ [SAMPreprocessor] = "SAM Preprocessor",
+ [ShufflePreprocessor] = "Shuffle Preprocessor",
+ [TEEDPreprocessor] = "TEED Preprocessor",
+ [TilePreprocessor] = "Tile Preprocessor",
+ [UniFormerSemSegPreprocessor] = "UniFormer SemSeg Preprocessor",
+ [SemSegPreprocessor] = "SemSeg Preprocessor",
+ [UnimatchOptFlowPreprocessor] = "Unimatch OptFlow Preprocessor",
+ [MaskOptFlow] = "Mask OptFlow",
+ [ZoeDepthMapPreprocessor] = "Zoe DepthMap Preprocessor"
+ };
+
+ public static IEnumerable Defaults => DisplayNamesMapping.Keys;
+
+ public string DisplayName => DisplayNamesMapping.GetValueOrDefault(this, Value);
+
+ ///
+ public override string ToString() => Value;
+}
From a15dd34d97e8e50566e8166b0c9569ab9a909c0f Mon Sep 17 00:00:00 2001
From: Ionite
Date: Tue, 5 Mar 2024 16:23:40 -0500
Subject: [PATCH 036/130] Add Debug GC Collect and clear image cache commands
---
.../FallbackRamCachedWebImageLoader.cs | 9 +++++++++
.../Settings/MainSettingsViewModel.cs | 20 ++++++++++++++++++-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs b/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs
index 9c001a92..93951249 100644
--- a/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs
+++ b/StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs
@@ -103,4 +103,13 @@ public class FallbackRamCachedWebImageLoader : RamCachedWebImageLoader
}
}
}
+
+ public void ClearCache()
+ {
+ var cache =
+ this.GetPrivateField>>("_memoryCache")
+ ?? throw new NullReferenceException("Memory cache not found");
+
+ cache.Clear();
+ }
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
index 55b6c896..642d5d5a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
@@ -14,6 +14,7 @@ using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
+using AsyncImageLoader;
using Avalonia;
using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives;
@@ -774,7 +775,9 @@ public partial class MainSettingsViewModel : PageViewModelBase
[
new CommandItem(DebugFindLocalModelFromIndexCommand),
new CommandItem(DebugExtractDmgCommand),
- new CommandItem(DebugShowNativeNotificationCommand)
+ new CommandItem(DebugShowNativeNotificationCommand),
+ new CommandItem(DebugClearImageCacheCommand),
+ new CommandItem(DebugGCCollectCommand)
];
[RelayCommand]
@@ -889,6 +892,21 @@ public partial class MainSettingsViewModel : PageViewModelBase
);
}
+ [RelayCommand]
+ private void DebugClearImageCache()
+ {
+ if (ImageLoader.AsyncImageLoader is FallbackRamCachedWebImageLoader loader)
+ {
+ loader.ClearCache();
+ }
+ }
+
+ [RelayCommand]
+ private void DebugGCCollect()
+ {
+ GC.Collect();
+ }
+
#endregion
#region Info Section
From 9abbaa0f16e312a82034f74414e72e921dad072a Mon Sep 17 00:00:00 2001
From: JT
Date: Tue, 5 Mar 2024 17:20:53 -0800
Subject: [PATCH 037/130] add teaching tip
---
.../Languages/Resources.Designer.cs | 9 +++++++++
StabilityMatrix.Avalonia/Languages/Resources.resx | 3 +++
.../ViewModels/RunningPackageViewModel.cs | 12 ++++++++++++
.../Views/ConsoleOutputPage.axaml | 7 +++++++
StabilityMatrix.Core/Models/Settings/TeachingTip.cs | 1 +
5 files changed, 32 insertions(+)
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 693fbe6b..ab384da9 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -2651,6 +2651,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to The 'Open Web UI' button has moved to the command bar.
+ ///
+ public static string TeachingTip_WebUiButtonMoved {
+ get {
+ return ResourceManager.GetString("TeachingTip_WebUiButtonMoved", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The app will relaunch after updating.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index a22000a4..c8fc96d3 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -1014,4 +1014,7 @@
Model Browser
+
+ The 'Open Web UI' button has moved to the command bar
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
index b1129352..38011e04 100644
--- a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
@@ -13,12 +13,14 @@ using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Services;
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource;
+using TeachingTip = StabilityMatrix.Core.Models.Settings.TeachingTip;
namespace StabilityMatrix.Avalonia.ViewModels;
[View(typeof(ConsoleOutputPage))]
public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, IAsyncDisposable
{
+ private readonly ISettingsManager settingsManager;
private readonly INotificationService notificationService;
private readonly RunningPackageService runningPackageService;
@@ -42,6 +44,9 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
[ObservableProperty]
private string consoleInput = string.Empty;
+ [ObservableProperty]
+ private bool showWebUiTeachingTip;
+
///
public RunningPackageViewModel(
ISettingsManager settingsManager,
@@ -51,6 +56,7 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
ConsoleViewModel console
)
{
+ this.settingsManager = settingsManager;
this.notificationService = notificationService;
this.runningPackageService = runningPackageService;
@@ -82,6 +88,12 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
{
WebUiUrl = url.Replace("0.0.0.0", "127.0.0.1");
ShowWebUiButton = !string.IsNullOrWhiteSpace(WebUiUrl);
+
+ if (settingsManager.Settings.SeenTeachingTips.Contains(TeachingTip.WebUiButtonMovedTip))
+ return;
+
+ ShowWebUiTeachingTip = true;
+ settingsManager.Transaction(s => s.SeenTeachingTips.Add(TeachingTip.WebUiButtonMovedTip));
}
private void DocumentOnLineCountChanged(object? sender, EventArgs e)
diff --git a/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml b/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
index 7e1634e9..85f4e34b 100644
--- a/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
@@ -51,6 +51,7 @@
Command="{Binding LaunchWebUiCommand}"
IsVisible="{Binding ShowWebUiButton}"
VerticalAlignment="Center"
+ x:Name="OpenWebUiButton"
Label="{x:Static lang:Resources.Action_OpenWebUI}">
@@ -82,5 +83,11 @@
Content="{x:Static lang:Resources.Action_Send}"
Command="{Binding SendToConsoleCommand}"/>
+
+
diff --git a/StabilityMatrix.Core/Models/Settings/TeachingTip.cs b/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
index 756e6cce..92a6ea3d 100644
--- a/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
+++ b/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
@@ -13,6 +13,7 @@ public record TeachingTip(string Value) : StringValue(Value)
public static TeachingTip CheckpointCategoriesTip => new("CheckpointCategoriesTip");
public static TeachingTip PackageExtensionsInstallNotice => new("PackageExtensionsInstallNotice");
public static TeachingTip DownloadsTip => new("DownloadsTip");
+ public static TeachingTip WebUiButtonMovedTip => new("WebUiButtonMovedTip");
///
public override string ToString()
From ea9dc5a3d2366e9ea9f8725cca76448f1789f8ad Mon Sep 17 00:00:00 2001
From: JT
Date: Tue, 5 Mar 2024 19:06:59 -0800
Subject: [PATCH 038/130] Changed from a dropdown list to a TreeView for
outputs browser
---
.../DesignData/DesignData.cs | 10 ++
.../Models/PackageOutputCategory.cs | 5 +-
.../ViewModels/OutputsPageViewModel.cs | 43 +++++--
.../Views/OutputsPage.axaml | 105 +++++++-----------
.../Models/Settings/Settings.cs | 1 +
5 files changed, 92 insertions(+), 72 deletions(-)
diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
index 77d5a384..48d0602e 100644
--- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs
+++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
@@ -507,6 +507,16 @@ public static class DesignData
}
)
};
+ vm.Categories =
+ [
+ new PackageOutputCategory
+ {
+ Name = "Category 1",
+ Path = "path1",
+ SubDirectories = [new PackageOutputCategory { Name = "SubCategory 1", Path = "path3" }]
+ },
+ new PackageOutputCategory { Name = "Category 2", Path = "path2" }
+ ];
return vm;
}
}
diff --git a/StabilityMatrix.Avalonia/Models/PackageOutputCategory.cs b/StabilityMatrix.Avalonia/Models/PackageOutputCategory.cs
index 2318d0f8..62b69917 100644
--- a/StabilityMatrix.Avalonia/Models/PackageOutputCategory.cs
+++ b/StabilityMatrix.Avalonia/Models/PackageOutputCategory.cs
@@ -1,7 +1,10 @@
-namespace StabilityMatrix.Avalonia.Models;
+using System.Collections.ObjectModel;
+
+namespace StabilityMatrix.Avalonia.Models;
public class PackageOutputCategory
{
+ public ObservableCollection SubDirectories { get; set; } = new();
public required string Name { get; set; }
public required string Path { get; set; }
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index ecb81a55..0728a792 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -86,6 +86,9 @@ public partial class OutputsPageViewModel : PageViewModelBase
[ObservableProperty]
private bool isConsolidating;
+ [ObservableProperty]
+ private bool showFolders;
+
public bool CanShowOutputTypes => SelectedCategory?.Name?.Equals("Shared Output Folder") ?? false;
public string NumImagesSelected =>
@@ -136,6 +139,13 @@ public partial class OutputsPageViewModel : PageViewModelBase
settings => settings.OutputsImageSize,
delay: TimeSpan.FromMilliseconds(250)
);
+
+ settingsManager.RelayPropertyFor(
+ this,
+ vm => vm.ShowFolders,
+ settings => settings.IsOutputsTreeViewEnabled,
+ true
+ );
}
protected override void OnInitialLoaded()
@@ -559,7 +569,10 @@ public partial class OutputsPageViewModel : PageViewModelBase
pair.InstalledPackage.FullPath!,
pair.BasePackage.OutputFolderName
),
- Name = pair.InstalledPackage.DisplayName ?? ""
+ Name = pair.InstalledPackage.DisplayName ?? "",
+ SubDirectories = GetSubfolders(
+ Path.Combine(pair.InstalledPackage.FullPath!, pair.BasePackage.OutputFolderName)
+ )
}
)
.ToList();
@@ -569,18 +582,34 @@ public partial class OutputsPageViewModel : PageViewModelBase
new PackageOutputCategory
{
Path = settingsManager.ImagesDirectory,
- Name = "Shared Output Folder"
+ Name = "Shared Output Folder",
+ SubDirectories = GetSubfolders(settingsManager.ImagesDirectory)
}
);
- packageCategories.Insert(
- 1,
- new PackageOutputCategory { Path = settingsManager.ImagesInferenceDirectory, Name = "Inference" }
- );
-
Categories = new ObservableCollection(packageCategories);
SelectedCategory =
Categories.FirstOrDefault(x => x.Name == previouslySelectedCategory?.Name) ?? Categories.First();
}
+
+ private ObservableCollection GetSubfolders(string strPath)
+ {
+ var subfolders = new ObservableCollection();
+ var directories = Directory.EnumerateDirectories(strPath, "*", SearchOption.TopDirectoryOnly);
+
+ foreach (var dir in directories)
+ {
+ var category = new PackageOutputCategory { Name = Path.GetFileName(dir), Path = dir };
+
+ if (Directory.GetDirectories(dir, "*", SearchOption.TopDirectoryOnly).Length > 0)
+ {
+ category.SubDirectories = GetSubfolders(dir);
+ }
+
+ subfolders.Add(category);
+ }
+
+ return subfolders;
+ }
}
diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
index 3b1a02bb..46b81990 100644
--- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
@@ -23,13 +23,29 @@
x:DataType="vm:OutputsPageViewModel"
Focusable="True"
mc:Ignorable="d">
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
+
@@ -161,7 +136,8 @@
-
+
-
+
From d5f726d9d66ef7c0874162115dba2f60223cbba1 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 6 Mar 2024 19:51:02 -0500
Subject: [PATCH 039/130] Add DebugExtractImagePromptsToTxt Command
---
.../Settings/MainSettingsViewModel.cs | 42 ++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
index 642d5d5a..8fdfe91d 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
@@ -777,7 +777,8 @@ public partial class MainSettingsViewModel : PageViewModelBase
new CommandItem(DebugExtractDmgCommand),
new CommandItem(DebugShowNativeNotificationCommand),
new CommandItem(DebugClearImageCacheCommand),
- new CommandItem(DebugGCCollectCommand)
+ new CommandItem(DebugGCCollectCommand),
+ new CommandItem(DebugExtractImagePromptsToTxtCommand)
];
[RelayCommand]
@@ -907,6 +908,45 @@ public partial class MainSettingsViewModel : PageViewModelBase
GC.Collect();
}
+ [RelayCommand]
+ private async Task DebugExtractImagePromptsToTxt()
+ {
+ // Choose images
+ var provider = App.StorageProvider;
+ var files = await provider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = true });
+
+ if (files.Count == 0)
+ return;
+
+ var images = await Task.Run(
+ () => files.Select(f => LocalImageFile.FromPath(f.TryGetLocalPath()!)).ToList()
+ );
+
+ var successfulFiles = new List();
+
+ foreach (var localImage in images)
+ {
+ var imageFile = new FilePath(localImage.AbsolutePath);
+
+ // Write a txt with the same name as the image
+ var txtFile = imageFile.WithName(imageFile.NameWithoutExtension + ".txt");
+
+ // Read metadata
+ if (localImage.GenerationParameters?.PositivePrompt is { } positivePrompt)
+ {
+ await File.WriteAllTextAsync(txtFile, positivePrompt);
+
+ successfulFiles.Add(localImage);
+ }
+ }
+
+ notificationService.Show(
+ "Extracted prompts",
+ $"Extracted prompts from {successfulFiles.Count}/{images.Count} images.",
+ NotificationType.Success
+ );
+ }
+
#endregion
#region Info Section
From 09c72677b7547f294d5af39bed675882c4660963 Mon Sep 17 00:00:00 2001
From: JT
Date: Wed, 6 Mar 2024 19:00:09 -0800
Subject: [PATCH 040/130] fix crash when directory not exist
---
StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index 0728a792..a2685a24 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -596,6 +596,10 @@ public partial class OutputsPageViewModel : PageViewModelBase
private ObservableCollection GetSubfolders(string strPath)
{
var subfolders = new ObservableCollection();
+
+ if (!Directory.Exists(strPath))
+ return subfolders;
+
var directories = Directory.EnumerateDirectories(strPath, "*", SearchOption.TopDirectoryOnly);
foreach (var dir in directories)
From b394e5b701c94c933d0039cc006ce95548dd356b Mon Sep 17 00:00:00 2001
From: JT
Date: Wed, 6 Mar 2024 21:36:32 -0800
Subject: [PATCH 041/130] faster outputs page with Task.Run & avalonia.labs
async image
---
StabilityMatrix.Avalonia/App.axaml | 2 +
.../SelectableImageButton.axaml | 5 +-
.../SelectableImageButton.cs | 8 ++-
.../ViewModels/OutputsPageViewModel.cs | 70 ++++++++++++++-----
.../Views/OutputsPage.axaml | 43 ++++++++++--
.../Models/Database/LocalImageFile.cs | 2 +
6 files changed, 100 insertions(+), 30 deletions(-)
diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml
index a1bf280c..fa669962 100644
--- a/StabilityMatrix.Avalonia/App.axaml
+++ b/StabilityMatrix.Avalonia/App.axaml
@@ -4,6 +4,7 @@
xmlns:local="using:StabilityMatrix.Avalonia"
xmlns:idcr="using:Dock.Avalonia.Controls.Recycling"
xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia"
+ xmlns:controls="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
Name="Stability Matrix"
RequestedThemeVariant="Dark">
@@ -80,6 +81,7 @@
+
+
+
+
@@ -161,13 +190,15 @@
-
+
-
+
@@ -177,7 +208,7 @@
ImageHeight="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).ImageSize.Height}"
ImageWidth="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).ImageSize.Width}"
IsSelected="{Binding IsSelected}"
- Source="{Binding ImageFile.AbsolutePath}">
+ Source="{Binding ImageFile.AbsolutePathUriString}">
public string FileNameWithoutExtension => Path.GetFileNameWithoutExtension(AbsolutePath);
+ public Uri AbsolutePathUriString => new($"file://{AbsolutePath}");
+
public (string? Parameters, string? ParametersJson, string? SMProject, string? ComfyNodes) ReadMetadata()
{
if (AbsolutePath.EndsWith("webp"))
From aed6e79957c3cf1d54a1baa94910164f44f7a1fe Mon Sep 17 00:00:00 2001
From: JT
Date: Wed, 6 Mar 2024 21:47:59 -0800
Subject: [PATCH 042/130] chagenlog
---
CHANGELOG.md | 4 ++++
StabilityMatrix.Avalonia/Views/OutputsPage.axaml | 7 +------
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3acb129..01d5ba5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ 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.10.0-dev.1
+### Changed
+- Changed the Outputs Page to use a TreeView for the directory selection instead of a dropdown selector
+
## v2.9.0
### Added
- Added new package: [StableSwarmUI](https://github.com/Stability-AI/StableSwarmUI) by Stability AI
diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
index 46b81990..b679e541 100644
--- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
@@ -54,12 +54,7 @@
-
-
+
Date: Wed, 6 Mar 2024 21:50:22 -0800
Subject: [PATCH 043/130] moar chagenlog
---
CHANGELOG.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01d5ba5a..f1472e89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
## v2.10.0-dev.1
### Changed
+- Revamped the Packages page to enable running multiple packages at the same time
- Changed the Outputs Page to use a TreeView for the directory selection instead of a dropdown selector
+### Removed
+- Removed the main Launch page, as it is no longer needed with the new Packages page
## v2.9.0
### Added
From 6fb5b0cb17514bf2902238f7afcad7215d67dd7f Mon Sep 17 00:00:00 2001
From: JT
Date: Wed, 6 Mar 2024 22:01:40 -0800
Subject: [PATCH 044/130] add the treeview back
---
.../Views/OutputsPage.axaml | 54 ++++++++++---------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
index dcc05e1c..ad145027 100644
--- a/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/OutputsPage.axaml
@@ -16,8 +16,6 @@
xmlns:selectableImageCard="clr-namespace:StabilityMatrix.Avalonia.Controls.SelectableImageCard"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
- xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
- xmlns:system="clr-namespace:System;assembly=System.Runtime"
d:DataContext="{x:Static mocks:DesignData.OutputsPageViewModel}"
d:DesignHeight="650"
d:DesignWidth="800"
@@ -25,20 +23,29 @@
x:DataType="vm:OutputsPageViewModel"
Focusable="True"
mc:Ignorable="d">
-
-
-
- loading
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+ Margin="8,0" />
+ VerticalAlignment="Center" />
@@ -96,7 +113,7 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+ Stretch="UniformToFill" />
+
+ Grid.RowSpan="2"
+ CornerRadius="8"
+ Width="330"
+ Height="400"
+ FontSize="100"
+ IsVisible="{Binding FirstThumbnail, Converter={x:Static ObjectConverters.IsNull}, FallbackValue=False}"
+ Value="fa-regular fa-file-code" />
+
-
+
+
+
+
+
+
+ Text="{Binding Workflow.Name}"
+ ToolTip.Tip="{Binding Workflow.Name}" />
diff --git a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
index 2d377dd1..867d2a62 100644
--- a/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/OpenArtBrowserPage.axaml
@@ -12,6 +12,7 @@
xmlns:avalonia="https://github.com/projektanker/icons.avalonia"
xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
x:DataType="viewModels:OpenArtBrowserViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="StabilityMatrix.Avalonia.Views.OpenArtBrowserPage">
@@ -23,7 +24,7 @@
-
+
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
index 86c40520..67b75973 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
+++ b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
@@ -9,6 +9,7 @@
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:scroll="clr-namespace:StabilityMatrix.Avalonia.Controls.Scroll"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
x:DataType="vmInference:ImageFolderCardViewModel">
@@ -195,12 +196,11 @@
-
+ Stretch="UniformToFill" />
@@ -115,12 +116,11 @@
-
+ Source="{Binding Uri}"
+ Stretch="Uniform" />
diff --git a/StabilityMatrix.Avalonia/Models/ImageSource.cs b/StabilityMatrix.Avalonia/Models/ImageSource.cs
index 973b0bf6..0da5749d 100644
--- a/StabilityMatrix.Avalonia/Models/ImageSource.cs
+++ b/StabilityMatrix.Avalonia/Models/ImageSource.cs
@@ -58,6 +58,8 @@ public record ImageSource : IDisposable, ITemplateKey
Bitmap = bitmap;
}
+ public Uri? Uri => LocalFile?.FullPath != null ? new Uri(LocalFile.FullPath) : RemoteUrl;
+
///
public ImageSourceTemplateType TemplateKey { get; private set; }
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index cda7adcd..b3fba009 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -39,17 +39,17 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
+
+
@@ -58,10 +58,10 @@
-
-
-
-
+
+
+
+
@@ -78,25 +78,25 @@
-
+
-
+
-
+
-
-
+
+
-
+
diff --git a/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml
index 61d77d82..652a4ade 100644
--- a/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml
+++ b/StabilityMatrix.Avalonia/Styles/ControlThemes/BetterComboBoxStyles.axaml
@@ -6,7 +6,8 @@
xmlns:mocks="using:StabilityMatrix.Avalonia.DesignData"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
- xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls">
@@ -42,15 +43,14 @@
ColumnSpacing="6"
RowSpacing="0">
-
+ Stretch="UniformToFill"/>
-
-
-
-
-
+ Stretch="UniformToFill"/>
-
-
-
-
-
+ Stretch="UniformToFill">
+
{
NumItemsSelected = Outputs.Count(o => o.IsSelected);
+ Console.WriteLine($"Subscribe called");
});
categoriesCache.Connect().DeferUntilLoaded().Bind(Categories).Subscribe();
@@ -395,12 +396,13 @@ public partial class OutputsPageViewModel : PageViewModelBase
var selected = Outputs.Where(o => o.IsSelected).ToList();
Debug.Assert(selected.Count == NumItemsSelected);
+
+ var imagesToRemove = new List();
foreach (var output in selected)
{
// Delete the file
var imageFile = new FilePath(output.ImageFile.AbsolutePath);
var result = await notificationService.TryAsync(imageFile.DeleteAsync());
-
if (!result.IsSuccessful)
{
continue;
@@ -413,15 +415,10 @@ public partial class OutputsPageViewModel : PageViewModelBase
await notificationService.TryAsync(sideCar.DeleteAsync());
}
- OutputsCache.Remove(output.ImageFile);
-
- // Invalidate cache
- if (ImageLoader.AsyncImageLoader is FallbackRamCachedWebImageLoader loader)
- {
- loader.RemoveAllNamesFromCache(imageFile.Name);
- }
+ imagesToRemove.Add(output.ImageFile);
}
+ OutputsCache.Remove(imagesToRemove);
NumItemsSelected = 0;
ClearSelection();
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs
index 93f3534a..71d624ec 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs
@@ -54,7 +54,7 @@ public partial class PackageCardViewModel(
private InstalledPackage? package;
[ObservableProperty]
- private string? cardImageSource;
+ private Uri? cardImageSource;
[ObservableProperty]
private bool isUpdateAvailable;
@@ -127,7 +127,7 @@ public partial class PackageCardViewModel(
)
{
IsUnknownPackage = true;
- CardImageSource = "";
+ CardImageSource = null;
InstalledVersion = "Unknown";
}
else
@@ -135,7 +135,7 @@ public partial class PackageCardViewModel(
IsUnknownPackage = false;
var basePackage = packageFactory[value.PackageName];
- CardImageSource = basePackage?.PreviewImageUri.ToString() ?? Assets.NoImage.ToString();
+ CardImageSource = basePackage?.PreviewImageUri ?? Assets.NoImage;
InstalledVersion = value.Version?.DisplayVersion ?? "Unknown";
CanUseConfigMethod =
basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Configuration) ?? false;
diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml
index c2831986..bbb08dae 100644
--- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml
@@ -13,6 +13,7 @@
xmlns:api="clr-namespace:StabilityMatrix.Core.Models.Api;assembly=StabilityMatrix.Core"
xmlns:generic="clr-namespace:System.Collections.Generic;assembly=System.Collections"
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
d:DataContext="{x:Static mocks:DesignData.CheckpointsPageViewModel}"
x:CompileBindings="True"
x:DataType="vm:CheckpointsPageViewModel"
@@ -138,7 +139,7 @@
TextWrapping="WrapWithOverflow"
IsVisible="{Binding IsConnectedModel}" />
-
-
+
-
@@ -60,7 +60,7 @@
@@ -103,7 +103,7 @@
CommandParameter="{Binding CivitModel}"
IsEnabled="{Binding !IsImporting}">
- -->
-
-
+
-
+ Source="{Binding CivitModel.Creator.Image}">
+
-
-
-
@@ -52,7 +52,7 @@
@@ -121,6 +121,7 @@
CornerRadius="16"
Margin="4"
Grid.Row="0"
+ ClipToBounds="True"
HorizontalAlignment="Left"
VerticalAlignment="Bottom">
@@ -142,14 +143,16 @@
Classes="transparent"
Padding="10,4">
-
+ Source="{Binding Creator.Avatar}">
+
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
index 5abbe50b..08436b3b 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
@@ -1,4 +1,6 @@
-using Avalonia.Input;
+using System.Diagnostics;
+using Avalonia.Input;
+using Avalonia.Labs.Controls;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.ViewModels.PackageManager;
using StabilityMatrix.Core.Attributes;
@@ -20,4 +22,9 @@ public partial class PackageInstallBrowserView : UserControlBase
vm.ClearSearchQuery();
}
}
+
+ private void AsyncImage_OnFailed(object? sender, AsyncImage.AsyncImageFailedEventArgs e)
+ {
+ Debug.WriteLine($"Failed to load image: {e.ErrorException?.Message}");
+ }
}
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
index 91b2e671..7bf74c46 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
@@ -2,7 +2,6 @@
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:viewModels="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:designData="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
@@ -10,24 +9,26 @@
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core"
xmlns:database="clr-namespace:StabilityMatrix.Core.Models.Database;assembly=StabilityMatrix.Core"
- xmlns:extensions="clr-namespace:StabilityMatrix.Core.Models.Packages.Extensions;assembly=StabilityMatrix.Core"
xmlns:packageManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.PackageManager"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="packageManager:PackageInstallDetailViewModel"
x:CompileBindings="True"
d:DataContext="{x:Static designData:DesignData.PackageInstallDetailViewModel}"
x:Class="StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallDetailView">
-
+
-
+ Margin="16, 16, 8, 8"
+ CornerRadius="8"
+ Source="{Binding SelectedPackage.PreviewImageUri}">
+
+
diff --git a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
index 81c912e6..ee2099d9 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
@@ -13,6 +13,7 @@
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:markupExtensions="clr-namespace:StabilityMatrix.Avalonia.MarkupExtensions"
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="450"
x:DataType="viewModels:PackageManagerViewModel"
x:CompileBindings="True"
@@ -44,15 +45,13 @@
-
diff --git a/StabilityMatrix.Core/StabilityMatrix.Core.csproj b/StabilityMatrix.Core/StabilityMatrix.Core.csproj
index de135217..5005b1bd 100644
--- a/StabilityMatrix.Core/StabilityMatrix.Core.csproj
+++ b/StabilityMatrix.Core/StabilityMatrix.Core.csproj
@@ -17,8 +17,8 @@
-
-
+
+
@@ -27,10 +27,10 @@
-
+
-
+
@@ -45,7 +45,7 @@
-
+
@@ -53,7 +53,7 @@
-
+
diff --git a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj
index 6283704a..257b8f93 100644
--- a/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj
+++ b/StabilityMatrix.Tests/StabilityMatrix.Tests.csproj
@@ -17,18 +17,18 @@
-
+
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
index d4c1e79e..eb592e08 100644
--- a/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
+++ b/StabilityMatrix.UITests/StabilityMatrix.UITests.csproj
@@ -15,16 +15,16 @@
-
+
-
-
+
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
From b2a76056afd02b244143b5a3f47fd14568dde92b Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 25 Mar 2024 23:30:57 -0700
Subject: [PATCH 095/130] phrasing
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2787d790..8f66aa16 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ Multi-Platform Package Manager and Inference UI for Stable Diffusion
- Embedded Git and Python dependencies, with no need for either to be globally installed
- Fully portable - move Stability Matrix's Data Directory to a new drive or computer at any time
-### ✨ Inference - A Reimagined Stable Diffusion Interface, Built-In to Stability Matrix
+### ✨ Inference - A Reimagined Interface for Stable Diffusion, Built-In to Stability Matrix
- Powerful auto-completion and syntax highlighting using a formal language grammar
- Workspaces open in tabs that save and load from `.smproj` project files
From 3af08e04f3d021c08a34c000ebe382475dcd24db Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 25 Mar 2024 23:36:58 -0700
Subject: [PATCH 096/130] more chagenlog
---
CHANGELOG.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba1236d8..b1487a44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
### Added
- Added OpenArt.AI workflow browser for ComfyUI workflows
### Changed
-- Updated to Avalonia 11.0.10
- Changed to a new image control for pages with many images
+- (Internal) Updated to Avalonia 11.0.10
+### Fixed
+- Improved performance when deleting many images from the Outputs page
## v2.10.0-dev.3
### Added
From 73771a29c16c11f298ac200dd05be4b0490df90c Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 25 Mar 2024 23:44:34 -0700
Subject: [PATCH 097/130] change PackageInstallDetailView back to
BetterAdvancedImage since the image should be cached from the previous page
---
.../Views/PackageManager/PackageInstallDetailView.axaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
index 7bf74c46..84499d89 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
@@ -19,7 +19,7 @@
-
-
+
Date: Mon, 25 Mar 2024 23:46:33 -0700
Subject: [PATCH 098/130] remove console write
---
StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index df39dd3d..da48a2e8 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -145,7 +145,6 @@ public partial class OutputsPageViewModel : PageViewModelBase
.Subscribe(_ =>
{
NumItemsSelected = Outputs.Count(o => o.IsSelected);
- Console.WriteLine($"Subscribe called");
});
categoriesCache.Connect().DeferUntilLoaded().Bind(Categories).Subscribe();
From 597c4c9aec7f956b614ed922931fa6c989f18885 Mon Sep 17 00:00:00 2001
From: JT
Date: Tue, 26 Mar 2024 00:44:23 -0700
Subject: [PATCH 099/130] jsonignore uri & remove unused event handler
---
StabilityMatrix.Avalonia/Models/ImageSource.cs | 1 +
.../PackageManager/PackageInstallBrowserView.axaml.cs | 9 +--------
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Models/ImageSource.cs b/StabilityMatrix.Avalonia/Models/ImageSource.cs
index 0da5749d..331a9c09 100644
--- a/StabilityMatrix.Avalonia/Models/ImageSource.cs
+++ b/StabilityMatrix.Avalonia/Models/ImageSource.cs
@@ -58,6 +58,7 @@ public record ImageSource : IDisposable, ITemplateKey
Bitmap = bitmap;
}
+ [JsonIgnore]
public Uri? Uri => LocalFile?.FullPath != null ? new Uri(LocalFile.FullPath) : RemoteUrl;
///
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
index 08436b3b..5abbe50b 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml.cs
@@ -1,6 +1,4 @@
-using System.Diagnostics;
-using Avalonia.Input;
-using Avalonia.Labs.Controls;
+using Avalonia.Input;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.ViewModels.PackageManager;
using StabilityMatrix.Core.Attributes;
@@ -22,9 +20,4 @@ public partial class PackageInstallBrowserView : UserControlBase
vm.ClearSearchQuery();
}
}
-
- private void AsyncImage_OnFailed(object? sender, AsyncImage.AsyncImageFailedEventArgs e)
- {
- Debug.WriteLine($"Failed to load image: {e.ErrorException?.Message}");
- }
}
From 870aa20a80e4b48768020535549277fd17dd73e1 Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 1 Apr 2024 21:41:39 -0700
Subject: [PATCH 100/130] output sharing by default & invokeai fixes & some
torch version updates
---
CHANGELOG.md | 6 +
.../Dialogs/RecommendedModelsViewModel.cs | 2 +-
.../PackageInstallDetailViewModel.cs | 15 +-
.../Views/MainWindow.axaml | 4 +-
.../Views/MainWindow.axaml.cs | 5 +
.../PackageInstallDetailView.axaml | 128 +++++++++---------
.../Views/PackageManagerPage.axaml | 3 +-
.../SetupOutputSharingStep.cs | 15 ++
.../Models/Packages/ComfyUI.cs | 5 +-
.../Models/Packages/InvokeAI.cs | 57 +-------
.../Models/Packages/RuinedFooocus.cs | 8 +-
StabilityMatrix.Core/Python/PyVenvRunner.cs | 2 +-
12 files changed, 123 insertions(+), 127 deletions(-)
create mode 100644 StabilityMatrix.Core/Models/PackageModification/SetupOutputSharingStep.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1487a44..cea82fd2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,17 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
## v2.10.0-preview.1
### Added
- Added OpenArt.AI workflow browser for ComfyUI workflows
+- Added Output Sharing toggle in Advanced Options during install flow
### Changed
- Changed to a new image control for pages with many images
+- Removed Symlink option for InvokeAI due to changes with InvokeAI v4.0+
+- Output sharing is now enabled by default for new installations
- (Internal) Updated to Avalonia 11.0.10
### Fixed
- Improved performance when deleting many images from the Outputs page
+- Fixed ComfyUI torch downgrading to 2.1.2 when updating
+- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
+- Fixed "Could not find entry point for InvokeAI" error on InvokeAI v4.0+
## v2.10.0-dev.3
### Added
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
index e037408e..a2aa480e 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
@@ -75,7 +75,7 @@ public partial class RecommendedModelsViewModel : ContentDialogViewModelBase
CivitModels
.Connect()
.DeferUntilLoaded()
- .Filter(f => f.ModelVersion.BaseModel == "SDXL 1.0")
+ .Filter(f => f.ModelVersion.BaseModel == "SDXL 1.0" || f.ModelVersion.BaseModel == "Pony")
.Bind(SdxlModels)
.Subscribe();
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
index 9172d5c5..4e9b7fa2 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
@@ -85,6 +85,9 @@ public partial class PackageInstallDetailViewModel(
[ObservableProperty]
private GitCommit? selectedCommit;
+ [ObservableProperty]
+ private bool isOutputSharingEnabled = true;
+
[ObservableProperty]
private bool canInstall;
@@ -97,6 +100,8 @@ public partial class PackageInstallDetailViewModel(
OnInstallNameChanged(InstallName);
+ CanInstall = false;
+
SelectedTorchVersion = SelectedPackage.GetRecommendedTorchVersion();
SelectedSharedFolderMethod = SelectedPackage.RecommendedSharedFolderMethod;
@@ -224,6 +229,8 @@ public partial class PackageInstallDetailViewModel(
installLocation
);
+ var setupOutputSharingStep = new SetupOutputSharingStep(SelectedPackage, installLocation);
+
var package = new InstalledPackage
{
DisplayName = InstallName,
@@ -234,7 +241,8 @@ public partial class PackageInstallDetailViewModel(
LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now,
PreferredTorchVersion = SelectedTorchVersion,
- PreferredSharedFolderMethod = SelectedSharedFolderMethod
+ PreferredSharedFolderMethod = SelectedSharedFolderMethod,
+ UseSharedOutputFolder = IsOutputSharingEnabled
};
var addInstalledPackageStep = new AddInstalledPackageStep(settingsManager, package);
@@ -249,6 +257,11 @@ public partial class PackageInstallDetailViewModel(
addInstalledPackageStep
};
+ if (IsOutputSharingEnabled)
+ {
+ steps.Insert(steps.IndexOf(addInstalledPackageStep), setupOutputSharingStep);
+ }
+
var packageName = SelectedPackage.Name;
var runner = new PackageModificationRunner
diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml b/StabilityMatrix.Avalonia/Views/MainWindow.axaml
index 75613afc..306a1a37 100644
--- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml
+++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml
@@ -70,11 +70,13 @@
Grid.RowSpan="2"
Name="NavigationView"
ItemInvoked="NavigationView_OnItemInvoked"
+ BackRequested="NavigationView_OnBackRequested"
PaneDisplayMode="Left"
IsPaneOpen="False"
OpenPaneLength="{Binding PaneWidth}"
IsSettingsVisible="False"
- IsBackEnabled="False"
+ IsBackEnabled="True"
+ IsBackButtonVisible="True"
MenuItemsSource="{Binding Pages, Mode=OneWay}"
FooterMenuItemsSource="{Binding FooterPages, Mode=OneWay}"
SelectedItem="{Binding SelectedCategory}">
diff --git a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
index c720f37b..eba477f8 100644
--- a/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
+++ b/StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
@@ -446,4 +446,9 @@ public partial class MainWindow : AppWindowBase
e.Handled = true;
navigationService.GoBack();
}
+
+ private void NavigationView_OnBackRequested(object? sender, NavigationViewBackRequestedEventArgs e)
+ {
+ navigationService.GoBack();
+ }
}
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
index 84499d89..594b03eb 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallDetailView.axaml
@@ -16,7 +16,7 @@
x:CompileBindings="True"
d:DataContext="{x:Static designData:DesignData.PackageInstallDetailViewModel}"
x:Class="StabilityMatrix.Avalonia.Views.PackageManager.PackageInstallDetailView">
-
+
-
+
-
+
+ Content="{Binding SelectedPackage.LicenseType}" />
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
+
diff --git a/StabilityMatrix.Core/Models/PackageModification/SetupOutputSharingStep.cs b/StabilityMatrix.Core/Models/PackageModification/SetupOutputSharingStep.cs
new file mode 100644
index 00000000..f92ff7ef
--- /dev/null
+++ b/StabilityMatrix.Core/Models/PackageModification/SetupOutputSharingStep.cs
@@ -0,0 +1,15 @@
+using StabilityMatrix.Core.Models.Packages;
+using StabilityMatrix.Core.Models.Progress;
+
+namespace StabilityMatrix.Core.Models.PackageModification;
+
+public class SetupOutputSharingStep(BasePackage package, string installPath) : IPackageStep
+{
+ public Task ExecuteAsync(IProgress? progress = null)
+ {
+ package.SetupOutputFolderLinks(installPath);
+ return Task.CompletedTask;
+ }
+
+ public string ProgressTitle => "Setting up output sharing...";
+}
diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
index da47bbb6..19843e75 100644
--- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
+++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
@@ -213,7 +213,7 @@ public class ComfyUI(
_
=> pipArgs
.AddArg("--upgrade")
- .WithTorch("~=2.1.0")
+ .WithTorch()
.WithTorchVision()
.WithTorchExtraIndex(
torchVersion switch
@@ -233,9 +233,6 @@ public class ComfyUI(
switch (torchVersion)
{
- case TorchVersion.Cuda:
- pipArgs = pipArgs.WithXFormers("==0.0.22.post4");
- break;
case TorchVersion.Mps:
pipArgs = pipArgs.AddArg("mpmath==1.3.0");
break;
diff --git a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs
index 6502f292..625a76f9 100644
--- a/StabilityMatrix.Core/Models/Packages/InvokeAI.cs
+++ b/StabilityMatrix.Core/Models/Packages/InvokeAI.cs
@@ -32,23 +32,14 @@ public class InvokeAI : BaseGitPackage
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Nightmare;
public override IReadOnlyList ExtraLaunchCommands =>
- new[]
- {
- "invokeai-configure",
- "invokeai-merge",
- "invokeai-metadata",
- "invokeai-model-install",
- "invokeai-node-cli",
- "invokeai-ti",
- "invokeai-update",
- };
+ new[] { "invokeai-db-maintenance", "invokeai-import-images", };
public override Uri PreviewImageUri =>
new("https://raw.githubusercontent.com/invoke-ai/InvokeAI/main/docs/assets/canvas_preview.png");
public override IEnumerable AvailableSharedFolderMethods =>
- new[] { SharedFolderMethod.Symlink, SharedFolderMethod.None };
- public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink;
+ new[] { SharedFolderMethod.None };
+ public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.None;
public override string MainBranch => "main";
@@ -127,23 +118,11 @@ public class InvokeAI : BaseGitPackage
Options = ["--allow-origins"]
},
new LaunchOptionDefinition
- {
- Name = "Always use CPU",
- Type = LaunchOptionType.Bool,
- Options = ["--always_use_cpu"]
- },
- new LaunchOptionDefinition
{
Name = "Precision",
Type = LaunchOptionType.Bool,
Options = ["--precision auto", "--precision float16", "--precision float32"]
},
- new LaunchOptionDefinition
- {
- Name = "Aggressively free up GPU memory after each operation",
- Type = LaunchOptionType.Bool,
- Options = ["--free_gpu_mem"]
- },
LaunchOptionDefinition.Extras
];
@@ -223,9 +202,9 @@ public class InvokeAI : BaseGitPackage
await venvRunner
.PipInstall(
new PipInstallArgs(args.Any() ? args.ToArray() : Array.Empty())
- .WithTorch("==2.1.2")
- .WithTorchVision("==0.16.2")
- .WithXFormers("==0.0.23post1")
+ .WithTorch("==2.2.1")
+ .WithTorchVision("==0.17.1")
+ .WithXFormers("==0.0.25")
.WithTorchExtraIndex("cu121"),
onConsoleOutput
)
@@ -262,24 +241,6 @@ public class InvokeAI : BaseGitPackage
.ConfigureAwait(false);
await venvRunner.PipInstall("rich packaging python-dotenv", onConsoleOutput).ConfigureAwait(false);
-
- progress?.Report(new ProgressReport(-1f, "Configuring InvokeAI", isIndeterminate: true));
-
- // need to setup model links before running invokeai-configure so it can do its conversion
- await SetupModelFolders(installLocation, selectedSharedFolderMethod).ConfigureAwait(false);
-
- await RunInvokeCommand(
- installLocation,
- "invokeai-configure",
- "--yes --skip-sd-weights",
- true,
- onConsoleOutput,
- spam3: true
- )
- .ConfigureAwait(false);
-
- await VenvRunner.Process.WaitForExitAsync();
-
progress?.Report(new ProgressReport(1f, "Done!", isIndeterminate: false));
}
@@ -362,12 +323,6 @@ public class InvokeAI : BaseGitPackage
await SetupVenv(installedPackagePath).ConfigureAwait(false);
- arguments = command switch
- {
- "invokeai-configure" => "--yes --skip-sd-weights",
- _ => arguments
- };
-
VenvRunner.EnvironmentVariables = GetEnvVars(installedPackagePath);
// fix frontend build missing for people who updated to v3.6 before the fix
diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs
index 181abc32..96dc5d65 100644
--- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs
+++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs
@@ -124,10 +124,10 @@ public class RuinedFooocus(
await venvRunner
.PipInstall(
new PipInstallArgs()
- .WithTorch("==2.0.1")
- .WithTorchVision("==0.15.2")
- .WithXFormers("==0.0.20")
- .WithTorchExtraIndex("cu118")
+ .WithTorch("==2.1.2")
+ .WithTorchVision("==0.16.2")
+ .WithXFormers("==0.0.23.post1")
+ .WithTorchExtraIndex("cu121")
.WithParsedFromRequirementsTxt(
await requirements.ReadAllTextAsync().ConfigureAwait(false),
excludePattern: "torch"
diff --git a/StabilityMatrix.Core/Python/PyVenvRunner.cs b/StabilityMatrix.Core/Python/PyVenvRunner.cs
index 2266498b..5dfc3a03 100644
--- a/StabilityMatrix.Core/Python/PyVenvRunner.cs
+++ b/StabilityMatrix.Core/Python/PyVenvRunner.cs
@@ -214,7 +214,7 @@ public class PyVenvRunner : IDisposable, IAsyncDisposable
});
SetPyvenvCfg(PyRunner.PythonDir);
- RunDetached(args.Prepend("-m pip install"), outputAction);
+ RunDetached(args.Prepend("-m pip install").Concat("--exists-action s"), outputAction);
await Process.WaitForExitAsync().ConfigureAwait(false);
// Check return code
From ca67f73ff6e66eb4f39db0af5fc6a40b6b48106f Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 1 Apr 2024 22:15:59 -0700
Subject: [PATCH 101/130] Fix duplicate InstallerSortOrder
---
StabilityMatrix.Core/Models/Packages/SDWebForge.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
index b22c5285..69a501d9 100644
--- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
+++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
@@ -35,8 +35,6 @@ public class SDWebForge(
"https://github.com/lllyasviel/stable-diffusion-webui-forge/assets/19834515/ca5e05ed-bd86-4ced-8662-f41034648e8c"
);
- public override PackageDifficulty InstallerSortOrder => PackageDifficulty.ReallyRecommended;
-
public override string MainBranch => "main";
public override bool ShouldIgnoreReleases => true;
public override IPackageExtensionManager ExtensionManager => null;
From 04db64fcfb129203343dc51cd7fcdaabb7ac4782 Mon Sep 17 00:00:00 2001
From: JT
Date: Tue, 2 Apr 2024 23:07:28 -0700
Subject: [PATCH 102/130] many change - Added more metadata to the image dialog
info flyout - Added Restart button to console page - Model download location
selector now searches all subfolders - Fixed Civitai model browser not
showing images when "Show NSFW" is disabled - Fixed crash when Installed
Workflows page is opened with no Workflows folder - Fixed progress bars not
displaying properly during package installs & updates
---
CHANGELOG.md | 13 +++-
.../Assets/sitecustomize.py | 14 ++++
.../DesignData/DesignData.cs | 2 +-
.../PackageSteps/UnpackSiteCustomizeStep.cs | 21 ++++++
.../Services/INavigationService.cs | 2 +
.../Services/NavigationService.cs | 2 +
.../CheckpointBrowserCardViewModel.cs | 5 +-
.../Dialogs/NewOneClickInstallViewModel.cs | 19 ++++--
.../Dialogs/SelectModelVersionViewModel.cs | 6 +-
.../ViewModels/InstalledWorkflowsViewModel.cs | 5 ++
.../PackageInstallDetailViewModel.cs | 3 +
.../PackageInstallProgressItemViewModel.cs | 15 ++++-
.../ViewModels/RunningPackageViewModel.cs | 10 ++-
.../Views/ConsoleOutputPage.axaml | 10 ++-
.../Views/Dialogs/ImageViewerDialog.axaml | 23 ++++++-
.../Extensions/ProgressExtensions.cs | 11 ++--
StabilityMatrix.Core/Models/Api/CivitImage.cs | 14 ++--
.../PackageModification/InstallPackageStep.cs | 2 +-
.../PackageModification/UpdatePackageStep.cs | 9 ++-
.../Models/Progress/ProgressReport.cs | 66 ++++++++++++++-----
20 files changed, 205 insertions(+), 47 deletions(-)
create mode 100644 StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 043ccb1c..fa0e8fc8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,18 @@ 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.10.0-preview.1
+## v2.10.0-pre.2
+### Added
+- Added more metadata to the image dialog info flyout
+- Added Restart button to console page
+### Changed
+- Model download location selector now searches all subfolders
+### Fixed
+- Fixed Civitai model browser not showing images when "Show NSFW" is disabled
+- Fixed crash when Installed Workflows page is opened with no Workflows folder
+- Fixed progress bars not displaying properly during package installs & updates
+
+## v2.10.0-pre.1
### Added
- Added OpenArt.AI workflow browser for ComfyUI workflows
- Added Output Sharing toggle in Advanced Options during install flow
diff --git a/StabilityMatrix.Avalonia/Assets/sitecustomize.py b/StabilityMatrix.Avalonia/Assets/sitecustomize.py
index b6ebb4c1..d154c13a 100644
--- a/StabilityMatrix.Avalonia/Assets/sitecustomize.py
+++ b/StabilityMatrix.Avalonia/Assets/sitecustomize.py
@@ -68,6 +68,20 @@ def _patch_rich_console():
pass
except Exception as e:
print("[sitecustomize error]:", e)
+
+ try:
+ from pip._vendor.rich import console
+
+ class _Console(console.Console):
+ @property
+ def is_terminal(self) -> bool:
+ return True
+
+ console.Console = _Console
+ except ImportError:
+ pass
+ except Exception as e:
+ print("[sitecustomize error]:", e)
_patch_rich_console()
diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
index 3fc6455b..471f4a53 100644
--- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs
+++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
@@ -360,7 +360,7 @@ public static class DesignData
{
new()
{
- Nsfw = "None",
+ NsfwLevel = 1,
Url =
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/"
+ "78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg"
diff --git a/StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs b/StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs
new file mode 100644
index 00000000..92e5f413
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Threading.Tasks;
+using StabilityMatrix.Core.Models.FileInterfaces;
+using StabilityMatrix.Core.Models.PackageModification;
+using StabilityMatrix.Core.Models.Progress;
+using StabilityMatrix.Core.Python;
+
+namespace StabilityMatrix.Avalonia.Models.PackageSteps;
+
+public class UnpackSiteCustomizeStep(DirectoryPath venvPath) : IPackageStep
+{
+ public async Task ExecuteAsync(IProgress? progress = null)
+ {
+ var sitePackages = venvPath.JoinDir(PyVenvRunner.RelativeSitePackagesPath);
+ var file = sitePackages.JoinFile("sitecustomize.py");
+ file.Directory?.Create();
+ await Assets.PyScriptSiteCustomize.ExtractTo(file);
+ }
+
+ public string ProgressTitle => "Unpacking prerequisites...";
+}
diff --git a/StabilityMatrix.Avalonia/Services/INavigationService.cs b/StabilityMatrix.Avalonia/Services/INavigationService.cs
index f1aa8ba4..68f7f261 100644
--- a/StabilityMatrix.Avalonia/Services/INavigationService.cs
+++ b/StabilityMatrix.Avalonia/Services/INavigationService.cs
@@ -37,4 +37,6 @@ public interface INavigationService<[SuppressMessage("ReSharper", "UnusedTypePar
void NavigateTo(ViewModelBase viewModel, NavigationTransitionInfo? transitionInfo = null);
bool GoBack();
+
+ bool CanGoBack { get; }
}
diff --git a/StabilityMatrix.Avalonia/Services/NavigationService.cs b/StabilityMatrix.Avalonia/Services/NavigationService.cs
index c95d3068..8778f7ca 100644
--- a/StabilityMatrix.Avalonia/Services/NavigationService.cs
+++ b/StabilityMatrix.Avalonia/Services/NavigationService.cs
@@ -188,4 +188,6 @@ public class NavigationService : INavigationService
_frame.GoBack();
return true;
}
+
+ public bool CanGoBack => _frame?.CanGoBack ?? false;
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
index bcb2ae62..341a3913 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -159,7 +160,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
// Try to find a valid image
var image = images
?.Where(img => LocalModelFile.SupportedImageExtensions.Any(img.Url.Contains))
- .FirstOrDefault(image => nsfwEnabled || image.Nsfw == "None");
+ .FirstOrDefault(image => nsfwEnabled || image.NsfwLevel <= 1);
if (image != null)
{
CardImage = new Uri(image.Url);
@@ -256,7 +257,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
{
var subFolder =
viewModel?.SelectedInstallLocation
- ?? Path.Combine("Models", model.Type.ConvertTo().GetStringValue());
+ ?? Path.Combine(@"Models", model.Type.ConvertTo().GetStringValue());
downloadPath = Path.Combine(settingsManager.LibraryDir, subFolder);
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
index c8592cc7..425b20e7 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
@@ -12,6 +12,7 @@ using DynamicData;
using DynamicData.Binding;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Extensions;
+using StabilityMatrix.Avalonia.Models.PackageSteps;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
@@ -107,18 +108,19 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase
{
Task.Run(async () =>
{
+ var installLocation = Path.Combine(
+ settingsManager.LibraryDir,
+ "Packages",
+ selectedPackage.Name
+ );
+
var steps = new List
{
new SetPackageInstallingStep(settingsManager, selectedPackage.Name),
- new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, selectedPackage)
+ new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, selectedPackage),
};
// get latest version & download & install
- var installLocation = Path.Combine(
- settingsManager.LibraryDir,
- "Packages",
- selectedPackage.Name
- );
if (Directory.Exists(installLocation))
{
var installPath = new DirectoryPath(installLocation);
@@ -148,6 +150,11 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase
);
steps.Add(downloadStep);
+ var unpackSiteCustomizeStep = new UnpackSiteCustomizeStep(
+ Path.Combine(installLocation, "venv")
+ );
+ steps.Add(unpackSiteCustomizeStep);
+
var installStep = new InstallPackageStep(
selectedPackage,
torchVersion,
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
index 9ef4c378..0b84de65 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
@@ -99,7 +99,7 @@ public partial class SelectModelVersionViewModel(
var allImages = value
?.ModelVersion
?.Images
- ?.Where(img => nsfwEnabled || img.Nsfw == "None")
+ ?.Where(img => nsfwEnabled || img.NsfwLevel <= 2)
?.Select(x => new ImageSource(x.Url))
.ToList();
@@ -316,7 +316,9 @@ public partial class SelectModelVersionViewModel(
installLocations.Add(downloadDirectory.ToString().Replace(rootModelsDirectory, "Models"));
- foreach (var directory in downloadDirectory.EnumerateDirectories())
+ foreach (
+ var directory in downloadDirectory.EnumerateDirectories(searchOption: SearchOption.AllDirectories)
+ )
{
installLocations.Add(directory.ToString().Replace(rootModelsDirectory, "Models"));
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
index b765c797..0bc14b2c 100644
--- a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
@@ -59,6 +59,11 @@ public partial class InstalledWorkflowsViewModel(
{
workflowsCache.Clear();
+ if (!Directory.Exists(settingsManager.WorkflowDirectory))
+ {
+ Directory.CreateDirectory(settingsManager.WorkflowDirectory);
+ }
+
foreach (
var workflowPath in Directory.EnumerateFiles(
settingsManager.WorkflowDirectory,
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
index 4e9b7fa2..6c24efc2 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
@@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Languages;
+using StabilityMatrix.Avalonia.Models.PackageSteps;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
@@ -188,6 +189,7 @@ public partial class PackageInstallDetailViewModel(
}
var prereqStep = new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, SelectedPackage);
+ var unpackSiteCustomizeStep = new UnpackSiteCustomizeStep(Path.Combine(installLocation, "venv"));
var downloadOptions = new DownloadPackageVersionOptions();
var installedVersion = new InstalledPackageVersion();
@@ -252,6 +254,7 @@ public partial class PackageInstallDetailViewModel(
setPackageInstallingStep,
prereqStep,
downloadStep,
+ unpackSiteCustomizeStep,
installStep,
setupModelFoldersStep,
addInstalledPackageStep
diff --git a/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs
index cd4f5f46..fb74fc17 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs
@@ -49,10 +49,21 @@ public class PackageInstallProgressItemViewModel : ProgressItemViewModelBase
Name = packageModificationRunner.CurrentStep?.ProgressTitle;
Failed = packageModificationRunner.Failed;
- if (string.IsNullOrWhiteSpace(e.Message) || e.Message.Contains("Downloading..."))
+ if (e.ProcessOutput == null && string.IsNullOrWhiteSpace(e.Message))
return;
- Progress.Console.PostLine(e.Message);
+ if (!string.IsNullOrWhiteSpace(e.Message) && e.Message.Contains("Downloading..."))
+ return;
+
+ if (e.ProcessOutput != null)
+ {
+ Progress.Console.Post(e.ProcessOutput.Value);
+ }
+ else
+ {
+ Progress.Console.PostLine(e.Message);
+ }
+
EventManager.Instance.OnScrollToBottomRequested();
if (
diff --git a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
index 38011e04..73f89a8b 100644
--- a/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
@@ -104,6 +104,14 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
}
}
+ [RelayCommand]
+ private async Task Restart()
+ {
+ await Stop();
+ await Task.Delay(100);
+ LaunchPackage();
+ }
+
[RelayCommand]
private void LaunchPackage()
{
@@ -113,10 +121,10 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
[RelayCommand]
private async Task Stop()
{
+ IsRunning = false;
await runningPackageService.StopPackage(RunningPackage.InstalledPackage.Id);
Console.PostLine($"{Environment.NewLine}Stopped process at {DateTimeOffset.Now}");
await Console.StopUpdatesAsync();
- IsRunning = false;
}
[RelayCommand]
diff --git a/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml b/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
index 7d86b568..d44b44e6 100644
--- a/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
@@ -34,8 +34,16 @@
Command="{Binding LaunchPackageCommand}"
VerticalAlignment="Center"
Label="{x:Static lang:Resources.Action_Launch}" />
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
? AsProcessOutputHandler(
- this IProgress? progress
- )
+ public static Action? AsProcessOutputHandler(this IProgress? progress)
{
return progress == null
? null
: output =>
{
progress.Report(
- new ProgressReport { IsIndeterminate = true, Message = output.Text }
+ new ProgressReport
+ {
+ IsIndeterminate = true,
+ Message = output.Text,
+ ProcessOutput = output
+ }
);
};
}
diff --git a/StabilityMatrix.Core/Models/Api/CivitImage.cs b/StabilityMatrix.Core/Models/Api/CivitImage.cs
index 0cab1b50..82aadce2 100644
--- a/StabilityMatrix.Core/Models/Api/CivitImage.cs
+++ b/StabilityMatrix.Core/Models/Api/CivitImage.cs
@@ -6,18 +6,18 @@ public class CivitImage
{
[JsonPropertyName("url")]
public string Url { get; set; }
-
- [JsonPropertyName("nsfw")]
- public string Nsfw { get; set; }
-
+
+ [JsonPropertyName("nsfwLevel")]
+ public int? NsfwLevel { get; set; }
+
[JsonPropertyName("width")]
public int Width { get; set; }
-
+
[JsonPropertyName("height")]
public int Height { get; set; }
-
+
[JsonPropertyName("hash")]
public string Hash { get; set; }
-
+
// TODO: "meta" ( object? )
}
diff --git a/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs b/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs
index ff0d20ae..25c6e357 100644
--- a/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs
+++ b/StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs
@@ -31,7 +31,7 @@ public class InstallPackageStep : IPackageStep
{
void OnConsoleOutput(ProcessOutput output)
{
- progress?.Report(new ProgressReport { IsIndeterminate = true, Message = output.Text });
+ progress?.Report(new ProgressReport { IsIndeterminate = true, ProcessOutput = output });
}
await package
diff --git a/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs b/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs
index 11a8e111..446a49d7 100644
--- a/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs
+++ b/StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs
@@ -31,7 +31,14 @@ public class UpdatePackageStep : IPackageStep
void OnConsoleOutput(ProcessOutput output)
{
- progress?.Report(new ProgressReport { IsIndeterminate = true, Message = output.Text });
+ progress?.Report(
+ new ProgressReport
+ {
+ IsIndeterminate = true,
+ Message = output.Text,
+ ProcessOutput = output
+ }
+ );
}
var updateResult = await basePackage
diff --git a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs
index 22657d70..6ffcec6d 100644
--- a/StabilityMatrix.Core/Models/Progress/ProgressReport.cs
+++ b/StabilityMatrix.Core/Models/Progress/ProgressReport.cs
@@ -1,4 +1,6 @@
-namespace StabilityMatrix.Core.Models.Progress;
+using StabilityMatrix.Core.Processes;
+
+namespace StabilityMatrix.Core.Models.Progress;
public record struct ProgressReport
{
@@ -6,21 +8,30 @@ public record struct ProgressReport
/// Progress value as percentage between 0 and 1.
///
public double? Progress { get; init; } = 0;
+
///
/// Current progress count.
///
public ulong? Current { get; init; } = 0;
+
///
/// Total progress count.
///
public ulong? Total { get; init; } = 0;
public string? Title { get; init; }
public string? Message { get; init; }
+ public ProcessOutput? ProcessOutput { get; init; }
public bool IsIndeterminate { get; init; } = false;
- public float Percentage => (float) Math.Ceiling(Math.Clamp(Progress ?? 0, 0, 1) * 100);
+ public float Percentage => (float)Math.Ceiling(Math.Clamp(Progress ?? 0, 0, 1) * 100);
public ProgressType Type { get; init; } = ProgressType.Generic;
-
- public ProgressReport(double progress, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic)
+
+ public ProgressReport(
+ double progress,
+ string? title = null,
+ string? message = null,
+ bool isIndeterminate = false,
+ ProgressType type = ProgressType.Generic
+ )
{
Progress = progress;
Title = title;
@@ -28,32 +39,53 @@ public record struct ProgressReport
IsIndeterminate = isIndeterminate;
Type = type;
}
-
- public ProgressReport(ulong current, ulong total, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic)
+
+ public ProgressReport(
+ ulong current,
+ ulong total,
+ string? title = null,
+ string? message = null,
+ bool isIndeterminate = false,
+ ProgressType type = ProgressType.Generic
+ )
{
Current = current;
Total = total;
- Progress = (double) current / total;
+ Progress = (double)current / total;
Title = title;
Message = message;
IsIndeterminate = isIndeterminate;
Type = type;
}
-
- public ProgressReport(int current, int total, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic)
+
+ public ProgressReport(
+ int current,
+ int total,
+ string? title = null,
+ string? message = null,
+ bool isIndeterminate = false,
+ ProgressType type = ProgressType.Generic
+ )
{
- if (current < 0) throw new ArgumentOutOfRangeException(nameof(current), "Current progress cannot negative.");
- if (total < 0) throw new ArgumentOutOfRangeException(nameof(total), "Total progress cannot be negative.");
- Current = (ulong) current;
- Total = (ulong) total;
- Progress = (double) current / total;
+ if (current < 0)
+ throw new ArgumentOutOfRangeException(nameof(current), "Current progress cannot negative.");
+ if (total < 0)
+ throw new ArgumentOutOfRangeException(nameof(total), "Total progress cannot be negative.");
+ Current = (ulong)current;
+ Total = (ulong)total;
+ Progress = (double)current / total;
Title = title;
Message = message;
IsIndeterminate = isIndeterminate;
Type = type;
}
-
- public ProgressReport(ulong current, string? title = null, string? message = null, ProgressType type = ProgressType.Generic)
+
+ public ProgressReport(
+ ulong current,
+ string? title = null,
+ string? message = null,
+ ProgressType type = ProgressType.Generic
+ )
{
Current = current;
Title = title;
@@ -61,6 +93,6 @@ public record struct ProgressReport
IsIndeterminate = true;
Type = type;
}
-
+
// Implicit conversion from action
}
From 61abe7a1f62d71123db03866788448952dbca7ec Mon Sep 17 00:00:00 2001
From: JT
Date: Tue, 2 Apr 2024 23:09:00 -0700
Subject: [PATCH 103/130] use same nsfwlevel
---
.../ViewModels/Dialogs/SelectModelVersionViewModel.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
index 0b84de65..338aa20d 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
@@ -99,7 +99,7 @@ public partial class SelectModelVersionViewModel(
var allImages = value
?.ModelVersion
?.Images
- ?.Where(img => nsfwEnabled || img.NsfwLevel <= 2)
+ ?.Where(img => nsfwEnabled || img.NsfwLevel <= 1)
?.Select(x => new ImageSource(x.Url))
.ToList();
From af89e07c01868420d900c633f2177455e0209357 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:32:30 -0400
Subject: [PATCH 104/130] Add LayerDiffuseCard
---
StabilityMatrix.Avalonia/App.axaml | 1 +
.../Controls/Inference/LayerDiffuseCard.axaml | 48 +++++++++++++++++++
.../Inference/LayerDiffuseCard.axaml.cs | 7 +++
.../DesignData/DesignData.cs | 3 ++
4 files changed, 59 insertions(+)
create mode 100644 StabilityMatrix.Avalonia/Controls/Inference/LayerDiffuseCard.axaml
create mode 100644 StabilityMatrix.Avalonia/Controls/Inference/LayerDiffuseCard.axaml.cs
diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml
index fa669962..643c72b3 100644
--- a/StabilityMatrix.Avalonia/App.axaml
+++ b/StabilityMatrix.Avalonia/App.axaml
@@ -81,6 +81,7 @@
+
+
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/LayerDiffuseCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/LayerDiffuseCard.axaml.cs
new file mode 100644
index 00000000..a8973a3f
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/Inference/LayerDiffuseCard.axaml.cs
@@ -0,0 +1,7 @@
+using Avalonia.Controls.Primitives;
+using StabilityMatrix.Core.Attributes;
+
+namespace StabilityMatrix.Avalonia.Controls;
+
+[Transient]
+public class LayerDiffuseCard : TemplatedControl;
diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
index df122b14..f2aa68cb 100644
--- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs
+++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
@@ -921,6 +921,9 @@ The gallery images are often inpainted, but you will get something very similar
vm.IsBatchIndexEnabled = true;
});
+ public static LayerDiffuseCardViewModel LayerDiffuseCardViewModel =>
+ DialogFactory.Get();
+
public static IList SampleCompletionData =>
new List
{
From 92d42b3c53077b705673859c73fdd62c2111f42d Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:32:59 -0400
Subject: [PATCH 105/130] PreOutputActions support for ModuleApplyStepEventArgs
---
.../Models/Inference/ModuleApplyStepEventArgs.cs | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
index f4bd13fb..487d39b7 100644
--- a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
+++ b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
@@ -28,6 +28,16 @@ public class ModuleApplyStepEventArgs : EventArgs
public List<(string SourcePath, string DestinationRelativePath)> FilesToTransfer { get; init; } = [];
+ public List> PreOutputActions { get; init; } = [];
+
+ public void InvokeAllPreOutputActions()
+ {
+ foreach (var action in PreOutputActions)
+ {
+ action(this);
+ }
+ }
+
///
/// Creates a new with the given .
///
From cefb08e4da98248c979f0271a35bcdd9e249878d Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:33:18 -0400
Subject: [PATCH 106/130] Add LayerDiffuseModule
---
.../ViewModels/Base/LoadableViewModelBase.cs | 3 +++
.../Inference/Modules/LayerDiffuseModule.cs | 26 +++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/Modules/LayerDiffuseModule.cs
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
index b06e9a68..ed787354 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
@@ -11,6 +11,7 @@ using NLog;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Avalonia.ViewModels.Inference.Modules;
+using StabilityMatrix.Core.Models.Inference;
namespace StabilityMatrix.Avalonia.ViewModels.Base;
@@ -20,12 +21,14 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base;
[JsonDerivedType(typeof(UpscalerCardViewModel), UpscalerCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(ControlNetCardViewModel), ControlNetCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(PromptExpansionCardViewModel), PromptExpansionCardViewModel.ModuleKey)]
+[JsonDerivedType(typeof(LayerDiffuseCardViewModel), LayerDiffuseCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(FreeUModule))]
[JsonDerivedType(typeof(HiresFixModule))]
[JsonDerivedType(typeof(UpscalerModule))]
[JsonDerivedType(typeof(ControlNetModule))]
[JsonDerivedType(typeof(SaveImageModule))]
[JsonDerivedType(typeof(PromptExpansionModule))]
+[JsonDerivedType(typeof(LayerDiffuseModule))]
public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/LayerDiffuseModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/LayerDiffuseModule.cs
new file mode 100644
index 00000000..11a70114
--- /dev/null
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/LayerDiffuseModule.cs
@@ -0,0 +1,26 @@
+using StabilityMatrix.Avalonia.Models.Inference;
+using StabilityMatrix.Avalonia.Services;
+using StabilityMatrix.Avalonia.ViewModels.Base;
+using StabilityMatrix.Core.Attributes;
+
+namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules;
+
+[ManagedService]
+[Transient]
+public class LayerDiffuseModule : ModuleBase
+{
+ ///
+ public LayerDiffuseModule(ServiceManager vmFactory)
+ : base(vmFactory)
+ {
+ Title = "Layer Diffuse";
+ AddCards(vmFactory.Get());
+ }
+
+ ///
+ protected override void OnApplyStep(ModuleApplyStepEventArgs e)
+ {
+ var card = GetCard();
+ card.ApplyStep(e);
+ }
+}
From 51b6e1be367efdee89158a0fa8ba9a3823555b9a Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:34:07 -0400
Subject: [PATCH 107/130] Add LayerDiffuseCard ViewModel
---
.../Inference/LayerDiffuseCardViewModel.cs | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
new file mode 100644
index 00000000..04cb8b80
--- /dev/null
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using CommunityToolkit.Mvvm.ComponentModel;
+using KGySoft.CoreLibraries;
+using StabilityMatrix.Avalonia.Controls;
+using StabilityMatrix.Avalonia.Models.Inference;
+using StabilityMatrix.Avalonia.ViewModels.Base;
+using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
+using StabilityMatrix.Core.Models.Inference;
+
+namespace StabilityMatrix.Avalonia.ViewModels.Inference;
+
+[Transient]
+[ManagedService]
+[View(typeof(LayerDiffuseCard))]
+public partial class LayerDiffuseCardViewModel : LoadableViewModelBase, IComfyStep
+{
+ public const string ModuleKey = "LayerDiffuse";
+
+ [ObservableProperty]
+ private LayerDiffuseMode selectedMode = LayerDiffuseMode.None;
+
+ public IEnumerable AvailableModes => Enum.GetValues();
+
+ [ObservableProperty]
+ [NotifyDataErrorInfo]
+ [Required]
+ [Range(-1d, 3d)]
+ private double weight = 1;
+
+ ///
+ public void ApplyStep(ModuleApplyStepEventArgs e)
+ {
+ if (SelectedMode == LayerDiffuseMode.None)
+ return;
+
+ foreach (var modelConnections in e.Temp.Models.Values)
+ {
+ var layerDiffuseApply = e.Nodes.AddTypedNode(
+ new ComfyNodeBuilder.LayeredDiffusionApply
+ {
+ Name = e.Nodes.GetUniqueName($"LayerDiffuseApply_{modelConnections.Name}"),
+ Model = modelConnections.Model,
+ Config = "SD15, Attention Injection, attn_sharing",
+ Weight = Weight,
+ }
+ );
+
+ modelConnections.Model = layerDiffuseApply.Output;
+ }
+
+ // Add pre output action
+ e.PreOutputActions.Add(applyArgs =>
+ {
+ // Use last latent for decode
+ var latent =
+ applyArgs.Builder.Connections.LastPrimaryLatent
+ ?? throw new InvalidOperationException("Connections.LastPrimaryLatent not set");
+
+ // Convert primary to image if not already
+ var primaryImage = applyArgs.Builder.GetPrimaryAsImage();
+ applyArgs.Builder.Connections.Primary = primaryImage;
+
+ // Add a Layer Diffuse Decode
+ var decode = applyArgs.Nodes.AddTypedNode(
+ new ComfyNodeBuilder.LayeredDiffusionDecodeRgba
+ {
+ Name = applyArgs.Nodes.GetUniqueName("LayerDiffuseDecode"),
+ Samples = latent,
+ Images = primaryImage,
+ SdVersion = "SD15",
+ }
+ );
+
+ // Set primary to decode output
+ applyArgs.Builder.Connections.Primary = decode.Output;
+ });
+ }
+}
From 52b32f922722106b7238130596979945ee6f8bc4 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:34:22 -0400
Subject: [PATCH 108/130] Add LayerDiffuseModule as Sampler addon option
---
.../ViewModels/Inference/SamplerCardViewModel.cs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs
index 8890a514..664ab0c8 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/SamplerCardViewModel.cs
@@ -109,7 +109,12 @@ public partial class SamplerCardViewModel : LoadableViewModelBase, IParametersLo
ModulesCardViewModel = vmFactory.Get(modulesCard =>
{
modulesCard.Title = Resources.Label_Addons;
- modulesCard.AvailableModules = [typeof(FreeUModule), typeof(ControlNetModule)];
+ modulesCard.AvailableModules =
+ [
+ typeof(FreeUModule),
+ typeof(ControlNetModule),
+ typeof(LayerDiffuseModule)
+ ];
});
}
From 255b1feb66fb4bff45dd267554489ef7920fe9c9 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:34:32 -0400
Subject: [PATCH 109/130] Add LayerDiffuseMode
---
.../Models/Inference/LayerDiffuseMode.cs | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
diff --git a/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs b/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
new file mode 100644
index 00000000..af243113
--- /dev/null
+++ b/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace StabilityMatrix.Core.Models.Inference;
+
+public enum LayerDiffuseMode
+{
+ ///
+ /// The layer diffuse mode is not set.
+ ///
+ [Display(Name = "None")]
+ None,
+
+ ///
+ /// Generate foreground only with transparency.
+ ///
+ [Display(Name = "Generate Foreground with Transparency")]
+ GenerateForegroundWithTransparency,
+}
From d6920be164d3d562bc127f5846615ac7e5868bbb Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 20:34:48 -0400
Subject: [PATCH 110/130] Add Nodes for LayerDiffuse
---
.../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 54 ++++++++++++++++++-
1 file changed, 53 insertions(+), 1 deletion(-)
diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
index c9a378b6..a1b79df5 100644
--- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
+++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
@@ -383,6 +383,39 @@ public class ComfyNodeBuilder
public int BatchSize { get; init; } = 1;
}
+ [TypedNodeOptions(
+ Name = "Inference_Core_LayeredDiffusionApply",
+ RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes >= 0.4.0"]
+ )]
+ public record LayeredDiffusionApply : ComfyTypedNodeBase
+ {
+ public required ModelNodeConnection Model { get; init; }
+
+ public required string Config { get; init; }
+
+ [Range(-1d, 3d)]
+ public double Weight { get; init; } = 1.0;
+ }
+
+ [TypedNodeOptions(
+ Name = "Inference_Core_LayeredDiffusionDecodeRGBA",
+ RequiredExtensions = ["https://github.com/LykosAI/ComfyUI-Inference-Core-Nodes >= 0.4.0"]
+ )]
+ public record LayeredDiffusionDecodeRgba : ComfyTypedNodeBase
+ {
+ public required LatentNodeConnection Samples { get; init; }
+
+ public required ImageNodeConnection Images { get; init; }
+
+ ///
+ /// Either "SD15" or "SDXL"
+ ///
+ public required string SdVersion { get; init; }
+
+ [Range(1, 4096)]
+ public int SubBatchSize { get; init; } = 16;
+ }
+
public ImageNodeConnection Lambda_LatentToImage(LatentNodeConnection latent, VAENodeConnection vae)
{
var name = GetUniqueName("VAEDecode");
@@ -867,7 +900,26 @@ public class ComfyNodeBuilder
set => SamplerTemporaryArgs["Base"] = value;
}
- public PrimaryNodeConnection? Primary { get; set; }
+ ///
+ /// The last primary set latent value, updated when is set to a latent value.
+ ///
+ public LatentNodeConnection? LastPrimaryLatent { get; private set; }
+
+ private PrimaryNodeConnection? primary;
+
+ public PrimaryNodeConnection? Primary
+ {
+ get => primary;
+ set
+ {
+ if (value?.IsT0 == true)
+ {
+ LastPrimaryLatent = value.AsT0;
+ }
+ primary = value;
+ }
+ }
+
public VAENodeConnection? PrimaryVAE { get; set; }
public Size PrimarySize { get; set; }
From 395d9c3963389442a52968268f33d40bd0c7b869 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 3 Apr 2024 22:00:59 -0400
Subject: [PATCH 111/130] Add PreOutputAction support for Text2Img and Img2Img
---
.../Inference/InferenceImageToImageViewModel.cs | 16 ++++++++++------
.../Inference/InferenceTextToImageViewModel.cs | 14 +++++++++-----
2 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
index 77c5230f..7600384a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
@@ -56,26 +56,30 @@ public class InferenceImageToImageViewModel : InferenceTextToImageViewModel
_ => Convert.ToUInt64(SeedCardViewModel.Seed)
};
- BatchSizeCardViewModel.ApplyStep(args);
+ var applyArgs = args.ToModuleApplyStepEventArgs();
+
+ BatchSizeCardViewModel.ApplyStep(applyArgs);
// Load models
- ModelCardViewModel.ApplyStep(args);
+ ModelCardViewModel.ApplyStep(applyArgs);
// Setup image latent source
- SelectImageCardViewModel.ApplyStep(args);
+ SelectImageCardViewModel.ApplyStep(applyArgs);
// Prompts and loras
- PromptCardViewModel.ApplyStep(args);
+ PromptCardViewModel.ApplyStep(applyArgs);
// Setup Sampler and Refiner if enabled
- SamplerCardViewModel.ApplyStep(args);
+ SamplerCardViewModel.ApplyStep(applyArgs);
// Apply module steps
foreach (var module in ModulesCardViewModel.Cards.OfType())
{
- module.ApplyStep(args);
+ module.ApplyStep(applyArgs);
}
+ applyArgs.InvokeAllPreOutputActions();
+
builder.SetupOutputImage();
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
index a1924559..04e46f05 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
@@ -131,10 +131,12 @@ public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, I
_ => Convert.ToUInt64(SeedCardViewModel.Seed)
};
- BatchSizeCardViewModel.ApplyStep(args);
+ var applyArgs = args.ToModuleApplyStepEventArgs();
+
+ BatchSizeCardViewModel.ApplyStep(applyArgs);
// Load models
- ModelCardViewModel.ApplyStep(args);
+ ModelCardViewModel.ApplyStep(applyArgs);
// Setup empty latent
builder.SetupEmptyLatentSource(
@@ -145,17 +147,19 @@ public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, I
);
// Prompts and loras
- PromptCardViewModel.ApplyStep(args);
+ PromptCardViewModel.ApplyStep(applyArgs);
// Setup Sampler and Refiner if enabled
- SamplerCardViewModel.ApplyStep(args);
+ SamplerCardViewModel.ApplyStep(applyArgs);
// Hires fix if enabled
foreach (var module in ModulesCardViewModel.Cards.OfType())
{
- module.ApplyStep(args);
+ module.ApplyStep(applyArgs);
}
+ applyArgs.InvokeAllPreOutputActions();
+
builder.SetupOutputImage();
}
From ff26180e8bd69ba562583dd9305c031c572889c1 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Thu, 4 Apr 2024 23:08:05 -0400
Subject: [PATCH 112/130] Apply post install dep updates for ComfyUI ext update
---
.../Models/Packages/ComfyUI.cs | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
index 19843e75..c620182c 100644
--- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
+++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
@@ -511,6 +511,32 @@ public class ComfyUI(
}
}
+ ///
+ public override async Task UpdateExtensionAsync(
+ InstalledPackageExtension installedExtension,
+ InstalledPackage installedPackage,
+ PackageExtensionVersion? version = null,
+ IProgress? progress = null,
+ CancellationToken cancellationToken = default
+ )
+ {
+ await base.UpdateExtensionAsync(
+ installedExtension,
+ installedPackage,
+ version,
+ progress,
+ cancellationToken
+ )
+ .ConfigureAwait(false);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var installedDirs = installedExtension.Paths.OfType().Where(dir => dir.Exists);
+
+ await PostInstallAsync(installedPackage, installedDirs, progress, cancellationToken)
+ .ConfigureAwait(false);
+ }
+
///
public override async Task InstallExtensionAsync(
PackageExtension extension,
@@ -539,6 +565,20 @@ public class ComfyUI(
.Select(path => cloneRoot.JoinDir(path!))
.Where(dir => dir.Exists);
+ await PostInstallAsync(installedPackage, installedDirs, progress, cancellationToken)
+ .ConfigureAwait(false);
+ }
+
+ ///
+ /// Runs post install / update tasks (i.e. install.py, requirements.txt)
+ ///
+ private async Task PostInstallAsync(
+ InstalledPackage installedPackage,
+ IEnumerable installedDirs,
+ IProgress? progress = null,
+ CancellationToken cancellationToken = default
+ )
+ {
foreach (var installedDir in installedDirs)
{
cancellationToken.ThrowIfCancellationRequested();
From 6621a8ce58db7787bf05de841e57891e0ba887b0 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Thu, 4 Apr 2024 23:12:24 -0400
Subject: [PATCH 113/130] Update CHANGELOG.md
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa0e8fc8..38097f46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Fixed Civitai model browser not showing images when "Show NSFW" is disabled
- Fixed crash when Installed Workflows page is opened with no Workflows folder
- Fixed progress bars not displaying properly during package installs & updates
+- Fixed ComfyUI extension updates not running install.py / updating requirements.txt
## v2.10.0-pre.1
### Added
From 660dad42454c54016fa41fc961068471567aca7b Mon Sep 17 00:00:00 2001
From: Ionite
Date: Thu, 4 Apr 2024 23:22:39 -0400
Subject: [PATCH 114/130] Add layer diffuse selection for SD1.5 / SDXL
---
.../Inference/LayerDiffuseCardViewModel.cs | 22 +++++++++++++++++--
.../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 6 +++++
.../Models/Inference/LayerDiffuseMode.cs | 12 +++++++---
3 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
index 04cb8b80..865a4c74 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/LayerDiffuseCardViewModel.cs
@@ -37,6 +37,24 @@ public partial class LayerDiffuseCardViewModel : LoadableViewModelBase, IComfySt
if (SelectedMode == LayerDiffuseMode.None)
return;
+ var sdType = SelectedMode switch
+ {
+ LayerDiffuseMode.GenerateForegroundWithTransparencySD15 => "SD15",
+ LayerDiffuseMode.GenerateForegroundWithTransparencySDXL => "SDXL",
+ LayerDiffuseMode.None => throw new ArgumentOutOfRangeException(),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+
+ // Choose config based on mode
+ var config = SelectedMode switch
+ {
+ LayerDiffuseMode.GenerateForegroundWithTransparencySD15
+ => "SD15, Attention Injection, attn_sharing",
+ LayerDiffuseMode.GenerateForegroundWithTransparencySDXL => "SDXL, Conv Injection",
+ LayerDiffuseMode.None => throw new ArgumentOutOfRangeException(),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+
foreach (var modelConnections in e.Temp.Models.Values)
{
var layerDiffuseApply = e.Nodes.AddTypedNode(
@@ -44,7 +62,7 @@ public partial class LayerDiffuseCardViewModel : LoadableViewModelBase, IComfySt
{
Name = e.Nodes.GetUniqueName($"LayerDiffuseApply_{modelConnections.Name}"),
Model = modelConnections.Model,
- Config = "SD15, Attention Injection, attn_sharing",
+ Config = config,
Weight = Weight,
}
);
@@ -71,7 +89,7 @@ public partial class LayerDiffuseCardViewModel : LoadableViewModelBase, IComfySt
Name = applyArgs.Nodes.GetUniqueName("LayerDiffuseDecode"),
Samples = latent,
Images = primaryImage,
- SdVersion = "SD15",
+ SdVersion = sdType
}
);
diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
index a1b79df5..df14284a 100644
--- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
+++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
@@ -391,6 +391,12 @@ public class ComfyNodeBuilder
{
public required ModelNodeConnection Model { get; init; }
+ ///
+ /// Available configs:
+ /// SD15, Attention Injection, attn_sharing
+ /// SDXL, Conv Injection
+ /// SDXL, Attention Injection
+ ///
public required string Config { get; init; }
[Range(-1d, 3d)]
diff --git a/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs b/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
index af243113..35621f60 100644
--- a/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
+++ b/StabilityMatrix.Core/Models/Inference/LayerDiffuseMode.cs
@@ -11,8 +11,14 @@ public enum LayerDiffuseMode
None,
///
- /// Generate foreground only with transparency.
+ /// Generate foreground only with transparency. SD1.5
///
- [Display(Name = "Generate Foreground with Transparency")]
- GenerateForegroundWithTransparency,
+ [Display(Name = "(SD 1.5) Generate Foreground with Transparency")]
+ GenerateForegroundWithTransparencySD15,
+
+ ///
+ /// Generate foreground only with transparency. SDXL
+ ///
+ [Display(Name = "(SDXL) Generate Foreground with Transparency")]
+ GenerateForegroundWithTransparencySDXL,
}
From 2d95adbda7f7786e155bb7e9bb7aa3debb1de536 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Fri, 5 Apr 2024 02:17:56 -0400
Subject: [PATCH 115/130] Fix dmg build script
---
.github/workflows/release.yml | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ffad36eb..320b8bc9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -257,13 +257,11 @@ jobs:
- uses: actions/setup-node@v4
with:
- node-version: '20.x'
+ node-version: '20.11.x'
- name: Install dependencies for dmg creation
- run: >
- npm install --global create-dmg
- brew install graphicsmagick imagemagick
-
+ run: brew install graphicsmagick imagemagick && npm install --global create-dmg
+
- name: Create dmg
working-directory: signing
run: >
From 026b9d0cb1bb440af39f20ea5e85252d9ba0557e Mon Sep 17 00:00:00 2001
From: JT
Date: Sat, 6 Apr 2024 13:34:14 -0700
Subject: [PATCH 116/130] Only download images from civitai with Type ==
"image" since they finally added that property
---
CHANGELOG.md | 4 ++++
.../Services/ModelDownloadLinkHandler.cs | 5 ++++-
.../CheckpointBrowserCardViewModel.cs | 9 +++++++--
.../ViewModels/CheckpointManager/CheckpointFolder.cs | 2 +-
.../Dialogs/RecommendedModelItemViewModel.cs | 4 ++--
.../ViewModels/Dialogs/RecommendedModelsViewModel.cs | 5 ++++-
.../Dialogs/SelectModelVersionViewModel.cs | 2 +-
StabilityMatrix.Core/Models/Api/CivitImage.cs | 3 +++
.../Services/MetadataImportService.cs | 12 +++++++++---
9 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38097f46..73eb4c18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ 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.10.0
+### Fixed
+- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
+
## v2.10.0-pre.2
### Added
- Added more metadata to the image dialog info flyout
diff --git a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs
index 326d715c..62145809 100644
--- a/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs
+++ b/StabilityMatrix.Avalonia/Services/ModelDownloadLinkHandler.cs
@@ -229,7 +229,10 @@ public class ModelDownloadLinkHandler(
return null;
}
- var image = modelVersion.Images[0];
+ var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image");
+ if (image is null)
+ return null;
+
var imageExtension = Path.GetExtension(image.Url).TrimStart('.');
if (imageExtension is "jpg" or "jpeg" or "png")
{
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
index 341a3913..7edf9920 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
@@ -159,7 +159,9 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
// Try to find a valid image
var image = images
- ?.Where(img => LocalModelFile.SupportedImageExtensions.Any(img.Url.Contains))
+ ?.Where(
+ img => LocalModelFile.SupportedImageExtensions.Any(img.Url.Contains) && img.Type == "image"
+ )
.FirstOrDefault(image => nsfwEnabled || image.NsfwLevel <= 1);
if (image != null)
{
@@ -295,7 +297,10 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
return null;
}
- var image = modelVersion.Images[0];
+ var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image");
+ if (image is null)
+ return null;
+
var imageExtension = Path.GetExtension(image.Url).TrimStart('.');
if (imageExtension is "jpg" or "jpeg" or "png")
{
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs
index e11cccdc..39408129 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs
@@ -500,7 +500,7 @@ public partial class CheckpointFolder : ViewModelBase
await modelInfo.SaveJsonToDirectory(DirectoryPath, modelFileName);
// If available, save thumbnail
- var image = version.Images?.FirstOrDefault();
+ var image = version.Images?.FirstOrDefault(x => x.Type == "image");
if (image != null)
{
var imageExt = Path.GetExtension(image.Url).TrimStart('.');
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs
index 3de1d5da..501fa5db 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelItemViewModel.cs
@@ -22,9 +22,9 @@ public partial class RecommendedModelItemViewModel : ViewModelBase
private CivitModel civitModel;
public Uri ThumbnailUrl =>
- ModelVersion.Images?.FirstOrDefault()?.Url == null
+ ModelVersion.Images?.FirstOrDefault(x => x.Type == "image")?.Url == null
? Assets.NoImage
- : new Uri(ModelVersion.Images.First().Url);
+ : new Uri(ModelVersion.Images.First(x => x.Type == "image").Url);
[RelayCommand]
public void ToggleSelection() => IsSelected = !IsSelected;
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
index a2aa480e..5eeaeb6a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
@@ -206,7 +206,10 @@ public partial class RecommendedModelsViewModel : ContentDialogViewModelBase
return null;
}
- var image = modelVersion.Images[0];
+ var image = modelVersion.Images.FirstOrDefault(x => x.Type == "image");
+ if (image is null)
+ return null;
+
var imageExtension = Path.GetExtension(image.Url).TrimStart('.');
if (imageExtension is "jpg" or "jpeg" or "png")
{
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
index 338aa20d..8327e996 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
@@ -99,7 +99,7 @@ public partial class SelectModelVersionViewModel(
var allImages = value
?.ModelVersion
?.Images
- ?.Where(img => nsfwEnabled || img.NsfwLevel <= 1)
+ ?.Where(img => img.Type == "image" && (nsfwEnabled || img.NsfwLevel <= 1))
?.Select(x => new ImageSource(x.Url))
.ToList();
diff --git a/StabilityMatrix.Core/Models/Api/CivitImage.cs b/StabilityMatrix.Core/Models/Api/CivitImage.cs
index 82aadce2..c29e3bac 100644
--- a/StabilityMatrix.Core/Models/Api/CivitImage.cs
+++ b/StabilityMatrix.Core/Models/Api/CivitImage.cs
@@ -19,5 +19,8 @@ public class CivitImage
[JsonPropertyName("hash")]
public string Hash { get; set; }
+ [JsonPropertyName("type")]
+ public string Type { get; set; }
+
// TODO: "meta" ( object? )
}
diff --git a/StabilityMatrix.Core/Services/MetadataImportService.cs b/StabilityMatrix.Core/Services/MetadataImportService.cs
index d31a603d..21ce5a2c 100644
--- a/StabilityMatrix.Core/Services/MetadataImportService.cs
+++ b/StabilityMatrix.Core/Services/MetadataImportService.cs
@@ -107,7 +107,9 @@ public class MetadataImportService(
.ConfigureAwait(false);
var image = modelVersion.Images?.FirstOrDefault(
- img => LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ img =>
+ LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ && img.Type == "image"
);
if (image == null)
{
@@ -201,7 +203,9 @@ public class MetadataImportService(
.ConfigureAwait(false);
var image = modelVersion.Images?.FirstOrDefault(
- img => LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ img =>
+ LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ && img.Type == "image"
);
if (image == null)
continue;
@@ -264,7 +268,9 @@ public class MetadataImportService(
.ConfigureAwait(false);
var image = modelVersion.Images?.FirstOrDefault(
- img => LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ img =>
+ LocalModelFile.SupportedImageExtensions.Contains(Path.GetExtension(img.Url))
+ && img.Type == "image"
);
if (image == null)
From e5d215463e626d285f54dba694292880af7788ad Mon Sep 17 00:00:00 2001
From: JT
Date: Sat, 6 Apr 2024 17:10:20 -0700
Subject: [PATCH 117/130] updated spanish/french/turkish translations
---
CHANGELOG.md | 2 +
.../Languages/Resources.es.resx | 62 +++++++++++++++++++
.../Languages/Resources.fr-FR.resx | 50 ++++++++++++++-
.../Languages/Resources.tr-TR.resx | 60 ++++++++++++++++++
4 files changed, 173 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 73eb4c18..7456d558 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ 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.10.0
+### Changed
+- Updated translations for French, Spanish, and Turkish
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.es.resx b/StabilityMatrix.Avalonia/Languages/Resources.es.resx
index 5efb7a15..28b0dae1 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.es.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.es.resx
@@ -963,4 +963,66 @@
Mientras se instala tu paquete, aquí hay algunos modelos que recomendamos para ayudarte a comenzar.
+
+ Notificaciones
+
+
+ Ninguno
+
+
+ Se Requiere ComfyUI
+
+
+ Se requiere ComfyUI para instalar este paquete. ¿Quieres instalarlo ahora?
+
+
+ Por favor, seleccione una ubicación de descarga.
+
+
+ Seleccione la Ubicación de Descarga:
+
+
+ Configuración
+ This is used in inference when models have a yaml config file
+
+
+ Desplazamiento Automático hasta el Final
+
+
+ Confirmar Salida
+
+
+ ¿Seguro que quieres salir? Esto también cerrará cualquier paquete que se esté ejecutando actualmente.
+
+
+ Consola
+
+
+ Interfaz Web
+ This will be used on a button to launch the web ui
+
+
+ Paquetes
+
+
+ Esta acción no se puede deshacer.
+
+
+ ¿Estás seguro de que deseas eliminar {0} imágenes?
+
+
+ Estamos verificando algunas especificaciones de hardware para determinar la compatibilidad.
+
+
+ ¡Todo parece estar bien!
+
+
+ Recomendamos una GPU con soporte CUDA para obtener la mejor experiencia. Puedes continuar sin una, pero es posible que algunos paquetes no funcionen y la inferencia pueda ser más lenta.
+
+
+ Checkpoints
+
+
+ Navegador de Modelos
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
index 6e195f4d..f205b67c 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
@@ -598,7 +598,7 @@
Informations sur la version de Python
- Redémarrage
+ Redémarrer
Confirmer la suppression
@@ -930,4 +930,52 @@
Pendant que votre paquet s'installe, voici quelques modèles que nous recommandons pour vous aidez à démarrer.
+
+ Notifications
+
+
+ Aucun
+
+
+ ComfyUI est requis
+
+
+ ComfyUI est requis pour installer ce paquet. Voulez vous l'installer maintenant ?
+
+
+ Merci de sélectionner un dossier de téléchargement.
+
+
+ Sélectionner un dossier de téléchargement:
+
+
+ Défiler automatiquement à la fin
+
+
+ Confirmer la sortie
+
+
+ Êtes vous certain de vouloir quitter ? Cela va fermer toutes les instances actuellement lancées.
+
+
+ Console
+
+
+ Paquets
+
+
+ Cette action ne peut être annulée.
+
+
+ Êtes vous certain de vouloir supprimer les {0} images?
+
+
+ Nous vérifions quelques spécifications matérielles pour vérifier la compatibilité.
+
+
+ Tout à l'air bon!
+
+
+ Nous recommandons un GPU avec prise en charge CUDA pour une meilleure expérience. Vous pouvez continuer sans en avoir un, mais certains packages peuvent ne pas fonctionner et l'inférence peut être plus lente.
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx b/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
index 8d2e1d7f..5b6064d2 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
@@ -961,4 +961,64 @@
Paketiniz yüklenirken başlamanıza yardımcı olması için önerdiğimiz bazı modeller aşağıda verilmiştir.
+
+ Bildirimler
+
+
+ Hiçbiri
+
+
+ ComfyUI Gerekli
+
+
+ Bu paketi kurmak için ComfyUI gereklidir. Şimdi yüklemek ister misiniz?
+
+
+ Lütfen bir indirme konumu seçin.
+
+
+ İndirme Konumunu Seçin:
+
+
+ Yapılandırma
+
+
+ Otomatik Sona Kaydır
+
+
+ Çıkışı Onayla
+
+
+ Çıkmak istediğine emin misin? Bu aynı zamanda şu anda çalışan tüm paketleri de kapatacaktır.
+
+
+ Konsol
+
+
+ Web arayüzü
+
+
+ Paketler
+
+
+ Bu eylem geri alınamaz.
+
+
+ {0} görseli silmek istediğinizden emin misiniz?
+
+
+ Uyumluluğu belirlemek için bazı donanım özelliklerini kontrol ediyoruz.
+
+
+ Her şey iyi gözüküyor!
+
+
+ En iyi deneyim için CUDA destekli bir GPU öneriyoruz. Olmadan da devam edebilirsiniz ancak bazı paketler çalışmayabilir ve çıkarımlar daha yavaş olabilir.
+
+
+ Kontrol noktaları
+
+
+ Model Tarayıcı
+
\ No newline at end of file
From 612509f4ff59e6ff634e86f87dfec3a8696682e5 Mon Sep 17 00:00:00 2001
From: JT
Date: Sun, 7 Apr 2024 11:25:21 -0700
Subject: [PATCH 118/130] Fixed incorrect output path for A3WebUI & made
package launch update output links
---
CHANGELOG.md | 1 +
.../Services/RunningPackageService.cs | 5 +++++
StabilityMatrix.Core/Models/Packages/A3WebUI.cs | 17 +++++++++++------
.../Models/Packages/SDWebForge.cs | 5 -----
4 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7456d558..0d4dcaaf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Updated translations for French, Spanish, and Turkish
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
+- Fixed [#522](https://github.com/LykosAI/StabilityMatrix/issues/522) - Incorrect output directory path for latest Auto1111
## v2.10.0-pre.2
### Added
diff --git a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs
index 96f1d719..38db4dc3 100644
--- a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs
+++ b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs
@@ -100,6 +100,11 @@ public partial class RunningPackageService(
installedPackage.PreferredSharedFolderMethod ?? basePackage.RecommendedSharedFolderMethod
);
+ if (installedPackage.UseSharedOutputFolder)
+ {
+ await basePackage.SetupOutputFolderLinks(installedPackage.FullPath!);
+ }
+
// Load user launch args from settings and convert to string
var userArgs = installedPackage.LaunchArgs ?? [];
var userArgsString = string.Join(" ", userArgs.Select(opt => opt.ToArgString()));
diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs
index f823efeb..9635cecc 100644
--- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs
+++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs
@@ -72,12 +72,12 @@ public class A3WebUI(
public override Dictionary>? SharedOutputFolders =>
new()
{
- [SharedOutputType.Extras] = new[] { "outputs/extras-images" },
+ [SharedOutputType.Extras] = new[] { "output/extras-images" },
[SharedOutputType.Saved] = new[] { "log/images" },
- [SharedOutputType.Img2Img] = new[] { "outputs/img2img-images" },
- [SharedOutputType.Text2Img] = new[] { "outputs/txt2img-images" },
- [SharedOutputType.Img2ImgGrids] = new[] { "outputs/img2img-grids" },
- [SharedOutputType.Text2ImgGrids] = new[] { "outputs/txt2img-grids" }
+ [SharedOutputType.Img2Img] = new[] { "output/img2img-images" },
+ [SharedOutputType.Text2Img] = new[] { "output/txt2img-images" },
+ [SharedOutputType.Img2ImgGrids] = new[] { "output/img2img-grids" },
+ [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" }
};
[SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")]
@@ -184,7 +184,7 @@ public class A3WebUI(
public override string MainBranch => "master";
- public override string OutputFolderName => "outputs";
+ public override string OutputFolderName => "output";
public override IPackageExtensionManager ExtensionManager => new A3WebUiExtensionManager(this);
@@ -294,6 +294,11 @@ public class A3WebUI(
VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit);
}
+ public override string? ExtraLaunchArguments { get; set; } =
+ settingsManager.IsLibraryDirSet
+ ? $"--gradio-allowed-path \"{settingsManager.ImagesDirectory}\""
+ : string.Empty;
+
private class A3WebUiExtensionManager(A3WebUI package)
: GitPackageExtensionManager(package.PrerequisiteHelper)
{
diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
index 69a501d9..f64a4197 100644
--- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
+++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
@@ -178,9 +178,4 @@ public class SDWebForge(
await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, "Install complete", isIndeterminate: false));
}
-
- public override string? ExtraLaunchArguments { get; set; } =
- settingsManager.IsLibraryDirSet
- ? $"--gradio-allowed-path \"{settingsManager.ImagesDirectory}\""
- : string.Empty;
}
From 4e42eee757f6a68d8eb3eb7c2be1f206da16e020 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Sun, 7 Apr 2024 17:37:47 -0400
Subject: [PATCH 119/130] Add default env vars, set
SETUPTOOLS_USE_DISTUTILS=stdlib
---
.../ViewModels/Settings/MainSettingsViewModel.cs | 4 ++--
StabilityMatrix.Core/Models/Settings/Settings.cs | 13 ++++++++++++-
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
index 0da8ab4c..c02c396b 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
@@ -365,7 +365,7 @@ public partial class MainSettingsViewModel : PageViewModelBase
var viewModel = dialogFactory.Get();
// Load current settings
- var current = settingsManager.Settings.EnvironmentVariables ?? new Dictionary();
+ var current = settingsManager.Settings.UserEnvironmentVariables ?? new Dictionary();
viewModel.EnvVars = new ObservableCollection(
current.Select(kvp => new EnvVarKeyPair(kvp.Key, kvp.Value))
);
@@ -385,7 +385,7 @@ public partial class MainSettingsViewModel : PageViewModelBase
.EnvVars.Where(kvp => !string.IsNullOrWhiteSpace(kvp.Key))
.GroupBy(kvp => kvp.Key, StringComparer.Ordinal)
.ToDictionary(g => g.Key, g => g.First().Value, StringComparer.Ordinal);
- settingsManager.Transaction(s => s.EnvironmentVariables = newEnvVars);
+ settingsManager.Transaction(s => s.UserEnvironmentVariables = newEnvVars);
}
}
diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs
index bf5e080f..01e22fd2 100644
--- a/StabilityMatrix.Core/Models/Settings/Settings.cs
+++ b/StabilityMatrix.Core/Models/Settings/Settings.cs
@@ -110,7 +110,18 @@ public class Settings
public bool IsDiscordRichPresenceEnabled { get; set; }
- public Dictionary? EnvironmentVariables { get; set; }
+ [JsonIgnore]
+ public Dictionary DefaultEnvironmentVariables { get; } =
+ new() { ["SETUPTOOLS_USE_DISTUTILS"] = "stdlib" };
+
+ [JsonPropertyName("EnvironmentVariables")]
+ public Dictionary? UserEnvironmentVariables { get; set; }
+
+ [JsonIgnore]
+ public IReadOnlyDictionary EnvironmentVariables =>
+ DefaultEnvironmentVariables
+ .Concat(UserEnvironmentVariables ?? [])
+ .ToDictionary(x => x.Key, x => x.Value);
public HashSet? InstalledModelHashes { get; set; } = new();
From 43f3c28b9a9cf8ee60c168572b550fbb8e2210d7 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Mon, 8 Apr 2024 00:16:40 -0400
Subject: [PATCH 120/130] Update CHANGELOG.md
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d4dcaaf..91ae423d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
- Fixed [#522](https://github.com/LykosAI/StabilityMatrix/issues/522) - Incorrect output directory path for latest Auto1111
+- Fixed CLIP Install errors due to setuptools distutils conflict, added default environment variable setting `SETUPTOOLS_USE_DISTUTILS=stdlib`
## v2.10.0-pre.2
### Added
From d211db88ab9bbd521953af99b81b8d75913ae6db Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 8 Apr 2024 18:02:13 -0700
Subject: [PATCH 121/130] Chunk installed model requests with more than 100
installed models cuz Civit doesn't paginate that
---
CHANGELOG.md | 1 +
.../CivitAiBrowserViewModel.cs | 42 ++++++++++++++++---
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d4dcaaf..8cb19019 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
- Fixed [#522](https://github.com/LykosAI/StabilityMatrix/issues/522) - Incorrect output directory path for latest Auto1111
+- Fixed Civitai model browser error when sorting by Installed with more than 100 installed models
## v2.10.0-pre.2
### Added
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
index 4754397d..ebf5401a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
@@ -196,10 +196,40 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScro
{
var timer = Stopwatch.StartNew();
var queryText = request.Query;
+ var models = new List();
+ CivitModelsResponse? modelsResponse = null;
try
{
- var modelsResponse = await civitApi.GetModels(request);
- var models = modelsResponse.Items;
+ if (!string.IsNullOrWhiteSpace(request.CommaSeparatedModelIds))
+ {
+ // count IDs
+ var ids = request.CommaSeparatedModelIds.Split(',');
+ if (ids.Length > 100)
+ {
+ var idChunks = ids.Chunk(100);
+ foreach (var chunk in idChunks)
+ {
+ request.CommaSeparatedModelIds = string.Join(",", chunk);
+ var chunkModelsResponse = await civitApi.GetModels(request);
+
+ if (chunkModelsResponse.Items != null)
+ {
+ models.AddRange(chunkModelsResponse.Items);
+ }
+ }
+ }
+ else
+ {
+ modelsResponse = await civitApi.GetModels(request);
+ models = modelsResponse.Items;
+ }
+ }
+ else
+ {
+ modelsResponse = await civitApi.GetModels(request);
+ models = modelsResponse.Items;
+ }
+
if (models is null)
{
Logger.Debug(
@@ -241,13 +271,13 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScro
InsertedAt = DateTimeOffset.UtcNow,
Request = request,
Items = models,
- Metadata = modelsResponse.Metadata
+ Metadata = modelsResponse?.Metadata
}
);
UpdateModelCards(models, isInfiniteScroll);
- NextPageCursor = modelsResponse.Metadata?.NextCursor;
+ NextPageCursor = modelsResponse?.Metadata?.NextCursor;
}
catch (OperationCanceledException)
{
@@ -428,12 +458,14 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScro
{
var connectedModels = CheckpointFile
.GetAllCheckpointFiles(settingsManager.ModelsDirectory)
- .Where(c => c.IsConnectedModel);
+ .Where(c => c.IsConnectedModel)
+ .ToList();
modelRequest.CommaSeparatedModelIds = string.Join(
",",
connectedModels.Select(c => c.ConnectedModel!.ModelId).GroupBy(m => m).Select(g => g.First())
);
+
modelRequest.Sort = null;
modelRequest.Period = null;
}
From 96f507619c7c2794bfb010cf7cd6a9aa56e4a557 Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 8 Apr 2024 20:28:17 -0700
Subject: [PATCH 122/130] release changelog
---
CHANGELOG.md | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97092981..2d35c902 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,13 +6,35 @@ 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.10.0
+### Added
+- Added Reference-Only mode for Inference ControlNet, used for guiding the sampler with an image without a pretrained model. Part of the latent and attention layers will be connected to the reference image, similar to Image to Image or Inpainting.
+- Inference ControlNet module now supports over 42 preprocessors, a new button next to the preprocessors dropdown allows previewing the output of the selected preprocessor on the image.
+- Added resolution selection for Inference ControlNet module, this controls preprocessor resolution too.
+- Added support for deep links from the new Stability Matrix Chrome extension
+- Added OpenArt.AI workflow browser for ComfyUI workflows
+- Added more metadata to the image dialog info flyout
+- Added Output Sharing toggle in Advanced Options during install flow
### Changed
+- Revamped the Packages page to enable running multiple packages at the same time
+- Changed the Outputs Page to use a TreeView for the directory selection instead of a dropdown selector
+- Model download location selector now searches all subfolders
+- Inference Primary Sampler Addons (i.e. ControlNet, FreeU) are now inherited by Hires Fix Samplers, this can be overriden from the Hires Fix module's settings menu by disabling the "Inherit Primary Sampler Addons" option.
+- Revisited the way images are loaded on the outputs page, with improvements to loading speed & not freezing the UI while loading
- Updated translations for French, Spanish, and Turkish
+- Changed to a new image control for pages with many images
+- (Internal) Updated to Avalonia 11.0.10
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
- Fixed [#522](https://github.com/LykosAI/StabilityMatrix/issues/522) - Incorrect output directory path for latest Auto1111
- Fixed Civitai model browser error when sorting by Installed with more than 100 installed models
- Fixed CLIP Install errors due to setuptools distutils conflict, added default environment variable setting `SETUPTOOLS_USE_DISTUTILS=stdlib`
+- Fixed progress bars not displaying properly during package installs & updates
+- Fixed ComfyUI extension updates not running install.py / updating requirements.txt
+- Improved performance when deleting many images from the Outputs page
+- Fixed ComfyUI torch downgrading to 2.1.2 when updating
+- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
+### Removed
+- Removed the main Launch page, as it is no longer needed with the new Packages page
## v2.10.0-pre.2
### Added
@@ -40,6 +62,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Fixed ComfyUI torch downgrading to 2.1.2 when updating
- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
- Fixed "Could not find entry point for InvokeAI" error on InvokeAI v4.0+
+- Fixed Inference HiresFix module "Inherit Primary Sampler Addons" setting not effectively disabling when unchecked
+- Fixed model download location options for VAEs in the CivitAI Model Browser
+
## v2.10.0-dev.3
### Added
From 8ba15c73a1290b593aca642795248efdb7796daa Mon Sep 17 00:00:00 2001
From: JT
Date: Mon, 8 Apr 2024 20:29:25 -0700
Subject: [PATCH 123/130] oops wrong section
---
CHANGELOG.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d35c902..14157ffd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,13 +26,15 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
### Fixed
- Fixed [#559](https://github.com/LykosAI/StabilityMatrix/issues/559) - "Unable to load bitmap from provided data" error in Checkpoints page
- Fixed [#522](https://github.com/LykosAI/StabilityMatrix/issues/522) - Incorrect output directory path for latest Auto1111
+- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
- Fixed Civitai model browser error when sorting by Installed with more than 100 installed models
- Fixed CLIP Install errors due to setuptools distutils conflict, added default environment variable setting `SETUPTOOLS_USE_DISTUTILS=stdlib`
- Fixed progress bars not displaying properly during package installs & updates
- Fixed ComfyUI extension updates not running install.py / updating requirements.txt
- Improved performance when deleting many images from the Outputs page
- Fixed ComfyUI torch downgrading to 2.1.2 when updating
-- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
+- Fixed Inference HiresFix module "Inherit Primary Sampler Addons" setting not effectively disabling when unchecked
+- Fixed model download location options for VAEs in the CivitAI Model Browser
### Removed
- Removed the main Launch page, as it is no longer needed with the new Packages page
@@ -62,9 +64,6 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Fixed ComfyUI torch downgrading to 2.1.2 when updating
- Fixed [#529](https://github.com/LykosAI/StabilityMatrix/issues/529) - OneTrainer requesting input during update
- Fixed "Could not find entry point for InvokeAI" error on InvokeAI v4.0+
-- Fixed Inference HiresFix module "Inherit Primary Sampler Addons" setting not effectively disabling when unchecked
-- Fixed model download location options for VAEs in the CivitAI Model Browser
-
## v2.10.0-dev.3
### Added
From 2a22a43cc8e3f6015e8a3f2349c9a786c4902923 Mon Sep 17 00:00:00 2001
From: JT
Date: Wed, 10 Apr 2024 18:51:20 -0700
Subject: [PATCH 124/130] Fixed double 2.9.2 changelog
---
CHANGELOG.md | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5648ef9f..d14f30f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -111,15 +111,6 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Fixed images not appearing in Civitai Model Browser when "Show NSFW" was disabled
- Fixed [#556](https://github.com/LykosAI/StabilityMatrix/issues/556) - "Could not find entry point for InvokeAI" error
-## v2.9.2
-### Changed
-- Model download location selector now searches all subfolders
-### Fixed
-- Fixed Civitai model browser not showing images when "Show NSFW" is disabled
-- Fixed crash when Installed Workflows page is opened with no Workflows folder
-- Fixed progress bars not displaying properly during package installs & updates
-- Fixed ComfyUI extension updates not running install.py / updating requirements.txt
-
## v2.9.2
### Changed
- Due to changes with the CivitAI API, you can no longer select a specific page in the CivitAI Model Browser
From 8e1c00312c48ce57c11345f9381b5030ce6c2dbe Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 10 Apr 2024 21:53:59 -0400
Subject: [PATCH 125/130] Add Inference prompt help tooltip
---
.../Controls/Inference/PromptCard.axaml | 30 ++++++++++++-------
.../Controls/Inference/PromptCard.axaml.cs | 2 +-
.../Languages/Resources.Designer.cs | 9 ++++++
.../Languages/Resources.resx | 3 ++
.../Inference/PromptCardViewModel.cs | 30 +++++++++++++++++++
.../Models/Settings/TeachingTip.cs | 1 +
6 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/PromptCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/PromptCard.axaml
index 7c53337d..12423e48 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/PromptCard.axaml
+++ b/StabilityMatrix.Avalonia/Controls/Inference/PromptCard.axaml
@@ -8,6 +8,8 @@
xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
x:DataType="vmInference:PromptCardViewModel">
@@ -56,21 +58,29 @@
HorizontalAlignment="Right"
Orientation="Horizontal">
-
-
+
+
+
+
+
+
-
+
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 388037ce..e38cda20 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -2795,6 +2795,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
+ ///
+ /// Looks up a localized string similar to Click here to review prompt syntax and how to include Lora / Embeddings..
+ ///
+ public static string TeachingTip_InferencePromptHelpButton {
+ get {
+ return ResourceManager.GetString("TeachingTip_InferencePromptHelpButton", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Additional folders such as IPAdapters and TextualInversions (embeddings) can be enabled here.
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index 4c70a20c..ee360cb1 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -1068,4 +1068,7 @@
The workflow and custom nodes have been imported.
+
+ Click here to review prompt syntax and how to include Lora / Embeddings.
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs
index d4a2b895..919e4e30 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs
@@ -20,6 +20,7 @@ using StabilityMatrix.Core.Exceptions;
using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
+using StabilityMatrix.Core.Models.Settings;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@@ -30,6 +31,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoadableState, IComfyStep
{
private readonly IModelIndexService modelIndexService;
+ private readonly ISettingsManager settingsManager;
///
/// Cache of prompt text to tokenized Prompt
@@ -48,6 +50,9 @@ public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoa
[ObservableProperty]
private bool isAutoCompletionEnabled;
+ [ObservableProperty]
+ private bool isHelpButtonTeachingTipOpen;
+
///
public PromptCardViewModel(
ICompletionProvider completionProvider,
@@ -59,6 +64,7 @@ public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoa
)
{
this.modelIndexService = modelIndexService;
+ this.settingsManager = settingsManager;
CompletionProvider = completionProvider;
TokenizerProvider = tokenizerProvider;
SharedState = sharedState;
@@ -77,6 +83,30 @@ public partial class PromptCardViewModel : LoadableViewModelBase, IParametersLoa
);
}
+ partial void OnIsHelpButtonTeachingTipOpenChanging(bool oldValue, bool newValue)
+ {
+ // If the teaching tip is being closed, save the setting
+ if (oldValue && !newValue)
+ {
+ settingsManager.Transaction(settings =>
+ {
+ settings.SeenTeachingTips.Add(TeachingTip.InferencePromptHelpButtonTip);
+ });
+ }
+ }
+
+ ///
+ public override void OnLoaded()
+ {
+ base.OnLoaded();
+
+ // Show teaching tip for help button if not seen
+ if (!settingsManager.Settings.SeenTeachingTips.Contains(TeachingTip.InferencePromptHelpButtonTip))
+ {
+ IsHelpButtonTeachingTipOpen = true;
+ }
+ }
+
///
/// Applies the prompt step.
/// Requires:
diff --git a/StabilityMatrix.Core/Models/Settings/TeachingTip.cs b/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
index 92a6ea3d..d69595c7 100644
--- a/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
+++ b/StabilityMatrix.Core/Models/Settings/TeachingTip.cs
@@ -14,6 +14,7 @@ public record TeachingTip(string Value) : StringValue(Value)
public static TeachingTip PackageExtensionsInstallNotice => new("PackageExtensionsInstallNotice");
public static TeachingTip DownloadsTip => new("DownloadsTip");
public static TeachingTip WebUiButtonMovedTip => new("WebUiButtonMovedTip");
+ public static TeachingTip InferencePromptHelpButtonTip => new("InferencePromptHelpButtonTip");
///
public override string ToString()
From 04e5459f756ed4e021cc0cf2da67e832fec346cc Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 10 Apr 2024 21:56:10 -0400
Subject: [PATCH 126/130] Add layer diffuse changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14157ffd..546b1b81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Added Reference-Only mode for Inference ControlNet, used for guiding the sampler with an image without a pretrained model. Part of the latent and attention layers will be connected to the reference image, similar to Image to Image or Inpainting.
- Inference ControlNet module now supports over 42 preprocessors, a new button next to the preprocessors dropdown allows previewing the output of the selected preprocessor on the image.
- Added resolution selection for Inference ControlNet module, this controls preprocessor resolution too.
+- Added Layer Diffuse sampler addon to Inference, allows generating foreground with transparency with SD1.5 and SDXL.
- Added support for deep links from the new Stability Matrix Chrome extension
- Added OpenArt.AI workflow browser for ComfyUI workflows
- Added more metadata to the image dialog info flyout
From 38a104146f193a50df1aebd9c6808e8fec0d0cd0 Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 10 Apr 2024 23:19:44 -0400
Subject: [PATCH 127/130] Add vendored labs controls to fix asyncimage
---
.../AsyncImage/AsyncImageFailedEventArgs.cs | 20 +
.../AsyncImage/BetterAsyncImage.Events.cs | 42 ++
.../AsyncImage/BetterAsyncImage.Properties.cs | 135 +++++
.../VendorLabs/AsyncImage/BetterAsyncImage.cs | 248 ++++++++
.../Controls/VendorLabs/Cache/CacheBase.cs | 565 ++++++++++++++++++
.../Controls/VendorLabs/Cache/CacheOptions.cs | 18 +
.../Controls/VendorLabs/Cache/FileCache.cs | 36 ++
.../Controls/VendorLabs/Cache/ImageCache.cs | 76 +++
.../VendorLabs/Cache/InMemoryStorage.cs | 156 +++++
.../VendorLabs/Cache/InMemoryStorageItem.cs | 49 ++
.../Controls/VendorLabs/LICENSE | 21 +
...tabilityMatrix.Avalonia.csproj.DotSettings | 3 +-
12 files changed, 1368 insertions(+), 1 deletion(-)
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/AsyncImageFailedEventArgs.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Events.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/FileCache.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorageItem.cs
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/LICENSE
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/AsyncImageFailedEventArgs.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/AsyncImageFailedEventArgs.cs
new file mode 100644
index 00000000..b236c348
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/AsyncImageFailedEventArgs.cs
@@ -0,0 +1,20 @@
+using System;
+using Avalonia.Interactivity;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs;
+
+public partial class BetterAsyncImage
+{
+ public class AsyncImageFailedEventArgs : RoutedEventArgs
+ {
+ internal AsyncImageFailedEventArgs(Exception? errorException = null, string errorMessage = "")
+ : base(FailedEvent)
+ {
+ ErrorException = errorException;
+ ErrorMessage = errorMessage;
+ }
+
+ public Exception? ErrorException { get; private set; }
+ public string ErrorMessage { get; private set; }
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Events.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Events.cs
new file mode 100644
index 00000000..3219a46d
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Events.cs
@@ -0,0 +1,42 @@
+using System;
+using Avalonia.Interactivity;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs;
+
+public partial class BetterAsyncImage
+{
+ ///
+ /// Deines the event
+ ///
+ public static readonly RoutedEvent OpenedEvent = RoutedEvent.Register<
+ BetterAsyncImage,
+ RoutedEventArgs
+ >(nameof(Opened), RoutingStrategies.Bubble);
+
+ ///
+ /// Deines the event
+ ///
+ public static readonly RoutedEvent FailedEvent =
+ RoutedEvent.Register<
+ BetterAsyncImage,
+ global::Avalonia.Labs.Controls.AsyncImage.AsyncImageFailedEventArgs
+ >(nameof(Failed), RoutingStrategies.Bubble);
+
+ ///
+ /// Occurs when the image is successfully loaded.
+ ///
+ public event EventHandler? Opened
+ {
+ add => AddHandler(OpenedEvent, value);
+ remove => RemoveHandler(OpenedEvent, value);
+ }
+
+ ///
+ /// Occurs when the image fails to load the uri provided.
+ ///
+ public event EventHandler? Failed
+ {
+ add => AddHandler(FailedEvent, value);
+ remove => RemoveHandler(FailedEvent, value);
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs
new file mode 100644
index 00000000..c31f00aa
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.Properties.cs
@@ -0,0 +1,135 @@
+using System;
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Labs.Controls;
+using Avalonia.Media;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs;
+
+public partial class BetterAsyncImage
+{
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty PlaceholderSourceProperty = AvaloniaProperty.Register<
+ BetterAsyncImage,
+ IImage?
+ >(nameof(PlaceholderSource));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty SourceProperty = AvaloniaProperty.Register<
+ BetterAsyncImage,
+ Uri?
+ >(nameof(Source));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty StretchProperty = AvaloniaProperty.Register<
+ BetterAsyncImage,
+ Stretch
+ >(nameof(Stretch), Stretch.Uniform);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty PlaceholderStretchProperty = AvaloniaProperty.Register<
+ BetterAsyncImage,
+ Stretch
+ >(nameof(PlaceholderStretch), Stretch.Uniform);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly DirectProperty StateProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(State),
+ o => o.State,
+ (o, v) => o.State = v
+ );
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ImageTransitionProperty =
+ AvaloniaProperty.Register(
+ nameof(ImageTransition),
+ new CrossFade(TimeSpan.FromSeconds(0.25))
+ );
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly DirectProperty IsCacheEnabledProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(IsCacheEnabled),
+ o => o.IsCacheEnabled,
+ (o, v) => o.IsCacheEnabled = v
+ );
+ private bool _isCacheEnabled;
+
+ ///
+ /// Gets or sets the placeholder image.
+ ///
+ public IImage? PlaceholderSource
+ {
+ get => GetValue(PlaceholderSourceProperty);
+ set => SetValue(PlaceholderSourceProperty, value);
+ }
+
+ ///
+ /// Gets or sets the uri pointing to the image resource
+ ///
+ public Uri? Source
+ {
+ get => GetValue(SourceProperty);
+ set => SetValue(SourceProperty, value);
+ }
+
+ ///
+ /// Gets or sets a value controlling how the image will be stretched.
+ ///
+ public Stretch Stretch
+ {
+ get { return GetValue(StretchProperty); }
+ set { SetValue(StretchProperty, value); }
+ }
+
+ ///
+ /// Gets or sets a value controlling how the placeholder will be stretched.
+ ///
+ public Stretch PlaceholderStretch
+ {
+ get { return GetValue(StretchProperty); }
+ set { SetValue(StretchProperty, value); }
+ }
+
+ ///
+ /// Gets the current loading state of the image.
+ ///
+ public AsyncImageState State
+ {
+ get => _state;
+ private set => SetAndRaise(StateProperty, ref _state, value);
+ }
+
+ ///
+ /// Gets or sets the transition to run when the image is loaded.
+ ///
+ public IPageTransition? ImageTransition
+ {
+ get => GetValue(ImageTransitionProperty);
+ set => SetValue(ImageTransitionProperty, value);
+ }
+
+ ///
+ /// Gets or sets whether to use cache for retrieved images
+ ///
+ public bool IsCacheEnabled
+ {
+ get => _isCacheEnabled;
+ set => SetAndRaise(IsCacheEnabledProperty, ref _isCacheEnabled, value);
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs
new file mode 100644
index 00000000..ec0cfa54
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/AsyncImage/BetterAsyncImage.cs
@@ -0,0 +1,248 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
+using Avalonia.Interactivity;
+using Avalonia.Labs.Controls;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs;
+
+///
+/// An image control that asynchronously retrieves an image using a .
+///
+[TemplatePart("PART_Image", typeof(Image))]
+[TemplatePart("PART_PlaceholderImage", typeof(Image))]
+public partial class BetterAsyncImage : TemplatedControl
+{
+ protected Image? ImagePart { get; private set; }
+ protected Image? PlaceholderPart { get; private set; }
+
+ private bool _isInitialized;
+ private CancellationTokenSource? _tokenSource;
+ private AsyncImageState _state;
+
+ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+ {
+ base.OnApplyTemplate(e);
+
+ ImagePart = e.NameScope.Get("PART_Image");
+ PlaceholderPart = e.NameScope.Get("PART_PlaceholderImage");
+
+ _tokenSource = new CancellationTokenSource();
+
+ _isInitialized = true;
+
+ if (Source != null)
+ {
+ SetSource(Source);
+ }
+ }
+
+ private async void SetSource(object? source)
+ {
+ if (!_isInitialized)
+ {
+ return;
+ }
+
+ _tokenSource?.Cancel();
+
+ _tokenSource = new CancellationTokenSource();
+
+ AttachSource(null);
+
+ if (source == null)
+ {
+ return;
+ }
+
+ State = AsyncImageState.Loading;
+
+ if (Source is IImage image)
+ {
+ AttachSource(image);
+
+ return;
+ }
+
+ if (Source == null)
+ {
+ return;
+ }
+
+ var uri = Source;
+
+ if (uri != null && uri.IsAbsoluteUri)
+ {
+ if (uri.Scheme == "http" || uri.Scheme == "https")
+ {
+ Bitmap? bitmap = null;
+ // Android doesn't allow network requests on the main thread, even though we are using async apis.
+#if NET6_0_OR_GREATER
+ if (OperatingSystem.IsAndroid())
+ {
+ await Task.Run(async () =>
+ {
+ try
+ {
+ bitmap = await LoadImageAsync(uri, _tokenSource.Token);
+ }
+ catch (Exception ex)
+ {
+ await Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ State = AsyncImageState.Failed;
+
+ RaiseEvent(new AsyncImageFailedEventArgs(ex));
+ });
+ }
+ });
+ }
+ else
+#endif
+ {
+ try
+ {
+ bitmap = await LoadImageAsync(uri, _tokenSource.Token);
+ }
+ catch (Exception ex)
+ {
+ await Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ State = AsyncImageState.Failed;
+
+ RaiseEvent(new AsyncImageFailedEventArgs(ex));
+ });
+ }
+ }
+
+ AttachSource(bitmap);
+ }
+ else if (uri.Scheme == "avares")
+ {
+ try
+ {
+ AttachSource(new Bitmap(AssetLoader.Open(uri)));
+ }
+ catch (Exception ex)
+ {
+ State = AsyncImageState.Failed;
+
+ RaiseEvent(new AsyncImageFailedEventArgs(ex));
+ }
+ }
+ else if (uri.Scheme == "file" && File.Exists(uri.LocalPath))
+ {
+ // Added error handling here for local files
+ try
+ {
+ AttachSource(new Bitmap(uri.LocalPath));
+ }
+ catch (Exception ex)
+ {
+ State = AsyncImageState.Failed;
+
+ RaiseEvent(new AsyncImageFailedEventArgs(ex));
+ }
+ }
+ else
+ {
+ RaiseEvent(
+ new AsyncImageFailedEventArgs(
+ new UriFormatException($"Uri has unsupported scheme. Uri:{source}")
+ )
+ );
+ }
+ }
+ else
+ {
+ RaiseEvent(
+ new AsyncImageFailedEventArgs(
+ new UriFormatException($"Relative paths aren't supported. Uri:{source}")
+ )
+ );
+ }
+ }
+
+ private void AttachSource(IImage? image)
+ {
+ if (ImagePart != null)
+ {
+ ImagePart.Source = image;
+ }
+
+ _tokenSource?.Cancel();
+ _tokenSource = new CancellationTokenSource();
+
+ if (image == null)
+ {
+ State = AsyncImageState.Unloaded;
+
+ ImageTransition?.Start(ImagePart, PlaceholderPart, true, _tokenSource.Token);
+ }
+ else if (image.Size != default)
+ {
+ State = AsyncImageState.Loaded;
+
+ ImageTransition?.Start(PlaceholderPart, ImagePart, true, _tokenSource.Token);
+
+ RaiseEvent(new RoutedEventArgs(OpenedEvent));
+ }
+ }
+
+ private async Task LoadImageAsync(Uri? url, CancellationToken token)
+ {
+ if (await ProvideCachedResourceAsync(url, token) is { } bitmap)
+ {
+ return bitmap;
+ }
+#if NET6_0_OR_GREATER
+ using var client = new HttpClient();
+ var stream = await client.GetStreamAsync(url, token).ConfigureAwait(false);
+
+ await using var memoryStream = new MemoryStream();
+ await stream.CopyToAsync(memoryStream, token).ConfigureAwait(false);
+#elif NETSTANDARD2_0
+ using var client = new HttpClient();
+ var response = await client.GetAsync(url, token).ConfigureAwait(false);
+ var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+ using var memoryStream = new MemoryStream();
+ await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
+#endif
+
+ memoryStream.Position = 0;
+ return new Bitmap(memoryStream);
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == SourceProperty)
+ {
+ SetSource(Source);
+ }
+ }
+
+ protected virtual async Task ProvideCachedResourceAsync(Uri? imageUri, CancellationToken token)
+ {
+ if (IsCacheEnabled && imageUri != null)
+ {
+ return await ImageCache
+ .Instance.GetFromCacheAsync(imageUri, cancellationToken: token)
+ .ConfigureAwait(false);
+ }
+ return null;
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs
new file mode 100644
index 00000000..a4604082
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheBase.cs
@@ -0,0 +1,565 @@
+// Parts of this file was taken from Windows Community Toolkit CacheBase implementation
+// https://github.com/CommunityToolkit/WindowsCommunityToolkit/blob/main/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+internal abstract class CacheBase
+{
+ private class ConcurrentRequest
+ {
+ public Task? Task { get; set; }
+
+ public bool EnsureCachedCopy { get; set; }
+ }
+
+ private readonly SemaphoreSlim _cacheFolderSemaphore = new SemaphoreSlim(1);
+ private string? _baseFolder = null;
+ private string? _cacheFolderName = null;
+
+ private string? _cacheFolder = null;
+ private InMemoryStorage? _inMemoryFileStorage = null;
+
+ private ConcurrentDictionary _concurrentTasks =
+ new ConcurrentDictionary();
+
+ private HttpClient? _httpClient = null;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected CacheBase()
+ {
+ var options = CacheOptions.Default;
+ CacheDuration = options?.CacheDuration ?? TimeSpan.FromDays(1);
+ _baseFolder = options?.BaseCachePath ?? null;
+ _inMemoryFileStorage = new InMemoryStorage();
+ RetryCount = 1;
+ }
+
+ ///
+ /// Gets or sets the life duration of every cache entry.
+ ///
+ public TimeSpan CacheDuration { get; set; }
+
+ ///
+ /// Gets or sets the number of retries trying to ensure the file is cached.
+ ///
+ public uint RetryCount { get; set; }
+
+ ///
+ /// Gets or sets max in-memory item storage count
+ ///
+ public int MaxMemoryCacheCount
+ {
+ get { return _inMemoryFileStorage?.MaxItemCount ?? 0; }
+ set
+ {
+ if (_inMemoryFileStorage != null)
+ _inMemoryFileStorage.MaxItemCount = value;
+ }
+ }
+
+ ///
+ /// Gets instance of
+ ///
+ protected HttpClient HttpClient
+ {
+ get
+ {
+ if (_httpClient == null)
+ {
+ var messageHandler = new HttpClientHandler();
+
+ _httpClient = new HttpClient(messageHandler);
+ }
+
+ return _httpClient;
+ }
+ }
+
+ ///
+ /// Initializes FileCache and provides root folder and cache folder name
+ ///
+ /// Folder that is used as root for cache
+ /// Cache folder name
+ /// instance of
+ /// awaitable task
+ public virtual async Task InitializeAsync(
+ string? folder = null,
+ string? folderName = null,
+ HttpMessageHandler? httpMessageHandler = null
+ )
+ {
+ _baseFolder = folder;
+ _cacheFolderName = folderName;
+
+ _cacheFolder = await GetCacheFolderAsync().ConfigureAwait(false);
+
+ if (httpMessageHandler != null)
+ {
+ _httpClient = new HttpClient(httpMessageHandler);
+ }
+ }
+
+ ///
+ /// Clears all files in the cache
+ ///
+ /// awaitable task
+ public async Task ClearAsync()
+ {
+ var folder = await GetCacheFolderAsync().ConfigureAwait(false);
+ var files = Directory.EnumerateFiles(folder!);
+
+ await InternalClearAsync(files.Select(x => x as string)).ConfigureAwait(false);
+
+ _inMemoryFileStorage?.Clear();
+ }
+
+ ///
+ /// Clears file if it has expired
+ ///
+ /// timespan to compute whether file has expired or not
+ /// awaitable task
+ public Task ClearAsync(TimeSpan duration)
+ {
+ return RemoveExpiredAsync(duration);
+ }
+
+ ///
+ /// Removes cached files that have expired
+ ///
+ /// Optional timespan to compute whether file has expired or not. If no value is supplied, is used.
+ /// awaitable task
+ public async Task RemoveExpiredAsync(TimeSpan? duration = null)
+ {
+ TimeSpan expiryDuration = duration ?? CacheDuration;
+
+ var folder = await GetCacheFolderAsync().ConfigureAwait(false);
+ var files = Directory.EnumerateFiles(folder!);
+
+ var filesToDelete = new List();
+
+ foreach (var file in files)
+ {
+ if (file == null)
+ {
+ continue;
+ }
+
+ if (await IsFileOutOfDateAsync(file, expiryDuration, false).ConfigureAwait(false))
+ {
+ filesToDelete.Add(file);
+ }
+ }
+
+ await InternalClearAsync(filesToDelete).ConfigureAwait(false);
+
+ _inMemoryFileStorage?.Clear(expiryDuration);
+ }
+
+ ///
+ /// Removed items based on uri list passed
+ ///
+ /// Enumerable uri list
+ /// awaitable Task
+ public async Task RemoveAsync(IEnumerable uriForCachedItems)
+ {
+ if (uriForCachedItems == null || !uriForCachedItems.Any())
+ {
+ return;
+ }
+
+ var folder = await GetCacheFolderAsync().ConfigureAwait(false);
+ var files = Directory.EnumerateFiles(folder!);
+ var filesToDelete = new List();
+ var keys = new List();
+
+ Dictionary hashDictionary = new Dictionary();
+
+ foreach (var file in files)
+ {
+ hashDictionary.Add(Path.GetFileName(file), file);
+ }
+
+ foreach (var uri in uriForCachedItems)
+ {
+ string fileName = GetCacheFileName(uri);
+ if (hashDictionary.TryGetValue(fileName, out var file))
+ {
+ filesToDelete.Add(file);
+ keys.Add(fileName);
+ }
+ }
+
+ await InternalClearAsync(filesToDelete).ConfigureAwait(false);
+
+ _inMemoryFileStorage?.Remove(keys);
+ }
+
+ ///
+ /// Assures that item represented by Uri is cached.
+ ///
+ /// Uri of the item
+ /// Indicates whether or not exception should be thrown if item cannot be cached
+ /// Indicates if item should be loaded into the in-memory storage
+ /// instance of
+ /// Awaitable Task
+ public Task PreCacheAsync(
+ Uri uri,
+ bool throwOnError = false,
+ bool storeToMemoryCache = false,
+ CancellationToken cancellationToken = default(CancellationToken)
+ )
+ {
+ return GetItemAsync(uri, throwOnError, !storeToMemoryCache, cancellationToken);
+ }
+
+ ///
+ /// Retrieves item represented by Uri from the cache. If the item is not found in the cache, it will try to downloaded and saved before returning it to the caller.
+ ///
+ /// Uri of the item.
+ /// Indicates whether or not exception should be thrown if item cannot be found / downloaded.
+ /// instance of
+ /// an instance of Generic type
+ public Task GetFromCacheAsync(
+ Uri uri,
+ bool throwOnError = false,
+ CancellationToken cancellationToken = default(CancellationToken)
+ )
+ {
+ return GetItemAsync(uri, throwOnError, false, cancellationToken);
+ }
+
+ ///
+ /// Gets the string containing cached item for given Uri
+ ///
+ /// Uri of the item.
+ /// a string
+ public async Task GetFileFromCacheAsync(Uri uri)
+ {
+ var folder = await GetCacheFolderAsync().ConfigureAwait(false);
+
+ return Path.Combine(folder!, GetCacheFileName(uri));
+ }
+
+ ///
+ /// Retrieves item represented by Uri from the in-memory cache if it exists and is not out of date. If item is not found or is out of date, default instance of the generic type is returned.
+ ///
+ /// Uri of the item.
+ /// an instance of Generic type
+ public T? GetFromMemoryCache(Uri uri)
+ {
+ T? instance = default(T);
+
+ string fileName = GetCacheFileName(uri);
+
+ if (_inMemoryFileStorage?.MaxItemCount > 0)
+ {
+ var msi = _inMemoryFileStorage?.GetItem(fileName, CacheDuration);
+ if (msi != null)
+ {
+ instance = msi.Item;
+ }
+ }
+
+ return instance;
+ }
+
+ ///
+ /// Cache specific hooks to process items from HTTP response
+ ///
+ /// input stream
+ /// awaitable task
+ protected abstract Task ConvertFromAsync(Stream stream);
+
+ ///
+ /// Cache specific hooks to process items from HTTP response
+ ///
+ /// storage file
+ /// awaitable task
+ protected abstract Task ConvertFromAsync(string baseFile);
+
+ ///
+ /// Override-able method that checks whether file is valid or not.
+ ///
+ /// storage file
+ /// cache duration
+ /// option to mark uninitialized file as expired
+ /// bool indicate whether file has expired or not
+ protected virtual async Task IsFileOutOfDateAsync(
+ string file,
+ TimeSpan duration,
+ bool treatNullFileAsOutOfDate = true
+ )
+ {
+ if (file == null)
+ {
+ return treatNullFileAsOutOfDate;
+ }
+
+ var info = new FileInfo(file);
+
+ return info.Length == 0 || DateTime.Now.Subtract(info.LastWriteTime) > duration;
+ }
+
+ private static string GetCacheFileName(Uri uri)
+ {
+ return CreateHash64(uri.ToString()).ToString();
+ }
+
+ private static ulong CreateHash64(string str)
+ {
+ byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(str);
+
+ ulong value = (ulong)utf8.Length;
+ for (int n = 0; n < utf8.Length; n++)
+ {
+ value += (ulong)utf8[n] << ((n * 5) % 56);
+ }
+
+ return value;
+ }
+
+ private async Task GetItemAsync(
+ Uri uri,
+ bool throwOnError,
+ bool preCacheOnly,
+ CancellationToken cancellationToken
+ )
+ {
+ T? instance = default(T);
+
+ string fileName = GetCacheFileName(uri);
+ _concurrentTasks.TryGetValue(fileName, out var request);
+
+ // if similar request exists check if it was preCacheOnly and validate that current request isn't preCacheOnly
+ if (request != null && request.EnsureCachedCopy && !preCacheOnly)
+ {
+ if (request.Task != null)
+ await request.Task.ConfigureAwait(false);
+ request = null;
+ }
+
+ if (request == null)
+ {
+ request = new ConcurrentRequest()
+ {
+ Task = GetFromCacheOrDownloadAsync(uri, fileName, preCacheOnly, cancellationToken),
+ EnsureCachedCopy = preCacheOnly
+ };
+
+ _concurrentTasks[fileName] = request;
+ }
+
+ try
+ {
+ if (request.Task != null)
+ instance = await request.Task.ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine(ex.Message);
+ if (throwOnError)
+ {
+ throw;
+ }
+ }
+ finally
+ {
+ _concurrentTasks.TryRemove(fileName, out _);
+ }
+
+ return instance;
+ }
+
+ private async Task GetFromCacheOrDownloadAsync(
+ Uri uri,
+ string fileName,
+ bool preCacheOnly,
+ CancellationToken cancellationToken
+ )
+ {
+ T? instance = default(T);
+
+ if (_inMemoryFileStorage?.MaxItemCount > 0)
+ {
+ var msi = _inMemoryFileStorage?.GetItem(fileName, CacheDuration);
+ if (msi != null)
+ {
+ instance = msi.Item;
+ }
+ }
+
+ if (instance != null)
+ {
+ return instance;
+ }
+
+ var folder = await GetCacheFolderAsync().ConfigureAwait(false);
+ var baseFile = Path.Combine(folder!, fileName);
+
+ bool downloadDataFile =
+ !File.Exists(baseFile)
+ || await IsFileOutOfDateAsync(baseFile, CacheDuration).ConfigureAwait(false);
+
+ if (!File.Exists(baseFile))
+ {
+ File.Create(baseFile).Dispose();
+ }
+
+ if (downloadDataFile)
+ {
+ uint retries = 0;
+ try
+ {
+ while (retries < RetryCount)
+ {
+ try
+ {
+ instance = await DownloadFileAsync(uri, baseFile, preCacheOnly, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (instance != null)
+ {
+ break;
+ }
+ }
+ catch (FileNotFoundException) { }
+
+ retries++;
+ }
+ }
+ catch (Exception ex)
+ {
+ File.Delete(baseFile);
+ throw; // re-throwing the exception changes the stack trace. just throw
+ }
+ }
+
+ if (EqualityComparer.Default.Equals(instance, default(T)) && !preCacheOnly)
+ {
+ instance = await ConvertFromAsync(baseFile).ConfigureAwait(false);
+
+ if (_inMemoryFileStorage?.MaxItemCount > 0)
+ {
+ var properties = new FileInfo(baseFile);
+
+ var msi = new InMemoryStorageItem(fileName, properties.LastWriteTime, instance);
+ _inMemoryFileStorage?.SetItem(msi);
+ }
+ }
+ return instance;
+ }
+
+ private async Task DownloadFileAsync(
+ Uri uri,
+ string baseFile,
+ bool preCacheOnly,
+ CancellationToken cancellationToken
+ )
+ {
+ T? instance = default(T);
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ using (var stream = await HttpClient.GetStreamAsync(uri))
+ {
+ stream.CopyTo(ms);
+ ms.Flush();
+
+ ms.Position = 0;
+
+ using (var fs = File.Open(baseFile, FileMode.OpenOrCreate, FileAccess.Write))
+ {
+ ms.CopyTo(fs);
+
+ fs.Flush();
+
+ ms.Position = 0;
+ }
+ }
+
+ // if its pre-cache we aren't looking to load items in memory
+ if (!preCacheOnly)
+ {
+ instance = await ConvertFromAsync(ms).ConfigureAwait(false);
+ }
+ }
+
+ return instance;
+ }
+
+ private async Task InternalClearAsync(IEnumerable files)
+ {
+ foreach (var file in files)
+ {
+ try
+ {
+ File.Delete(file!);
+ }
+ catch
+ {
+ // Just ignore errors for now}
+ }
+ }
+ }
+
+ ///
+ /// Initializes with default values if user has not initialized explicitly
+ ///
+ /// awaitable task
+ private async Task ForceInitialiseAsync()
+ {
+ if (_cacheFolder != null)
+ {
+ return;
+ }
+
+ await _cacheFolderSemaphore.WaitAsync().ConfigureAwait(false);
+
+ _inMemoryFileStorage = new InMemoryStorage();
+
+ if (_baseFolder == null)
+ {
+ _baseFolder = Path.GetTempPath();
+ }
+
+ if (string.IsNullOrWhiteSpace(_cacheFolderName))
+ {
+ _cacheFolderName = GetType().Name;
+ }
+
+ try
+ {
+ _cacheFolder = Path.Combine(_baseFolder, _cacheFolderName);
+ Directory.CreateDirectory(_cacheFolder);
+ }
+ finally
+ {
+ _cacheFolderSemaphore.Release();
+ }
+ }
+
+ private async Task GetCacheFolderAsync()
+ {
+ if (_cacheFolder == null)
+ {
+ await ForceInitialiseAsync().ConfigureAwait(false);
+ }
+
+ return _cacheFolder;
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs
new file mode 100644
index 00000000..a07ca33c
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/CacheOptions.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+public class CacheOptions
+{
+ private static CacheOptions? _cacheOptions;
+
+ public static CacheOptions Default => _cacheOptions ??= new CacheOptions();
+
+ public static void SetDefault(CacheOptions defaultCacheOptions)
+ {
+ _cacheOptions = defaultCacheOptions;
+ }
+
+ public string? BaseCachePath { get; set; }
+ public TimeSpan? CacheDuration { get; set; }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/FileCache.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/FileCache.cs
new file mode 100644
index 00000000..a273ca0b
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/FileCache.cs
@@ -0,0 +1,36 @@
+using System.IO;
+using System.Threading.Tasks;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+///
+/// Provides methods and tools to cache files in a folder
+///
+internal class FileCache : CacheBase
+{
+ ///
+ /// Private singleton field.
+ ///
+ private static FileCache? _instance;
+
+ ///
+ /// Gets public singleton property.
+ ///
+ public static FileCache Instance => _instance ?? (_instance = new FileCache());
+
+ protected override Task ConvertFromAsync(Stream stream)
+ {
+ // nothing to do in this instance;
+ return Task.FromResult("");
+ }
+
+ ///
+ /// Returns a cached path
+ ///
+ /// storage file
+ /// awaitable task
+ protected override Task ConvertFromAsync(string baseFile)
+ {
+ return Task.FromResult(baseFile);
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs
new file mode 100644
index 00000000..5582b071
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/ImageCache.cs
@@ -0,0 +1,76 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Media.Imaging;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+///
+/// Provides methods and tools to cache images in a folder
+///
+internal class ImageCache : CacheBase
+{
+ ///
+ /// Private singleton field.
+ ///
+ [ThreadStatic]
+ private static ImageCache? _instance;
+
+ ///
+ /// Gets public singleton property.
+ ///
+ public static ImageCache Instance => _instance ?? (_instance = new ImageCache());
+
+ ///
+ /// Creates a bitmap from a stream
+ ///
+ /// input stream
+ /// awaitable task
+ protected override async Task ConvertFromAsync(Stream stream)
+ {
+ if (stream.Length == 0)
+ {
+ throw new FileNotFoundException();
+ }
+
+ return new Bitmap(stream);
+ }
+
+ ///
+ /// Creates a bitmap from a cached file
+ ///
+ /// file
+ /// awaitable task
+ protected override async Task ConvertFromAsync(string baseFile)
+ {
+ using (var stream = File.OpenRead(baseFile))
+ {
+ return await ConvertFromAsync(stream).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ /// Checks whether file is valid or not.
+ ///
+ /// file
+ /// cache duration
+ /// option to mark uninitialized file as expired
+ /// bool indicate whether file has expired or not
+ protected override async Task IsFileOutOfDateAsync(
+ string file,
+ TimeSpan duration,
+ bool treatNullFileAsOutOfDate = true
+ )
+ {
+ if (file == null)
+ {
+ return treatNullFileAsOutOfDate;
+ }
+
+ var fileInfo = new FileInfo(file);
+
+ return fileInfo.Length == 0
+ || DateTime.Now.Subtract(File.GetLastAccessTime(file)) > duration
+ || DateTime.Now.Subtract(File.GetLastWriteTime(file)) > duration;
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs
new file mode 100644
index 00000000..5643e679
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorage.cs
@@ -0,0 +1,156 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Labs.Controls.Cache;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+///
+/// Generic in-memory storage of items
+///
+/// T defines the type of item stored
+public class InMemoryStorage
+{
+ private int _maxItemCount;
+ private ConcurrentDictionary> _inMemoryStorage =
+ new ConcurrentDictionary>();
+ private object _settingMaxItemCountLocker = new object();
+
+ ///
+ /// Gets or sets the maximum count of Items that can be stored in this InMemoryStorage instance.
+ ///
+ public int MaxItemCount
+ {
+ get { return _maxItemCount; }
+ set
+ {
+ if (_maxItemCount == value)
+ {
+ return;
+ }
+
+ _maxItemCount = value;
+
+ lock (_settingMaxItemCountLocker)
+ {
+ EnsureStorageBounds(value);
+ }
+ }
+ }
+
+ ///
+ /// Clears all items stored in memory
+ ///
+ public void Clear()
+ {
+ _inMemoryStorage.Clear();
+ }
+
+ ///
+ /// Clears items stored in memory based on duration passed
+ ///
+ /// TimeSpan to identify expired items
+ public void Clear(TimeSpan duration)
+ {
+ var expirationDate = DateTime.Now.Subtract(duration);
+
+ var itemsToRemove = _inMemoryStorage
+ .Where(kvp => kvp.Value.LastUpdated <= expirationDate)
+ .Select(kvp => kvp.Key);
+
+ if (itemsToRemove.Any())
+ {
+ Remove(itemsToRemove);
+ }
+ }
+
+ ///
+ /// Remove items based on provided keys
+ ///
+ /// identified of the in-memory storage item
+ public void Remove(IEnumerable keys)
+ {
+ foreach (var key in keys)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ {
+ continue;
+ }
+
+ _inMemoryStorage.TryRemove(key, out _);
+ }
+ }
+
+ ///
+ /// Add new item to in-memory storage
+ ///
+ /// item to be stored
+ public void SetItem(InMemoryStorageItem item)
+ {
+ if (MaxItemCount == 0)
+ {
+ return;
+ }
+
+ _inMemoryStorage[item.Id] = item;
+
+ // ensure max limit is maintained. trim older entries first
+ if (_inMemoryStorage.Count > MaxItemCount)
+ {
+ var itemsToRemove = _inMemoryStorage
+ .OrderBy(kvp => kvp.Value.Created)
+ .Take(_inMemoryStorage.Count - MaxItemCount)
+ .Select(kvp => kvp.Key);
+ Remove(itemsToRemove);
+ }
+ }
+
+ ///
+ /// Get item from in-memory storage as long as it has not ex
+ ///
+ /// id of the in-memory storage item
+ /// timespan denoting expiration
+ /// Valid item if not out of date or return null if out of date or item does not exist
+ public InMemoryStorageItem? GetItem(string id, TimeSpan duration)
+ {
+ if (!_inMemoryStorage.TryGetValue(id, out var tempItem))
+ {
+ return null;
+ }
+
+ var expirationDate = DateTime.Now.Subtract(duration);
+
+ if (tempItem.LastUpdated > expirationDate)
+ {
+ return tempItem;
+ }
+
+ _inMemoryStorage.TryRemove(id, out _);
+
+ return null;
+ }
+
+ private void EnsureStorageBounds(int maxCount)
+ {
+ if (_inMemoryStorage.Count == 0)
+ {
+ return;
+ }
+
+ if (maxCount == 0)
+ {
+ _inMemoryStorage.Clear();
+ return;
+ }
+
+ if (_inMemoryStorage.Count > maxCount)
+ {
+ Remove(_inMemoryStorage.Keys.Take(_inMemoryStorage.Count - maxCount));
+ }
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorageItem.cs b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorageItem.cs
new file mode 100644
index 00000000..4bad770d
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Cache/InMemoryStorageItem.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace StabilityMatrix.Avalonia.Controls.VendorLabs.Cache;
+
+///
+/// Generic InMemoryStorageItem holds items for InMemoryStorage.
+///
+/// Type is set by consuming cache
+public class InMemoryStorageItem
+{
+ ///
+ /// Gets the item identifier
+ ///
+ public string Id { get; private set; }
+
+ ///
+ /// Gets the item created timestamp.
+ ///
+ public DateTime Created { get; private set; }
+
+ ///
+ /// Gets the item last updated timestamp.
+ ///
+ public DateTime LastUpdated { get; private set; }
+
+ ///
+ /// Gets the item being stored.
+ ///
+ public T Item { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Constructor for InMemoryStorageItem
+ ///
+ /// uniquely identifies the item
+ /// last updated timestamp
+ /// the item being stored
+ public InMemoryStorageItem(string id, DateTime lastUpdated, T item)
+ {
+ Id = id;
+ LastUpdated = lastUpdated;
+ Item = item;
+ Created = DateTime.Now;
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/LICENSE b/StabilityMatrix.Avalonia/Controls/VendorLabs/LICENSE
new file mode 100644
index 00000000..8a6071d2
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 AvaloniaUI
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj.DotSettings b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj.DotSettings
index ef254925..524abe98 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj.DotSettings
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj.DotSettings
@@ -2,4 +2,5 @@
Yes
Pessimistic
UI
- True
+ True
+ True
From 224b008cd9ba2d6238dd29c223cc860d9daf6a4d Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 10 Apr 2024 23:24:05 -0400
Subject: [PATCH 128/130] Switch usages to BetterAsyncImage
---
.../Controls/Inference/ImageFolderCard.axaml | 3 ++-
.../Controls/Inference/ImageGalleryCard.axaml | 3 ++-
.../SelectableImageCard/SelectableImageButton.axaml | 5 +++--
.../Styles/ControlThemes/BetterComboBoxStyles.axaml | 11 ++++++-----
StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml | 5 +++--
.../Views/CivitAiBrowserPage.axaml | 12 ++++++------
.../Views/Dialogs/OpenArtWorkflowDialog.axaml | 3 ++-
.../Views/InstalledWorkflowsPage.axaml | 5 +++--
.../Views/OpenArtBrowserPage.axaml | 7 ++++---
.../Views/PackageManagerPage.axaml | 3 ++-
10 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
index 67b75973..b34b8b42 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
+++ b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml
@@ -10,6 +10,7 @@
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:scroll="clr-namespace:StabilityMatrix.Avalonia.Controls.Scroll"
xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
+ xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs"
x:DataType="vmInference:ImageFolderCardViewModel">
@@ -196,7 +197,7 @@
-
@@ -116,7 +117,7 @@
-
+ xmlns:controls1="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
+ xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs">
@@ -39,7 +40,7 @@
CornerRadius="12"
Command="{TemplateBinding Command}"
CommandParameter="{TemplateBinding CommandParameter}">
-
+ xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
+ xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs">
@@ -43,7 +44,7 @@
ColumnSpacing="6"
RowSpacing="0">
-
-
-
-
+
-
-
- -->
-
-
+
-
-
+ Source="{Binding CivitModel.Creator.Image}"/>
-
-
-
@@ -106,7 +107,7 @@
Command="{StaticResource OpenWorkflowCommand}"
CommandParameter="{Binding }">
-
-
-
+
-
Date: Wed, 10 Apr 2024 23:36:32 -0400
Subject: [PATCH 129/130] Add control theme for BetterAsyncImage
---
StabilityMatrix.Avalonia/App.axaml | 1 +
.../VendorLabs/Themes/BetterAsyncImage.axaml | 48 +++++++++++++++++++
2 files changed, 49 insertions(+)
create mode 100644 StabilityMatrix.Avalonia/Controls/VendorLabs/Themes/BetterAsyncImage.axaml
diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml
index 2ca1c5c3..63547818 100644
--- a/StabilityMatrix.Avalonia/App.axaml
+++ b/StabilityMatrix.Avalonia/App.axaml
@@ -29,6 +29,7 @@
+
diff --git a/StabilityMatrix.Avalonia/Controls/VendorLabs/Themes/BetterAsyncImage.axaml b/StabilityMatrix.Avalonia/Controls/VendorLabs/Themes/BetterAsyncImage.axaml
new file mode 100644
index 00000000..2b6f1bd0
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/VendorLabs/Themes/BetterAsyncImage.axaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 2d961be0f396287ebe65038af3b8e38e703f322c Mon Sep 17 00:00:00 2001
From: Ionite
Date: Wed, 10 Apr 2024 23:36:52 -0400
Subject: [PATCH 130/130] Remove not needed AsyncImage fix
---
StabilityMatrix.Avalonia/App.axaml | 3 ---
1 file changed, 3 deletions(-)
diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml
index 63547818..d6db2ffd 100644
--- a/StabilityMatrix.Avalonia/App.axaml
+++ b/StabilityMatrix.Avalonia/App.axaml
@@ -88,8 +88,5 @@
-