diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2287c1e8b..0a2669171 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,25 @@ 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.12.4
+### Added
+- Added new package - [CogVideo](https://github.com/THUDM/CogVideo) - many thanks to @NullDev for the contribution!
+- Added more formatting options for Inference output filenames - thanks to @yansigit!
+### Changed
+- Model browser base model types are now loaded dynamically from CivitAI, reducing the need for updates to add new types
+### Fixed
+- Fixed crash when clicking "Remind me Later" on the update dialog
+- Fixed some cases of crashing when GitHub API rate limits are exceeded
+- Fixed Git missing from env vars when running SwarmUI
+- Fixed missing package thumbnails due to moved or inaccessible urls
+- Fixed an issue with updating FluxGym in certain cases - thanks to @NullDev!
+- Fixed a typo in the Japanese translation - thanks to @mattyatea!
+### Supporters
+#### Visionaries
+- A huge thank you to our dedicated Visionary-tier Patreon supporter, **Waterclouds**! We’re thrilled to have your ongoing support!
+#### Pioneers
+- Shoutout to our great Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, **Szir777**, and our newest Pioneer, **Tigon**!. Your continued support is greatly appreciated!
+
## v2.12.3
### Added
- Added new package - [SimpleSDXL](https://github.com/metercai/SimpleSDXL) - many thanks to @NullDev for the contribution!
diff --git a/Directory.Build.props b/Directory.Build.props
index ebef34b63..3b07e6b68 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,4 +2,10 @@
11.1.4
+
+
+
+ $(NoWarn);CsWinRT1028
+
diff --git a/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs
index d04e2f741..90c860db2 100644
--- a/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs
+++ b/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
@@ -29,9 +31,7 @@ public class TextEditorToolTipBehavior : Behavior
private ToolTip? toolTip;
public static readonly StyledProperty TokenizerProviderProperty =
- AvaloniaProperty.Register(
- "TokenizerProvider"
- );
+ AvaloniaProperty.Register("TokenizerProvider");
public ITokenizerProvider? TokenizerProvider
{
@@ -137,6 +137,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e)
toolTip
.GetPropertyChangedObservable(ToolTip.IsOpenProperty)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(c =>
{
if (c.NewValue as bool? != true)
@@ -159,10 +160,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e)
private ToolTipData? GetCaretToolTipData(TextViewPosition position)
{
var logicalPosition = position.Location;
- var pointerOffset = textEditor.Document.GetOffset(
- logicalPosition.Line,
- logicalPosition.Column
- );
+ var pointerOffset = textEditor.Document.GetOffset(logicalPosition.Line, logicalPosition.Column);
var line = textEditor.Document.GetLineByOffset(pointerOffset);
var lineText = textEditor.Document.GetText(line.Offset, line.Length);
@@ -227,10 +225,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e)
if (result.Tokens.ElementAtOrDefault(currentTokenIndex + tokenOffset) is { } token)
{
// Check supported scopes
- if (
- token.Scopes.Where(s => s.Contains("invalid")).ToArray() is
- { Length: > 0 } results
- )
+ if (token.Scopes.Where(s => s.Contains("invalid")).ToArray() is { Length: > 0 } results)
{
// Special cases
if (results.Contains("invalid.illegal.mismatched.parenthesis.closing.prompt"))
diff --git a/StabilityMatrix.Avalonia/Collections/SearchCollection.cs b/StabilityMatrix.Avalonia/Collections/SearchCollection.cs
index 6a268ec2f..c2b4b9531 100644
--- a/StabilityMatrix.Avalonia/Collections/SearchCollection.cs
+++ b/StabilityMatrix.Avalonia/Collections/SearchCollection.cs
@@ -3,6 +3,7 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
+using System.Threading;
using DynamicData;
using DynamicData.Binding;
using JetBrains.Annotations;
@@ -72,6 +73,7 @@ public SearchCollection(
.Filter(dynamicPredicate)
.Sort(SortComparer)
.Bind(FilteredItems)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
}
@@ -114,6 +116,7 @@ public SearchCollection(
.Sort(SearchItemSortComparer, SortOptimisations.ComparesImmutableValuesOnly)
.Transform(searchItem => searchItem.Item)
.Bind(FilteredItems)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe()
);
}
diff --git a/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs
index 2c54ac385..b6bbbf370 100644
--- a/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs
+++ b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs
@@ -2,6 +2,7 @@
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
+using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
@@ -48,7 +49,9 @@ public BetterComboBox()
.Select(_ => currentInput);
// Subscribe to the observable to filter the ComboBox items
- subscription = inputObservable.Subscribe(OnInputReceived, _ => ResetPopupText());
+ subscription = inputObservable
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe(OnInputReceived, _ => ResetPopupText());
// Initialize the popup
inputPopup = new Popup
diff --git a/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs b/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs
new file mode 100644
index 000000000..024bef8fa
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs
@@ -0,0 +1,16 @@
+using Markdown.Avalonia;
+using StabilityMatrix.Avalonia.Styles.Markdown;
+
+namespace StabilityMatrix.Avalonia.Controls;
+
+///
+/// Fix MarkdownScrollViewer IBrush errors and not working with Avalonia 11.2.0
+///
+public class BetterMarkdownScrollViewer : MarkdownScrollViewer
+{
+ public BetterMarkdownScrollViewer()
+ {
+ MarkdownStyleName = "Empty";
+ MarkdownStyle = new MarkdownStyleFluentAvalonia();
+ }
+}
diff --git a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs
index d7890c9ed..c743b028e 100644
--- a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs
+++ b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs
@@ -1,4 +1,6 @@
using System;
+using System.Reactive.Linq;
+using System.Threading;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using DynamicData.Binding;
@@ -24,6 +26,7 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
imageControl
.WhenPropertyChanged(x => x.CurrentImage)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(propertyValue =>
{
if (propertyValue.Value is { } image)
diff --git a/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs b/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs
index 57012561b..85cd915e9 100644
--- a/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs
+++ b/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs
@@ -3,6 +3,8 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
@@ -108,6 +110,7 @@ protected override void OnDataContextChanged(EventArgs e)
viewModelSubscription?.Dispose();
viewModelSubscription = viewModel
.WhenPropertyChanged(vm => vm.CanvasSize)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(change =>
{
if (MainCanvas is not null && !change.Value.IsEmpty)
diff --git a/StabilityMatrix.Avalonia/DialogHelper.cs b/StabilityMatrix.Avalonia/DialogHelper.cs
index 0b98ddf13..f4c79278c 100644
--- a/StabilityMatrix.Avalonia/DialogHelper.cs
+++ b/StabilityMatrix.Avalonia/DialogHelper.cs
@@ -81,7 +81,11 @@ public static BetterContentDialog CreateTextEntryDialog(
IReadOnlyList textFields
)
{
- return CreateTextEntryDialog(title, new MarkdownScrollViewer { Markdown = description }, textFields);
+ return CreateTextEntryDialog(
+ title,
+ new BetterMarkdownScrollViewer { Markdown = description },
+ textFields
+ );
}
///
@@ -94,7 +98,7 @@ public static BetterContentDialog CreateTextEntryDialog(
IReadOnlyList textFields
)
{
- var markdown = new MarkdownScrollViewer { Markdown = description };
+ var markdown = new BetterMarkdownScrollViewer { Markdown = description };
var image = new BetterAdvancedImage((Uri?)null)
{
Source = imageSource,
@@ -235,7 +239,7 @@ public static BetterContentDialog CreateMarkdownDialog(
{
Dispatcher.UIThread.VerifyAccess();
- var viewer = new MarkdownScrollViewer { Markdown = markdown };
+ var viewer = new BetterMarkdownScrollViewer { Markdown = markdown };
// Apply syntax highlighting to code blocks if preset is provided
if (editorPreset != default)
diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
index 21aa70245..352e8c983 100644
--- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
+++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
@@ -3,6 +3,7 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
@@ -164,6 +165,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(Models)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
controlNetModelsSource
@@ -176,6 +178,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(ControlNetModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
loraModelsSource
@@ -185,6 +188,7 @@ ICompletionProvider completionProvider
LoraModels,
SortExpressionComparer.Ascending(f => f.Type).ThenByAscending(f => f.SortKey)
)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
promptExpansionModelsSource
@@ -197,6 +201,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(PromptExpansionModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
ultralyticsModelsSource
@@ -209,6 +214,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(UltralyticsModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
samModelsSource
@@ -221,6 +227,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(SamModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
unetModelsSource
@@ -232,6 +239,7 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(UnetModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
clipModelsSource
@@ -244,13 +252,24 @@ ICompletionProvider completionProvider
)
.DeferUntilLoaded()
.Bind(ClipModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
vaeModelsDefaults.AddOrUpdate(HybridModelFile.Default);
- vaeModelsDefaults.Connect().Or(vaeModelsSource.Connect()).Bind(VaeModels).Subscribe();
+ vaeModelsDefaults
+ .Connect()
+ .Or(vaeModelsSource.Connect())
+ .Bind(VaeModels)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
- samplersSource.Connect().DeferUntilLoaded().Bind(Samplers).Subscribe();
+ samplersSource
+ .Connect()
+ .DeferUntilLoaded()
+ .Bind(Samplers)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
latentUpscalersSource
.Connect()
@@ -258,11 +277,22 @@ ICompletionProvider completionProvider
.Or(downloadableUpscalersSource.Connect())
.Sort(SortExpressionComparer.Ascending(f => f.Type).ThenByAscending(f => f.Name))
.Bind(Upscalers)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
- schedulersSource.Connect().DeferUntilLoaded().Bind(Schedulers).Subscribe();
+ schedulersSource
+ .Connect()
+ .DeferUntilLoaded()
+ .Bind(Schedulers)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
- preprocessorsSource.Connect().DeferUntilLoaded().Bind(Preprocessors).Subscribe();
+ preprocessorsSource
+ .Connect()
+ .DeferUntilLoaded()
+ .Bind(Preprocessors)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
settingsManager.RegisterOnLibraryDirSet(_ =>
{
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index 3a8b64f4d..d99372018 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -113,7 +113,7 @@
-
+
diff --git a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml
new file mode 100644
index 000000000..cf02c7d3e
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs
new file mode 100644
index 000000000..e8ece0398
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs
@@ -0,0 +1,11 @@
+using Avalonia.Markup.Xaml;
+
+namespace StabilityMatrix.Avalonia.Styles.Markdown;
+
+public partial class MarkdownStyleFluentAvalonia : global::Avalonia.Styling.Styles
+{
+ public MarkdownStyleFluentAvalonia()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
index e08626b6b..d0126e7a7 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
@@ -5,6 +5,8 @@
using System.Linq;
using System.Net.Http;
using System.Reactive.Linq;
+using System.Text.Json.Nodes;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
@@ -42,6 +44,7 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
private readonly ISettingsManager settingsManager;
private readonly ILiteDbContext liteDbContext;
private readonly INotificationService notificationService;
+ private bool dontSearch = false;
private readonly SourceCache, int> modelCache = new(static ov => ov.Value.Id);
@@ -80,7 +83,7 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
private string noResultsText = string.Empty;
[ObservableProperty]
- private string selectedBaseModelType = "All";
+ private string selectedBaseModelType;
[ObservableProperty]
private bool showSantaHats = true;
@@ -98,6 +101,11 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
[NotifyPropertyChangedFor(nameof(StatsResizeFactor))]
private double resizeFactor;
+ private readonly SourceCache baseModelCache = new(static s => s);
+
+ [ObservableProperty]
+ private IObservableCollection allBaseModels = new ObservableCollectionExtended();
+
public double StatsResizeFactor => Math.Clamp(ResizeFactor, 0.75d, 1.25d);
public IEnumerable AllCivitPeriods =>
@@ -111,9 +119,6 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
.Where(t => t == CivitModelType.All || t.ConvertTo() > 0)
.OrderBy(t => t.ToString());
- public IEnumerable BaseModelOptions =>
- Enum.GetValues().Select(t => t.GetStringValue());
-
public CivitAiBrowserViewModel(
ICivitApi civitApi,
IDownloadService downloadService,
@@ -142,6 +147,7 @@ or nameof(HideEarlyAccessModels)
.Throttle(TimeSpan.FromMilliseconds(50))
.Select(_ => (Func)FilterModelCardsPredicate)
.StartWith(FilterModelCardsPredicate)
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
var sortPredicate = SortExpressionComparer.Ascending(
@@ -163,8 +169,18 @@ or nameof(HideEarlyAccessModels)
.DisposeMany()
.Filter(filterPredicate)
.SortAndBind(ModelCards, sortPredicate)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
+ baseModelCache
+ .Connect()
+ .DeferUntilLoaded()
+ .SortAndBind(AllBaseModels)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
+
+ baseModelCache.AddOrUpdate(Enum.GetValues().Select(t => t.GetStringValue()));
+
settingsManager.RelayPropertyFor(
this,
model => model.ShowNsfw,
@@ -230,10 +246,38 @@ public override void OnLoaded()
SelectedModelType = searchOptions?.SelectedModelType ?? CivitModelType.Checkpoint;
SelectedBaseModelType = searchOptions?.SelectedBaseModelType ?? "All";
+ base.OnLoaded();
+ }
+
+ protected override async Task OnInitialLoadedAsync()
+ {
+ await base.OnInitialLoadedAsync();
if (settingsManager.Settings.AutoLoadCivitModels)
{
- SearchModelsCommand.ExecuteAsync(false);
+ await SearchModelsCommand.ExecuteAsync(false);
+ }
+
+ var baseModels = await GetBaseModelList();
+ if (baseModels.Count == 0)
+ {
+ LoadSelectedBaseModelType();
+ return;
}
+
+ dontSearch = true;
+ baseModelCache.AddOrUpdate(baseModels);
+ dontSearch = false;
+
+ LoadSelectedBaseModelType();
+ }
+
+ private void LoadSelectedBaseModelType()
+ {
+ var searchOptions = settingsManager.Settings.ModelSearchOptions;
+ dontSearch = true;
+ SelectedBaseModelType = "All";
+ SelectedBaseModelType = searchOptions is null ? "All" : searchOptions.SelectedBaseModelType;
+ dontSearch = false;
}
///
@@ -340,7 +384,22 @@ private async Task CivitModelQuery(CivitModelsRequest request, bool isInfiniteSc
}
);
- UpdateModelCards(models, isInfiniteScroll);
+ if (cacheNew)
+ {
+ var doesBaseModelTypeMatch =
+ SelectedBaseModelType == "All"
+ ? string.IsNullOrWhiteSpace(request.BaseModel)
+ : SelectedBaseModelType == request.BaseModel;
+ var doesModelTypeMatch =
+ SelectedModelType == CivitModelType.All
+ ? request.Types == null || request.Types.Length == 0
+ : SelectedModelType == request.Types?.FirstOrDefault();
+
+ if (doesBaseModelTypeMatch && doesModelTypeMatch)
+ {
+ UpdateModelCards(models, isInfiniteScroll);
+ }
+ }
NextPageCursor = modelsResponse?.Metadata?.NextCursor;
}
@@ -615,6 +674,9 @@ partial void OnSelectedModelTypeChanged(CivitModelType value)
partial void OnSelectedBaseModelTypeChanged(string value)
{
+ if (dontSearch)
+ return;
+
TrySearchAgain().SafeFireAndForget();
settingsManager.Transaction(
s =>
@@ -632,6 +694,7 @@ private async Task TrySearchAgain(bool shouldUpdatePageNumber = true)
{
if (!HasSearched)
return;
+
modelCache.Clear();
if (shouldUpdatePageNumber)
@@ -649,5 +712,35 @@ private void UpdateResultsText()
NoResultsText = "No results found";
}
+ [Localizable(false)]
+ private async Task> GetBaseModelList()
+ {
+ try
+ {
+ var baseModelsResponse = await civitApi.GetBaseModelList();
+ var jsonContent = await baseModelsResponse.Content.ReadAsStringAsync();
+ var baseModels = JsonNode.Parse(jsonContent);
+
+ var jArray =
+ baseModels?["error"]?["issues"]?[0]?["unionErrors"]?[0]?["issues"]?[0]?["options"]
+ as JsonArray;
+ var civitBaseModels = jArray?.GetValues().ToList() ?? [];
+
+ civitBaseModels.Insert(0, CivitBaseModelType.All.ToString());
+
+ var filteredResults = civitBaseModels
+ .Where(s => s.Equals("odor", StringComparison.OrdinalIgnoreCase) == false)
+ .OrderBy(s => s)
+ .ToList();
+
+ return filteredResults;
+ }
+ catch (Exception e)
+ {
+ Logger.Error(e, "Failed to get base model list");
+ return [];
+ }
+ }
+
public override string Header => Resources.Label_CivitAi;
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs
index 3ab3c6b44..58c0e86eb 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs
@@ -6,6 +6,7 @@
using System.Reactive.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
@@ -86,6 +87,7 @@ INotificationService notificationService
.Bind(Categories)
.WhenAnyPropertyChanged()
.Throttle(TimeSpan.FromMilliseconds(50))
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(_ => NumSelected = Categories.Sum(c => c.NumSelected));
progressTimer.Tick += (_, _) =>
diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
index f9ce925a7..1083f9a5c 100644
--- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
@@ -196,6 +197,7 @@ protected override void OnInitialLoaded()
)
)
)
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
var filterPredicate = Observable
@@ -209,6 +211,7 @@ or nameof(SelectedBaseModels)
)
.Throttle(TimeSpan.FromMilliseconds(50))
.Select(_ => (Func)FilterModels)
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
var comparerObservable = Observable
@@ -282,6 +285,7 @@ or nameof(SortConnectedModelsFirst)
return comparer;
})
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
ModelsCache
@@ -304,6 +308,7 @@ or nameof(SortConnectedModelsFirst)
.SortAndBind(Models, comparerObservable)
.WhenPropertyChanged(p => p.IsSelected)
.Throttle(TimeSpan.FromMilliseconds(50))
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(_ =>
{
NumItemsSelected = Models.Count(o => o.IsSelected);
@@ -315,6 +320,7 @@ or nameof(SortConnectedModelsFirst)
.Throttle(TimeSpan.FromMilliseconds(50))
.Select(_ => (Func)FilterCategories)
.StartWith(FilterCategories)
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
categoriesCache
@@ -327,6 +333,7 @@ or nameof(SortConnectedModelsFirst)
.Descending(x => x.Name == "All Models")
.ThenByAscending(x => x.Name)
)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
settingsManager.RelayPropertyFor(
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
index f390b3fd7..f8da3be6a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Threading;
@@ -70,6 +71,7 @@ INotificationService notificationService
var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages)
.Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages))
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
AllPackagesCache
@@ -83,6 +85,7 @@ INotificationService notificationService
.Ascending(p => p.InstallerSortOrder)
.ThenByAscending(p => p.DisplayName)
)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
AllPackagesCache.AddOrUpdate(packageFactory.GetAllAvailablePackages());
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
index b91336c86..97ada3ec4 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs
@@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -73,6 +75,7 @@ IModelImportService modelImportService
.DeferUntilLoaded()
.Filter(f => f.ModelVersion.BaseModel == "SD 1.5")
.Bind(Sd15Models)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
CivitModels
@@ -80,6 +83,7 @@ IModelImportService modelImportService
.DeferUntilLoaded()
.Filter(f => f.ModelVersion.BaseModel == "SDXL 1.0" || f.ModelVersion.BaseModel == "Pony")
.Bind(SdxlModels)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs
index 755153f70..7a46dc116 100644
--- a/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using DynamicData.Binding;
@@ -35,6 +37,7 @@ public CategoryViewModel(IEnumerable items, string modelsDir)
.Transform(i => new HuggingfaceItemViewModel { Item = i, ModelsDir = modelsDir })
.Bind(Items)
.WhenPropertyChanged(p => p.IsSelected)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(_ => NumSelected = Items.Count(i => i.IsSelected));
ItemsCache.EditDiff(items, (a, b) => a.RepositoryPath == b.RepositoryPath);
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
index ae75414fb..41eaa811c 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs
@@ -1,5 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
+using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -75,6 +77,7 @@ ServiceManager vmFactory
// Update our width and height when the image changes
SelectImageCardViewModel
.WhenPropertyChanged(card => card.CurrentBitmapSize)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(propertyValue =>
{
if (!propertyValue.Value.IsEmpty)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs
index d92bed140..84dc2fc51 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using AsyncImageLoader;
@@ -76,6 +77,7 @@ ServiceManager vmFactory
var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery)
.Throttle(TimeSpan.FromMilliseconds(50))!
.Select(property => searcher.GetPredicate(property.Value))
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
imageIndexService
@@ -84,6 +86,7 @@ ServiceManager vmFactory
.Filter(searchPredicate)
.SortBy(file => file.LastModifiedAt, SortDirection.Descending)
.Bind(LocalImages)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
AddDisposable(
@@ -191,6 +194,7 @@ private async Task OnImageClick(LocalImageFile item)
vm,
nameof(ImageViewerViewModel.NavigationRequested)
)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(ctx =>
{
Dispatcher
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
index daf355508..dc49664de 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reactive.Linq;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Threading;
@@ -114,6 +115,7 @@ RunningPackageService runningPackageService
AddDisposable(
ModelCardViewModel
.WhenPropertyChanged(x => x.IsRefinerSelectionEnabled)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(e =>
{
SamplerCardViewModel.IsRefinerStepsEnabled =
diff --git a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
index c821d305a..0cd1a8564 100644
--- a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
@@ -2,7 +2,9 @@
using System.IO;
using System.Linq;
using System.Text.Json;
+using System.Threading;
using System.Threading.Tasks;
+using System.Reactive.Linq;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
@@ -45,7 +47,7 @@ protected override async Task OnInitialLoadedAsync()
{
await base.OnInitialLoadedAsync();
- workflowsCache.Connect().DeferUntilLoaded().Bind(DisplayedWorkflows).Subscribe();
+ workflowsCache.Connect().DeferUntilLoaded().Bind(DisplayedWorkflows).ObserveOn(SynchronizationContext.Current).Subscribe();
if (Design.IsDesignMode)
return;
diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
index cc13e869a..0897932a6 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls.Notifications;
@@ -86,7 +88,12 @@ IPackageFactory packageFactory
protected override void OnInitialLoaded()
{
- searchResultsCache.Connect().DeferUntilLoaded().Bind(SearchResults).Subscribe();
+ searchResultsCache
+ .Connect()
+ .DeferUntilLoaded()
+ .Bind(SearchResults)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
SelectedSortMode = AllSortModes.First();
DoSearch().SafeFireAndForget();
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index c35b94984..f53c8844f 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -134,6 +134,7 @@ ServiceManager vmFactory
var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery)
.Throttle(TimeSpan.FromMilliseconds(100))!
.Select(property => searcher.GetPredicate(property.Value))
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
OutputsCache
@@ -149,12 +150,18 @@ ServiceManager vmFactory
.Bind(Outputs)
.WhenPropertyChanged(p => p.IsSelected)
.Throttle(TimeSpan.FromMilliseconds(50))
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(_ =>
{
NumItemsSelected = Outputs.Count(o => o.IsSelected);
});
- categoriesCache.Connect().DeferUntilLoaded().Bind(Categories).Subscribe();
+ categoriesCache
+ .Connect()
+ .DeferUntilLoaded()
+ .Bind(Categories)
+ .ObserveOn(SynchronizationContext.Current)
+ .Subscribe();
settingsManager.RelayPropertyFor(
this,
@@ -268,6 +275,7 @@ public async Task ShowImageDialog(OutputImageViewModel item)
vm,
nameof(ImageViewerViewModel.NavigationRequested)
)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(ctx =>
{
Dispatcher
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs
index ca4527e30..65dd3b763 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs
@@ -3,6 +3,8 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
@@ -101,6 +103,7 @@ RunningPackageService runningPackageService
})
)
.Bind(PackageCards)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
timer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(60), IsEnabled = true };
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs
index b4951cdb8..3a6db87bc 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs
@@ -102,6 +102,7 @@ ServiceManager vmFactory
.AutoRefresh(item => item.IsSelected)
.Filter(item => item.IsSelected)
.Bind(SelectedAvailableItems)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
var installedItemsChangeSet = installedExtensionsSource
@@ -114,6 +115,7 @@ ServiceManager vmFactory
.AutoRefresh(item => item.IsSelected)
.Filter(item => item.IsSelected)
.Bind(SelectedInstalledItems)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
cleanUp = new CompositeDisposable(
diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs
index 841c7408f..e3bfeaa8a 100644
--- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs
@@ -1,5 +1,6 @@
using System;
using System.Reactive.Linq;
+using System.Threading;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
@@ -71,6 +72,7 @@ IAnalyticsHelper analyticsHelper
var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages)
.Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages))
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchFilter)
@@ -80,6 +82,7 @@ IAnalyticsHelper analyticsHelper
p => p.DisplayName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase)
)
)
+ .ObserveOn(SynchronizationContext.Current)
.AsObservable();
packageSource
@@ -94,6 +97,7 @@ IAnalyticsHelper analyticsHelper
.ThenByAscending(p => p.DisplayName)
)
.Bind(InferencePackages)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
packageSource
@@ -108,6 +112,7 @@ IAnalyticsHelper analyticsHelper
.ThenByAscending(p => p.DisplayName)
)
.Bind(TrainingPackages)
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe();
packageSource.EditDiff(
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
index 55e8b488c..dc5cc078b 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
@@ -4,6 +4,7 @@
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reactive.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls.Notifications;
using Avalonia.Platform.Storage;
@@ -122,6 +123,7 @@ ISettingsManager settingsManager
this.WhenPropertyChanged(vm => vm.OutputImageFileNameFormat)
.Throttle(TimeSpan.FromMilliseconds(50))
+ .ObserveOn(SynchronizationContext.Current)
.Subscribe(formatProperty =>
{
var provider = FileNameFormatProvider.GetSample();
diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml
index 2e6f01856..7d7cda10d 100644
--- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml
+++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml
@@ -492,8 +492,14 @@
Grid.Column="3"
MinWidth="100"
Margin="4,0,4,8"
- ItemsSource="{Binding BaseModelOptions}"
- SelectedItem="{Binding SelectedBaseModelType}" />
+ ItemsSource="{Binding AllBaseModels}"
+ SelectedItem="{Binding SelectedBaseModelType}">
+
+
+
+
+
+
-
-
+
+
+ Watermark="{x:Static lang:Resources.Label_Email}" />
-
-
-
+
+
-
+ Severity="Error" />
+
-
+ NavigateUri="{x:Static sm:Assets.LykosForgotPasswordUrl}" />
+
+ Content="Sign in with Google" />
-
+
-
-
+
+
+ Watermark="{x:Static lang:Resources.Label_Email}" />
+ Watermark="{x:Static lang:Resources.Label_Username}" />
-
+ Watermark="{x:Static lang:Resources.Label_Password}" />
-
-
-
+
+
-
-
+
+
-
+ Markdown="{Binding SignupFooterMarkdown}"
+ TextElement.Foreground="{DynamicResource TextFillColorTertiaryBrush}">
+
-
-
+
+
-
+
diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml
index c463e833c..88aa3a8be 100644
--- a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml
+++ b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml
@@ -1,107 +1,120 @@
-
+
-
+
-
-
-
-
+
+
+
+
-
+
-
+ FontSize="15"
+ IconVariant="Filled"
+ Symbol="ArrowRight" />
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
diff --git a/StabilityMatrix.Core/Api/ICivitApi.cs b/StabilityMatrix.Core/Api/ICivitApi.cs
index b2d87371f..b0dd41338 100644
--- a/StabilityMatrix.Core/Api/ICivitApi.cs
+++ b/StabilityMatrix.Core/Api/ICivitApi.cs
@@ -1,4 +1,5 @@
-using Refit;
+using System.Text.Json.Nodes;
+using Refit;
using StabilityMatrix.Core.Models.Api;
namespace StabilityMatrix.Core.Api;
@@ -16,4 +17,7 @@ public interface ICivitApi
[Get("/api/v1/model-versions/{id}")]
Task GetModelVersionById(int id);
+
+ [Get("/api/v1/models?baseModels=gimmethelist")]
+ Task GetBaseModelList();
}
diff --git a/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs b/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs
index 27ff7cae6..66b584c0e 100644
--- a/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs
+++ b/StabilityMatrix.Core/Models/Api/CivitBaseModelType.cs
@@ -29,6 +29,9 @@ public enum CivitBaseModelType
[StringValue("Lumina")]
Lumina,
+ [StringValue("Mochi")]
+ Mochi,
+
[StringValue("PixArt a")]
PixArtA,
@@ -53,6 +56,15 @@ public enum CivitBaseModelType
[StringValue("SD 3.5")]
Sd35,
+ [StringValue("SD 3.5 Large")]
+ Sd35Large,
+
+ [StringValue("SD 3.5 Large Turbo")]
+ Sd35LargeTurbo,
+
+ [StringValue("SD 3.5 Medium")]
+ Sd35Medium,
+
[StringValue("SDXL 0.9")]
Sdxl09,
diff --git a/StabilityMatrix.Core/Models/Api/CivitFileType.cs b/StabilityMatrix.Core/Models/Api/CivitFileType.cs
index ef142a8c7..314c39504 100644
--- a/StabilityMatrix.Core/Models/Api/CivitFileType.cs
+++ b/StabilityMatrix.Core/Models/Api/CivitFileType.cs
@@ -11,6 +11,7 @@ public enum CivitFileType
Model,
VAE,
Config,
+ Archive,
[EnumMember(Value = "Pruned Model")]
PrunedModel,
diff --git a/StabilityMatrix.Core/Models/Api/CivitModelFormat.cs b/StabilityMatrix.Core/Models/Api/CivitModelFormat.cs
index d2e910bf7..6c11a3cce 100644
--- a/StabilityMatrix.Core/Models/Api/CivitModelFormat.cs
+++ b/StabilityMatrix.Core/Models/Api/CivitModelFormat.cs
@@ -10,5 +10,6 @@ public enum CivitModelFormat
SafeTensor,
PickleTensor,
Diffusers,
+ GGUF,
Other
}
diff --git a/StabilityMatrix.Core/Models/IndexCollection.cs b/StabilityMatrix.Core/Models/IndexCollection.cs
index b91ed50fe..3160214e6 100644
--- a/StabilityMatrix.Core/Models/IndexCollection.cs
+++ b/StabilityMatrix.Core/Models/IndexCollection.cs
@@ -1,4 +1,5 @@
-using DynamicData;
+using System.Reactive.Linq;
+using DynamicData;
using DynamicData.Binding;
using StabilityMatrix.Core.Services;
@@ -16,16 +17,12 @@ public class IndexCollection
///
/// Observable Collection of indexed items
///
- public IObservableCollection Items { get; } =
- new ObservableCollectionExtended();
+ public IObservableCollection Items { get; } = new ObservableCollectionExtended();
public IndexCollection(
IImageIndexService imageIndexService,
Func keySelector,
- Func<
- IObservable>,
- IObservable>
- >? transform = null
+ Func>, IObservable>>? transform = null
)
{
this.imageIndexService = imageIndexService;
@@ -39,7 +36,7 @@ public IndexCollection(
source = transform(source);
}
- source.Bind(Items).Subscribe();
+ source.Bind(Items).ObserveOn(SynchronizationContext.Current).Subscribe();
}
public void Add(TObject item)
diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
index b559f6695..e20fa1864 100644
--- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
+++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
@@ -76,7 +76,9 @@ IPrerequisiteHelper prerequisiteHelper
PrerequisiteHelper = prerequisiteHelper;
}
- public override async Task GetLatestVersion(bool includePrerelease = false)
+ public override async Task GetLatestVersion(
+ bool includePrerelease = false
+ )
{
if (ShouldIgnoreReleases)
{
@@ -88,12 +90,23 @@ public override async Task GetLatestVersion(bool
IsLatest = true,
IsPrerelease = false,
BranchName = MainBranch,
- CommitHash = commits?.FirstOrDefault()?.Sha ?? "unknown"
+ CommitHash = commits?.FirstOrDefault()?.Sha
};
}
var releases = await GithubApi.GetAllReleases(RepositoryAuthor, RepositoryName).ConfigureAwait(false);
- var latestRelease = includePrerelease ? releases.First() : releases.First(x => !x.Prerelease);
+ var releaseList = releases.ToList();
+ if (releaseList.Count == 0)
+ {
+ return new DownloadPackageVersionOptions
+ {
+ IsLatest = true,
+ IsPrerelease = false,
+ BranchName = MainBranch
+ };
+ }
+
+ var latestRelease = includePrerelease ? releaseList.First() : releaseList.First(x => !x.Prerelease);
return new DownloadPackageVersionOptions
{
@@ -319,7 +332,7 @@ public override async Task CheckForUpdates(InstalledPackage package)
await GetAllCommits(currentVersion.InstalledBranch!).ConfigureAwait(false)
)?.ToList();
- if (allCommits == null || !allCommits.Any())
+ if (allCommits == null || allCommits.Count == 0)
{
Logger.Warn("No commits found for {Package}", package.PackageName);
return false;
@@ -363,7 +376,7 @@ await GetAllCommits(currentVersion.InstalledBranch!).ConfigureAwait(false)
await GetAllCommits(currentVersion.InstalledBranch!).ConfigureAwait(false)
)?.ToList();
- if (allCommits == null || !allCommits.Any())
+ if (allCommits == null || allCommits.Count == 0)
{
Logger.Warn("No commits found for {Package}", installedPackage.PackageName);
return null;
diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs
index 7164a41ca..c1cff82d8 100644
--- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs
+++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs
@@ -188,7 +188,7 @@ public virtual TorchIndex GetRecommendedTorchVersion()
int page = 1,
int perPage = 10
);
- public abstract Task GetLatestVersion(bool includePrerelease = false);
+ public abstract Task GetLatestVersion(bool includePrerelease = false);
public abstract string MainBranch { get; }
public event EventHandler? Exited;
public event EventHandler? StartupComplete;
diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
index dc5a99f8f..f049050db 100644
--- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
+++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs
@@ -37,8 +37,7 @@ IPrerequisiteHelper prerequisiteHelper
public override string Blurb => "A powerful and modular stable diffusion GUI and backend";
public override string LaunchCommand => "main.py";
- public override Uri PreviewImageUri =>
- new("https://github.com/comfyanonymous/ComfyUI/raw/master/comfyui_screenshot.png");
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/comfyui/preview.webp");
public override bool ShouldIgnoreReleases => true;
public override bool IsInferenceCompatible => true;
public override string OutputFolderName => "output";
diff --git a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs
index 12f4d5f19..bb1b0ed7e 100644
--- a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs
+++ b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs
@@ -27,10 +27,7 @@ IPyRunner runner
public override string LicenseUrl => "https://github.com/bmaltais/kohya_ss/blob/master/LICENSE.md";
public override string LaunchCommand => "kohya_gui.py";
- public override Uri PreviewImageUri =>
- new(
- "https://camo.githubusercontent.com/5154eea62c113d5c04393e51a0d0f76ef25a723aad29d256dcc85ead1961cd41/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f6b35696d713031757655592f302e6a7067"
- );
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/kohyass/preview.webp");
public override string OutputFolderName => string.Empty;
public override bool IsCompatible => HardwareHelper.HasNvidiaGpu();
diff --git a/StabilityMatrix.Core/Models/Packages/Mashb1tFooocus.cs b/StabilityMatrix.Core/Models/Packages/Mashb1tFooocus.cs
index 02e501196..eabdb3ab1 100644
--- a/StabilityMatrix.Core/Models/Packages/Mashb1tFooocus.cs
+++ b/StabilityMatrix.Core/Models/Packages/Mashb1tFooocus.cs
@@ -23,8 +23,5 @@ IPrerequisiteHelper prerequisiteHelper
public override string LicenseUrl => "https://github.com/mashb1t/Fooocus/blob/main/LICENSE";
- public override Uri PreviewImageUri =>
- new("https://github.com/lllyasviel/Fooocus/assets/19834515/483fb86d-c9a2-4c20-997c-46dafc124f25");
-
public override bool ShouldIgnoreReleases => false;
}
diff --git a/StabilityMatrix.Core/Models/Packages/Reforge.cs b/StabilityMatrix.Core/Models/Packages/Reforge.cs
index a40237071..913fea8c7 100644
--- a/StabilityMatrix.Core/Models/Packages/Reforge.cs
+++ b/StabilityMatrix.Core/Models/Packages/Reforge.cs
@@ -21,10 +21,7 @@ IPrerequisiteHelper prerequisiteHelper
"Stable Diffusion WebUI reForge is a platform on top of Stable Diffusion WebUI (based on Gradio) to make development easier, optimize resource management, speed up inference, and study experimental features.";
public override string LicenseUrl =>
"https://github.com/Panchovix/stable-diffusion-webui-reForge/blob/main/LICENSE.txt";
- public override Uri PreviewImageUri =>
- new(
- "https://github.com/lllyasviel/stable-diffusion-webui-forge/assets/19834515/de1a2d05-344a-44d7-bab8-9ecc0a58a8d3"
- );
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/reforge/preview.webp");
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.ReallyRecommended;
}
diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
index aa1599ba8..f4c0cd503 100644
--- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
+++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs
@@ -29,10 +29,7 @@ IPrerequisiteHelper prerequisiteHelper
public override string LicenseUrl =>
"https://github.com/lllyasviel/stable-diffusion-webui-forge/blob/main/LICENSE.txt";
- public override Uri PreviewImageUri =>
- new(
- "https://github.com/lllyasviel/stable-diffusion-webui-forge/assets/19834515/ca5e05ed-bd86-4ced-8662-f41034648e8c"
- );
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/sdwebforge/preview.webp");
public override string MainBranch => "main";
public override bool ShouldIgnoreReleases => true;
diff --git a/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs b/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs
index 830cc3f0a..31f6ae13b 100644
--- a/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs
+++ b/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs
@@ -24,8 +24,7 @@ IPrerequisiteHelper prerequisiteHelper
public override string Blurb =>
"Enhanced version of Fooocus for SDXL, more suitable for Chinese and Cloud. Supports Flux.";
public override string LicenseUrl => "https://github.com/metercai/SimpleSDXL/blob/SimpleSDXL/LICENSE";
- public override Uri PreviewImageUri =>
- new("https://github.com/user-attachments/assets/98715a4d-9f4a-4846-ae62-eb8d69793d31");
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/simplesdxl/preview.webp");
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Expert;
public override IEnumerable AvailableSharedFolderMethods =>
[SharedFolderMethod.Configuration, SharedFolderMethod.Symlink, SharedFolderMethod.None];
diff --git a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs
index 950c398b7..1194f06c9 100644
--- a/StabilityMatrix.Core/Models/Packages/StableSwarm.cs
+++ b/StabilityMatrix.Core/Models/Packages/StableSwarm.cs
@@ -257,13 +257,24 @@ public override async Task RunPackage(
CancellationToken cancellationToken = default
)
{
+ var portableGitBin = new DirectoryPath(PrerequisiteHelper.GitBinPath);
var aspEnvVars = new Dictionary
{
["ASPNETCORE_ENVIRONMENT"] = "Production",
- ["ASPNETCORE_URLS"] = "http://*:7801"
+ ["ASPNETCORE_URLS"] = "http://*:7801",
+ ["GIT"] = portableGitBin.JoinFile("git.exe")
};
aspEnvVars.Update(settingsManager.Settings.EnvironmentVariables);
+ if (aspEnvVars.TryGetValue("PATH", out var pathValue))
+ {
+ aspEnvVars["PATH"] = Compat.GetEnvPathWithExtensions(portableGitBin, pathValue);
+ }
+ else
+ {
+ aspEnvVars["PATH"] = Compat.GetEnvPathWithExtensions(portableGitBin);
+ }
+
void HandleConsoleOutput(ProcessOutput s)
{
onConsoleOutput?.Invoke(s);
diff --git a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs
index 0a1491a2c..543b8a9f4 100644
--- a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs
+++ b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs
@@ -36,8 +36,7 @@ IPrerequisiteHelper prerequisiteHelper
public override string Blurb => "Stable Diffusion implementation with advanced features and modern UI";
public override string LaunchCommand => "launch.py";
- public override Uri PreviewImageUri =>
- new("https://github.com/vladmandic/automatic/raw/master/html/screenshot-modernui.jpg");
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/vladautomatic/preview.webp");
public override bool ShouldIgnoreReleases => true;
public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink;
diff --git a/StabilityMatrix.Core/Models/Packages/VoltaML.cs b/StabilityMatrix.Core/Models/Packages/VoltaML.cs
index 415d99b25..d4c88ed3b 100644
--- a/StabilityMatrix.Core/Models/Packages/VoltaML.cs
+++ b/StabilityMatrix.Core/Models/Packages/VoltaML.cs
@@ -26,10 +26,7 @@ IPrerequisiteHelper prerequisiteHelper
public override string Blurb => "Fast Stable Diffusion with support for AITemplate";
public override string LaunchCommand => "main.py";
- public override Uri PreviewImageUri =>
- new(
- "https://github.com/LykosAI/StabilityMatrix/assets/13956642/d9a908ed-5665-41a5-a380-98458f4679a8"
- );
+ public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/voltaml/preview.webp");
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Simple;
diff --git a/StabilityMatrix.Tests/Models/Packages/PackageHelper.cs b/StabilityMatrix.Tests/Models/Packages/PackageHelper.cs
new file mode 100644
index 000000000..dc9bcf8d8
--- /dev/null
+++ b/StabilityMatrix.Tests/Models/Packages/PackageHelper.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using NSubstitute;
+using StabilityMatrix.Core.Helper;
+using StabilityMatrix.Core.Helper.Cache;
+using StabilityMatrix.Core.Models.Packages;
+using StabilityMatrix.Core.Python;
+using StabilityMatrix.Core.Services;
+
+namespace StabilityMatrix.Tests.Models.Packages;
+
+public static class PackageHelper
+{
+ ///
+ /// Get all BasePackage implementations in the assembly.
+ ///
+ public static IEnumerable GetPackages()
+ {
+ var services = new ServiceCollection();
+ services
+ .AddSingleton(Substitute.For())
+ .AddSingleton(Substitute.For())
+ .AddSingleton(Substitute.For())
+ .AddSingleton(Substitute.For())
+ .AddSingleton(Substitute.For());
+
+ var assembly = typeof(BasePackage).Assembly;
+ var packageTypes = assembly
+ .GetTypes()
+ .Where(t => t.IsSubclassOf(typeof(BasePackage)) && !t.IsAbstract)
+ .Where(t => t != typeof(DankDiffusion) && t != typeof(UnknownPackage))
+ .ToList();
+
+ // Register all package types
+ services.TryAddEnumerable(
+ packageTypes.Select(t => ServiceDescriptor.Singleton(typeof(BasePackage), t))
+ );
+
+ var serviceProvider = services.BuildServiceProvider();
+ return serviceProvider.GetServices();
+ }
+}
diff --git a/StabilityMatrix.Tests/Models/Packages/PackageLinkTests.cs b/StabilityMatrix.Tests/Models/Packages/PackageLinkTests.cs
new file mode 100644
index 000000000..9bdbf6f24
--- /dev/null
+++ b/StabilityMatrix.Tests/Models/Packages/PackageLinkTests.cs
@@ -0,0 +1,56 @@
+using System.Net.Http.Headers;
+using StabilityMatrix.Core.Models.Packages;
+
+namespace StabilityMatrix.Tests.Models.Packages;
+
+///
+/// Tests that URL links on Packages should be valid. Requires internet connection.
+///
+[TestClass]
+public sealed class PackageLinkTests
+{
+ private static HttpClient HttpClient { get; } =
+ new() { DefaultRequestHeaders = { { "User-Agent", "StabilityMatrix/2.0" } } };
+
+ private static IEnumerable