Skip to content

Commit a353386

Browse files
authored
Merge pull request LykosAI#1099 from LykosAI/main
v2.13.1
2 parents 18c1db5 + 44e9cd6 commit a353386

22 files changed

+499
-341
lines changed

Avalonia.Gif/WebpInstance.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,18 @@ public WebpInstance(Stream currentStream)
5454

5555
var pixSize = new PixelSize(_codec.Info.Width, _codec.Info.Height);
5656

57-
_targetBitmap = new WriteableBitmap(pixSize, new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Opaque);
57+
_targetBitmap = new WriteableBitmap(
58+
pixSize,
59+
new Vector(96, 96),
60+
PixelFormat.Bgra8888,
61+
AlphaFormat.Opaque
62+
);
5863
GifPixelSize = pixSize;
5964

6065
_totalTime = TimeSpan.Zero;
6166

6267
_frameTimes = _codec
63-
.FrameInfo
64-
.Select(frame =>
68+
.FrameInfo.Select(frame =>
6569
{
6670
_totalTime = _totalTime.Add(TimeSpan.FromMilliseconds(frame.Duration));
6771
return _totalTime;

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ All notable changes to Stability Matrix will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
77

8+
## v2.13.1
9+
### Changed
10+
- Redesigned the Checkpoint Manager Filter flyout to include more options and improve the layout
11+
- "Clear All" button will now remain at the top of the Downloads list regardless of scroll position - thanks to @Genteure!
12+
- Improved image metadata parsing - thanks to @Genteure!
13+
### Fixed
14+
- Fixed [#1078](https://github.com/LykosAI/StabilityMatrix/issues/1078) - "Call from invalid thread" error after one-click install finishes
15+
- Fixed [#1080](https://github.com/LykosAI/StabilityMatrix/issues/1080) - Some models not displayed in Checkpoint Manager
16+
- Fixed Inference image selector card buttons taking up the whole height of the card
17+
- Fixed Inference mask editor failing to paint to the right-most edge on large images
18+
- Fixed Inference mask editor not showing the entire image in certain circumstances
19+
- Fixed crash when dragging & dropping images in Inference (hopefully)
20+
- Fixed an issue where certain sampler/scheduler combos would not get saved in image metadata - thanks to @yansigit!
21+
### Supporters
22+
#### Visionaries
23+
- A heartfelt thank you to our exceptional Visionary-tier Patreon backers, **Waterclouds** and **TheTekknician**! We truly appreciate your steadfast support!
24+
#### Pioneers
25+
- We are also very grateful to our wonderful Pioneer-tier Patreon supporters, **tankfox**, **Mr Unknown**, **Szir777**, **Tigon**, and **NowFallenAngel**! Your support means a lot to us!
26+
827
## v2.13.0
928
### Added
1029
- Added new package - [ComfyUI-Zluda](https://github.com/patientx/ComfyUI-Zluda) - for AMD GPU users on Windows

StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
Source="{Binding ImageSource}"
4949
Stretch="Uniform"
5050
StretchDirection="Both" />
51-
51+
5252
<!-- Overlay Image -->
5353
<Panel>
5454
<Panel.IsVisible>
@@ -57,13 +57,13 @@
5757
<CompiledBinding Path="IsMaskOverlayEnabled" />
5858
</MultiBinding>
5959
</Panel.IsVisible>
60-
<controls:BetterImage
60+
<controls:BetterImage
6161
VerticalAlignment="Stretch"
62-
Stretch="Uniform"
63-
StretchDirection="Both"
64-
RenderOptions.BitmapInterpolationMode="HighQuality"
6562
DataContext="{Binding MaskEditorViewModel}"
66-
Source="{Binding CachedOrNewMaskRenderImage.Bitmap}"/>
63+
RenderOptions.BitmapInterpolationMode="HighQuality"
64+
Source="{Binding CachedOrNewMaskRenderImage.Bitmap}"
65+
Stretch="Uniform"
66+
StretchDirection="Both" />
6767
</Panel>
6868

6969
<!-- Missing image -->
@@ -102,16 +102,18 @@
102102
<!-- Active Selection Prompt -->
103103
<StackPanel
104104
Margin="4"
105-
Spacing="4"
106-
Orientation="Horizontal"
107105
HorizontalAlignment="Right"
108106
VerticalAlignment="Top"
109-
IsVisible="{Binding !IsSelectionAvailable}">
110-
<!-- Mask Overlay Toggle -->
107+
IsVisible="{Binding !IsSelectionAvailable}"
108+
Orientation="Horizontal"
109+
Spacing="4">
110+
<!-- Mask Overlay Toggle -->
111111
<Border
112-
IsVisible="{Binding IsMaskEditorEnabled}"
112+
Width="40"
113+
Height="40"
113114
BoxShadow="inset 1.2 0 80 1.8 #66000000"
114-
CornerRadius="10">
115+
CornerRadius="10"
116+
IsVisible="{Binding IsMaskEditorEnabled}">
115117
<Border.Resources>
116118
<DropShadowEffect
117119
x:Key="TextDropShadowEffect"
@@ -126,9 +128,9 @@
126128
</Border.Resources>
127129
<ToggleButton
128130
Padding="2"
129-
IsChecked="{Binding IsMaskOverlayEnabled}"
130131
CornerRadius="10"
131-
FontSize="{TemplateBinding FontSize}">
132+
FontSize="{TemplateBinding FontSize}"
133+
IsChecked="{Binding IsMaskOverlayEnabled}">
132134
<ToolTip.Tip>
133135
<MultiBinding StringFormat="{}{0} - {1}">
134136
<CompiledBinding Source="{x:Static lang:Resources.Label_ClippingMask}" />
@@ -142,11 +144,13 @@
142144
Symbol="Eye" />
143145
</ToggleButton>
144146
</Border>
145-
<!-- Mask Editor -->
147+
<!-- Mask Editor -->
146148
<Border
147-
IsVisible="{Binding IsMaskEditorEnabled}"
149+
Width="40"
150+
Height="40"
148151
BoxShadow="inset 1.2 0 80 1.8 #66000000"
149-
CornerRadius="10">
152+
CornerRadius="10"
153+
IsVisible="{Binding IsMaskEditorEnabled}">
150154
<Border.Resources>
151155
<DropShadowEffect
152156
x:Key="TextDropShadowEffect"
@@ -178,8 +182,10 @@
178182
Symbol="Layer" />
179183
</Button>
180184
</Border>
181-
<!-- Replace Contents -->
185+
<!-- Replace Contents -->
182186
<Border
187+
Width="40"
188+
Height="40"
183189
BoxShadow="inset 1.2 0 80 1.8 #66000000"
184190
CornerRadius="10">
185191
<Border.Resources>

StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ private void HandlePointerMoved(PointerEventArgs e)
260260
// penPath.Path.LineTo(cursorPosition.ToSKPoint());
261261

262262
// Get bounds for discarding invalid points
263-
var canvasBounds = MainCanvas?.Bounds ?? new Rect();
263+
var canvasBounds = new Rect(0, 0, MainCanvas?.Bounds.Width ?? 0, MainCanvas?.Bounds.Height ?? 0);
264264

265265
// Add points
266266
foreach (var point in points)

StabilityMatrix.Avalonia/Models/ImageSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ protected virtual void Dispose(bool disposing)
277277
if (!disposing)
278278
return;
279279

280-
Bitmap?.Dispose();
280+
Bitmap = null;
281281
}
282282

283283
/// <inheritdoc />
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System.Text.Json.Nodes;
2+
using Injectio.Attributes;
3+
using Microsoft.Extensions.Logging;
4+
using StabilityMatrix.Core.Api;
5+
using StabilityMatrix.Core.Database;
6+
using StabilityMatrix.Core.Models.Api;
7+
using StabilityMatrix.Core.Models.Database;
8+
9+
namespace StabilityMatrix.Avalonia.Services;
10+
11+
[RegisterSingleton<ICivitBaseModelTypeService, CivitBaseModelTypeService>]
12+
public class CivitBaseModelTypeService(
13+
ILogger<CivitBaseModelTypeService> logger,
14+
ICivitApi civitApi,
15+
ILiteDbContext dbContext
16+
) : ICivitBaseModelTypeService
17+
{
18+
private const string CacheId = "BaseModelTypes";
19+
private static readonly TimeSpan CacheExpiration = TimeSpan.FromHours(24);
20+
21+
/// <summary>
22+
/// Gets the list of base model types, using cache if available and not expired
23+
/// </summary>
24+
public async Task<List<string>> GetBaseModelTypes(bool forceRefresh = false, bool includeAllOption = true)
25+
{
26+
List<string> civitBaseModels = [];
27+
28+
if (!forceRefresh)
29+
{
30+
var cached = await dbContext.GetCivitBaseModelTypeCacheEntry(CacheId);
31+
if (cached != null && DateTimeOffset.UtcNow.Subtract(cached.CreatedAt) < CacheExpiration)
32+
{
33+
civitBaseModels = cached.ModelTypes;
34+
}
35+
}
36+
37+
try
38+
{
39+
if (civitBaseModels.Count <= 0)
40+
{
41+
var baseModelsResponse = await civitApi.GetBaseModelList();
42+
var jsonContent = await baseModelsResponse.Content.ReadAsStringAsync();
43+
var baseModels = JsonNode.Parse(jsonContent);
44+
45+
var jArray =
46+
baseModels?["error"]?["issues"]?[0]?["unionErrors"]?[0]?["issues"]?[0]?["options"]
47+
as JsonArray;
48+
49+
civitBaseModels = jArray?.GetValues<string>().ToList() ?? [];
50+
51+
// Cache the results
52+
var cacheEntry = new CivitBaseModelTypeCacheEntry
53+
{
54+
Id = CacheId,
55+
ModelTypes = civitBaseModels,
56+
CreatedAt = DateTimeOffset.UtcNow
57+
};
58+
59+
await dbContext.UpsertCivitBaseModelTypeCacheEntry(cacheEntry);
60+
}
61+
62+
if (includeAllOption)
63+
{
64+
civitBaseModels.Insert(0, CivitBaseModelType.All.ToString());
65+
}
66+
67+
// Filter and sort results
68+
var filteredResults = civitBaseModels
69+
.Where(s => !s.Equals("odor", StringComparison.OrdinalIgnoreCase))
70+
.OrderBy(s => s)
71+
.ToList();
72+
73+
return filteredResults;
74+
}
75+
catch (Exception e)
76+
{
77+
logger.LogError(e, "Failed to get base model list");
78+
79+
// Return cached results if available, even if expired
80+
var expiredCache = await dbContext.GetCivitBaseModelTypeCacheEntry(CacheId);
81+
return expiredCache?.ModelTypes ?? [];
82+
}
83+
}
84+
85+
/// <summary>
86+
/// Clears the cached base model types
87+
/// </summary>
88+
public void ClearCache()
89+
{
90+
dbContext.CivitBaseModelTypeCache.DeleteAllAsync();
91+
}
92+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace StabilityMatrix.Avalonia.Services;
2+
3+
public interface ICivitBaseModelTypeService
4+
{
5+
Task<List<string>> GetBaseModelTypes(bool forceRefresh = false, bool includeAllOption = true);
6+
void ClearCache();
7+
}

StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ await notificationService.ShowAsync(
421421

422422
// Clear progress
423423
OutputProgress.ClearProgress();
424-
ImageGalleryCardViewModel.PreviewImage?.Dispose();
424+
// ImageGalleryCardViewModel.PreviewImage?.Dispose();
425425
ImageGalleryCardViewModel.PreviewImage = null;
426426
ImageGalleryCardViewModel.IsPreviewOverlayEnabled = false;
427427

StabilityMatrix.Avalonia/ViewModels/Base/PageViewModelBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base;
55
/// <summary>
66
/// An abstract class for enabling page navigation.
77
/// </summary>
8-
public abstract class PageViewModelBase : ViewModelBase
8+
public abstract class PageViewModelBase : DisposableViewModelBase
99
{
1010
/// <summary>
1111
/// Gets if the user can navigate to the next page
@@ -16,7 +16,7 @@ public abstract class PageViewModelBase : ViewModelBase
1616
/// Gets if the user can navigate to the previous page
1717
/// </summary>
1818
public virtual bool CanNavigatePrevious { get; protected set; }
19-
19+
2020
public abstract string Title { get; }
2121
public abstract IconSource IconSource { get; }
2222
}

StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
4545
private readonly ISettingsManager settingsManager;
4646
private readonly ILiteDbContext liteDbContext;
4747
private readonly INotificationService notificationService;
48+
private readonly ICivitBaseModelTypeService baseModelTypeService;
4849
private bool dontSearch = false;
4950

5051
private readonly SourceCache<OrderedValue<CivitModel>, int> modelCache = new(static ov => ov.Value.Id);
@@ -126,13 +127,15 @@ public CivitAiBrowserViewModel(
126127
ISettingsManager settingsManager,
127128
ServiceManager<ViewModelBase> dialogFactory,
128129
ILiteDbContext liteDbContext,
129-
INotificationService notificationService
130+
INotificationService notificationService,
131+
ICivitBaseModelTypeService baseModelTypeService
130132
)
131133
{
132134
this.civitApi = civitApi;
133135
this.settingsManager = settingsManager;
134136
this.liteDbContext = liteDbContext;
135137
this.notificationService = notificationService;
138+
this.baseModelTypeService = baseModelTypeService;
136139

137140
EventManager.Instance.NavigateAndFindCivitModelRequested += OnNavigateAndFindCivitModelRequested;
138141

@@ -727,31 +730,7 @@ private void UpdateResultsText()
727730
[Localizable(false)]
728731
private async Task<List<string>> GetBaseModelList()
729732
{
730-
try
731-
{
732-
var baseModelsResponse = await civitApi.GetBaseModelList();
733-
var jsonContent = await baseModelsResponse.Content.ReadAsStringAsync();
734-
var baseModels = JsonNode.Parse(jsonContent);
735-
736-
var jArray =
737-
baseModels?["error"]?["issues"]?[0]?["unionErrors"]?[0]?["issues"]?[0]?["options"]
738-
as JsonArray;
739-
var civitBaseModels = jArray?.GetValues<string>().ToList() ?? [];
740-
741-
civitBaseModels.Insert(0, CivitBaseModelType.All.ToString());
742-
743-
var filteredResults = civitBaseModels
744-
.Where(s => s.Equals("odor", StringComparison.OrdinalIgnoreCase) == false)
745-
.OrderBy(s => s)
746-
.ToList();
747-
748-
return filteredResults;
749-
}
750-
catch (Exception e)
751-
{
752-
Logger.Error(e, "Failed to get base model list");
753-
return [];
754-
}
733+
return await baseModelTypeService.GetBaseModelTypes();
755734
}
756735

757736
public override string Header => Resources.Label_CivitAi;

0 commit comments

Comments
 (0)