Skip to content

Commit c7ccc59

Browse files
authored
Merge pull request LykosAI#1432 from LykosAI/main
v2.15.3
2 parents a540828 + 83ac2c0 commit c7ccc59

File tree

15 files changed

+289
-47
lines changed

15 files changed

+289
-47
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ 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.15.3
9+
### Changed
10+
- Updated fallback rocm index for InvokeAI to rocm6.3
11+
- Updated SwarmUI to launch via the launch script for better compatibility
12+
### Fixed
13+
- Fixed cuDNN frontend error on ComfyUI-Zluda startup (thanks @neural_fault!)
14+
- Maybe finally actually fixed threading issue with the Python Packages dialog search box for real this time? (may fix [#1392](https://github.com/LykosAI/StabilityMatrix/issues/1392))
15+
- Fixed potential install failures when moving duplicate files into shared model folders (may fix [#1393](https://github.com/LykosAI/StabilityMatrix/issues/1393))
16+
- Fixed potential threading issues with the Inference image gallery (may fix [#1408](https://github.com/LykosAI/StabilityMatrix/issues/1408))
17+
- Fixed [#1424](https://github.com/LykosAI/StabilityMatrix/issues/1424) - Civitai account 401 error when connecting accounts, updated for new API changes
18+
### Supporters
19+
#### 🌟 Visionaries
20+
Our deepest gratitude to our Visionaries for their foundational support: **Waterclouds**, **JungleDragon**, **bluepopsicle**, **Bob S**, and **whudunit**! Your commitment allows us to focus on the essential work of squashing bugs and improving stability, ensuring a rock-solid experience for everyone.
21+
#### 🚀 Pioneers
22+
A huge thank you to our incredible Pioneers for keeping the project on track! Your support is vital for these important refinement updates. Thank you to **Szir777**, **Noah M**, **USATechDude**, **Thom**, **SeraphOfSalem**, **Desert Viber**, **Tundra Everquill**, **Adam**, **Droolguy**, **Philip R.**, **ACTUALLY_the_Real_Willem_Dafoe**, **takyamtom**, and a warm welcome to our newest Pioneer, **robek**!
23+
24+
825
## v2.15.2
926
### Changed
1027
- Updated Avalonia to 11.3.7

StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using StabilityMatrix.Avalonia.Languages;
1313
using StabilityMatrix.Core.Exceptions;
1414
using StabilityMatrix.Core.Helper;
15+
using StabilityMatrix.Core.Helper.HardwareInfo;
1516
using StabilityMatrix.Core.Models;
1617
using StabilityMatrix.Core.Models.FileInterfaces;
1718
using StabilityMatrix.Core.Models.Packages;
@@ -696,6 +697,69 @@ public async Task InstallUvIfNecessary(IProgress<ProgressReport>? progress = nul
696697
File.Delete(UvDownloadPath);
697698
}
698699

700+
public string? GetGfxArchFromAmdGpuName()
701+
{
702+
var gpu =
703+
settingsManager.Settings.PreferredGpu
704+
?? HardwareHelper.IterGpuInfo().FirstOrDefault(x => x is { Name: not null, IsAmd: true });
705+
706+
if (gpu?.Name is null || !gpu.IsAmd)
707+
return null;
708+
709+
// Normalize for safer substring checks (handles RX7800 vs RX 7800, etc.)
710+
var name = gpu.Name;
711+
var nameNoSpaces = name.Replace(" ", "", StringComparison.Ordinal);
712+
713+
return name switch
714+
{
715+
// RDNA4
716+
_ when Has("9060") || Has("9070") => "gfx1201",
717+
718+
// RDNA3.5 APUs
719+
_ when Has("860M") => "gfx1152",
720+
_ when Has("890M") => "gfx1150",
721+
_ when Has("8040S") || Has("8050S") || Has("8060S") || Has("880M") || Has("Z2 Extreme") =>
722+
"gfx1151",
723+
724+
// RDNA3 APUs (Phoenix)
725+
_ when Has("740M") || Has("760M") || Has("780M") || Has("Z1") || Has("Z2") => "gfx1103",
726+
727+
// RDNA3 dGPU Navi33
728+
_ when Has("7400") || Has("7500") || Has("7600") || Has("7650") || Has("7700S") => "gfx1102",
729+
730+
// RDNA3 dGPU Navi32
731+
_ when Has("7700") || Has("RX 7800") || HasNoSpace("RX7800") => "gfx1101",
732+
733+
// RDNA3 dGPU Navi31 (incl. Pro)
734+
_ when Has("W7800") || Has("7900") || Has("7950") || Has("7990") => "gfx1100",
735+
736+
// RDNA2 APUs (Rembrandt)
737+
_ when Has("660M") || Has("680M") => "gfx1035",
738+
739+
// RDNA2 Navi24 low-end (incl. some mobiles)
740+
_ when Has("6300") || Has("6400") || Has("6450") || Has("6500") || Has("6550") || Has("6500M") =>
741+
"gfx1034",
742+
743+
// RDNA2 Navi23
744+
_ when Has("6600") || Has("6650") || Has("6700S") || Has("6800S") || Has("6600M") => "gfx1032",
745+
746+
// RDNA2 Navi22 (note: desktop 6800 is NOT here; that’s Navi21/gfx1030)
747+
_ when Has("6700") || Has("6750") || Has("6800M") || Has("6850M") => "gfx1031",
748+
749+
// RDNA2 Navi21 (big die)
750+
_ when Has("6800") || Has("6900") || Has("6950") => "gfx1030",
751+
752+
_ => null,
753+
};
754+
755+
bool HasNoSpace(string s) =>
756+
nameNoSpaces.Contains(
757+
s.Replace(" ", "", StringComparison.Ordinal),
758+
StringComparison.OrdinalIgnoreCase
759+
);
760+
bool Has(string s) => name.Contains(s, StringComparison.OrdinalIgnoreCase);
761+
}
762+
699763
private async Task DownloadAndExtractPrerequisite(
700764
IProgress<ProgressReport>? progress,
701765
string downloadUrl,

StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,69 @@ public async Task AddMissingLibsToVenv(
921921
// await downloadPath.DeleteAsync();
922922
}
923923

924+
public string? GetGfxArchFromAmdGpuName()
925+
{
926+
var gpu =
927+
settingsManager.Settings.PreferredGpu
928+
?? HardwareHelper.IterGpuInfo().FirstOrDefault(x => x is { Name: not null, IsAmd: true });
929+
930+
if (gpu?.Name is null || !gpu.IsAmd)
931+
return null;
932+
933+
// Normalize for safer substring checks (handles RX7800 vs RX 7800, etc.)
934+
var name = gpu.Name;
935+
var nameNoSpaces = name.Replace(" ", "", StringComparison.Ordinal);
936+
937+
return name switch
938+
{
939+
// RDNA4
940+
_ when Has("9060") || Has("9070") => "gfx1201",
941+
942+
// RDNA3.5 APUs
943+
_ when Has("860M") => "gfx1152",
944+
_ when Has("890M") => "gfx1150",
945+
_ when Has("8040S") || Has("8050S") || Has("8060S") || Has("880M") || Has("Z2 Extreme") =>
946+
"gfx1151",
947+
948+
// RDNA3 APUs (Phoenix)
949+
_ when Has("740M") || Has("760M") || Has("780M") || Has("Z1") || Has("Z2") => "gfx1103",
950+
951+
// RDNA3 dGPU Navi33
952+
_ when Has("7400") || Has("7500") || Has("7600") || Has("7650") || Has("7700S") => "gfx1102",
953+
954+
// RDNA3 dGPU Navi32
955+
_ when Has("7700") || Has("RX 7800") || HasNoSpace("RX7800") => "gfx1101",
956+
957+
// RDNA3 dGPU Navi31 (incl. Pro)
958+
_ when Has("W7800") || Has("7900") || Has("7950") || Has("7990") => "gfx1100",
959+
960+
// RDNA2 APUs (Rembrandt)
961+
_ when Has("660M") || Has("680M") => "gfx1035",
962+
963+
// RDNA2 Navi24 low-end (incl. some mobiles)
964+
_ when Has("6300") || Has("6400") || Has("6450") || Has("6500") || Has("6550") || Has("6500M") =>
965+
"gfx1034",
966+
967+
// RDNA2 Navi23
968+
_ when Has("6600") || Has("6650") || Has("6700S") || Has("6800S") || Has("6600M") => "gfx1032",
969+
970+
// RDNA2 Navi22 (note: desktop 6800 is NOT here; that’s Navi21/gfx1030)
971+
_ when Has("6700") || Has("6750") || Has("6800M") || Has("6850M") => "gfx1031",
972+
973+
// RDNA2 Navi21 (big die)
974+
_ when Has("6800") || Has("6900") || Has("6950") => "gfx1030",
975+
976+
_ => null,
977+
};
978+
979+
bool HasNoSpace(string s) =>
980+
nameNoSpaces.Contains(
981+
s.Replace(" ", "", StringComparison.Ordinal),
982+
StringComparison.OrdinalIgnoreCase
983+
);
984+
bool Has(string s) => name.Contains(s, StringComparison.OrdinalIgnoreCase);
985+
}
986+
924987
private async Task DownloadAndExtractPrerequisite(
925988
IProgress<ProgressReport>? progress,
926989
string downloadUrl,

StabilityMatrix.Avalonia/Services/AccountsService.cs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,10 @@ public async Task CivitLoginAsync(string apiToken)
172172
var secrets = await secretsManager.SafeLoadAsync();
173173

174174
// Get id first using the api token
175-
var userAccount = await civitTRPCApi.GetUserAccountDefault(apiToken);
176-
var id = userAccount.Result.Data.Json.Id;
175+
var userAccount = await civitTRPCApi.GetUserAccount(bearerToken: apiToken);
176+
var id =
177+
userAccount.InnerJson?.Id
178+
?? throw new InvalidOperationException("GetUserAccount did not contain an id");
177179

178180
// Then get the username using the id
179181
var account = await civitTRPCApi.GetUserById(new CivitGetUserByIdRequest { Id = id }, apiToken);
@@ -241,7 +243,7 @@ secrets.LykosAccountV2 is not null
241243
{
242244
IsConnected = true,
243245
Principal = principal,
244-
User = user
246+
User = user,
245247
}
246248
);
247249

@@ -282,27 +284,55 @@ private async Task RefreshHuggingFaceAsync(Secrets secrets)
282284
if (response.IsSuccessStatusCode && response.Content != null)
283285
{
284286
// Token is valid, user info fetched
285-
logger.LogInformation("Hugging Face token is valid. User: {Username}", response.Content.Name);
286-
OnHuggingFaceAccountStatusUpdate(new HuggingFaceAccountStatusUpdateEventArgs(true, response.Content.Name));
287+
logger.LogInformation(
288+
"Hugging Face token is valid. User: {Username}",
289+
response.Content.Name
290+
);
291+
OnHuggingFaceAccountStatusUpdate(
292+
new HuggingFaceAccountStatusUpdateEventArgs(true, response.Content.Name)
293+
);
287294
}
288295
else
289296
{
290297
// Token is likely invalid or other API error
291-
logger.LogWarning("Hugging Face token validation failed. Status: {StatusCode}, Error: {Error}, Content: {Content}", response.StatusCode, response.Error?.ToString(), await response.Error?.GetContentAsAsync<string>() ?? "N/A");
292-
OnHuggingFaceAccountStatusUpdate(new HuggingFaceAccountStatusUpdateEventArgs(false, null, $"Token validation failed: {response.StatusCode}"));
298+
logger.LogWarning(
299+
"Hugging Face token validation failed. Status: {StatusCode}, Error: {Error}, Content: {Content}",
300+
response.StatusCode,
301+
response.Error?.ToString(),
302+
await response.Error?.GetContentAsAsync<string>() ?? "N/A"
303+
);
304+
OnHuggingFaceAccountStatusUpdate(
305+
new HuggingFaceAccountStatusUpdateEventArgs(
306+
false,
307+
null,
308+
$"Token validation failed: {response.StatusCode}"
309+
)
310+
);
293311
}
294312
}
295313
catch (ApiException apiEx)
296314
{
297315
// Handle Refit's ApiException (network issues, non-success status codes not caught by IsSuccessStatusCode if IApiResponse isn't used directly)
298-
logger.LogError(apiEx, "Hugging Face API request failed during token validation. Content: {Content}", await apiEx.GetContentAsAsync<string>() ?? "N/A");
299-
OnHuggingFaceAccountStatusUpdate(new HuggingFaceAccountStatusUpdateEventArgs(false, null, "API request failed during token validation."));
316+
logger.LogError(
317+
apiEx,
318+
"Hugging Face API request failed during token validation. Content: {Content}",
319+
await apiEx.GetContentAsAsync<string>() ?? "N/A"
320+
);
321+
OnHuggingFaceAccountStatusUpdate(
322+
new HuggingFaceAccountStatusUpdateEventArgs(
323+
false,
324+
null,
325+
"API request failed during token validation."
326+
)
327+
);
300328
}
301329
catch (Exception ex)
302330
{
303331
// Handle other unexpected errors
304332
logger.LogError(ex, "An unexpected error occurred during Hugging Face token validation.");
305-
OnHuggingFaceAccountStatusUpdate(new HuggingFaceAccountStatusUpdateEventArgs(false, null, "An unexpected error occurred."));
333+
OnHuggingFaceAccountStatusUpdate(
334+
new HuggingFaceAccountStatusUpdateEventArgs(false, null, "An unexpected error occurred.")
335+
);
306336
}
307337
}
308338
else
@@ -390,7 +420,10 @@ private void OnHuggingFaceAccountStatusUpdate(HuggingFaceAccountStatusUpdateEven
390420
else if (e.IsConnected && HuggingFaceStatus?.IsConnected == false)
391421
{
392422
// Assuming Username might be null for now as we are not fetching it.
393-
logger.LogInformation("Hugging Face account connected" + (string.IsNullOrWhiteSpace(e.Username) ? "" : $" (User: {e.Username})"));
423+
logger.LogInformation(
424+
"Hugging Face account connected"
425+
+ (string.IsNullOrWhiteSpace(e.Username) ? "" : $" (User: {e.Username})")
426+
);
394427
}
395428
else if (!e.IsConnected && !string.IsNullOrWhiteSpace(e.ErrorMessage))
396429
{

StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
88
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
99
<ApplicationIcon>./Assets/Icon.ico</ApplicationIcon>
10-
<Version>2.15.0-dev.999</Version>
10+
<Version>2.16.0-dev.999</Version>
1111
<InformationalVersion>$(Version)</InformationalVersion>
1212
<EnableWindowsTargeting>true</EnableWindowsTargeting>
1313
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private void PostConstruct()
6868
var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery)
6969
.Throttle(TimeSpan.FromMilliseconds(100))
7070
.DistinctUntilChanged()
71+
.ObserveOn(SynchronizationContext.Current!)
7172
.Select(value =>
7273
{
7374
if (string.IsNullOrWhiteSpace(value.Value))
@@ -86,8 +87,8 @@ private void PostConstruct()
8687
.Filter(searchPredicate)
8788
.Transform(p => new PythonPackagesItemViewModel(settingsManager) { Package = p })
8889
.SortBy(vm => vm.Package.Name)
89-
.Bind(Packages)
9090
.ObserveOn(SynchronizationContext.Current!)
91+
.Bind(Packages)
9192
.Subscribe();
9293
}
9394

@@ -120,10 +121,14 @@ await pyInstallationManager.GetInstallationAsync(
120121

121122
var packages = await venvRunner.PipList();
122123

123-
packageSource.EditDiff(packages);
124+
Dispatcher.UIThread.Post(() =>
125+
{
126+
var currentName = SelectedPackage?.Package.Name;
127+
SelectedPackage = null;
124128

125-
// Delay a bit to prevent thread issues with UI list
126-
await Task.Delay(100);
129+
packageSource.EditDiff(packages);
130+
SelectedPackage = Packages.FirstOrDefault(p => p.Package.Name == currentName);
131+
});
127132
}
128133
}
129134
finally
@@ -155,6 +160,7 @@ await pyInstallationManager.GetInstallationAsync(
155160
{
156161
// Backup selected package
157162
var currentPackageName = SelectedPackage?.Package.Name;
163+
SelectedPackage = null;
158164

159165
packageSource.EditDiff(packages);
160166

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq;
2+
using Avalonia.Threading;
23
using StabilityMatrix.Avalonia.Models;
34

45
namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@@ -12,13 +13,20 @@ public interface IImageGalleryComponent
1213
/// </summary>
1314
public void LoadImagesToGallery(params ImageSource[] imageSources)
1415
{
15-
ImageGalleryCardViewModel.ImageSources.Clear();
16-
17-
foreach (var imageSource in imageSources)
16+
Dispatcher.UIThread.Post(() =>
1817
{
19-
ImageGalleryCardViewModel.ImageSources.Add(imageSource);
20-
}
18+
ImageGalleryCardViewModel.SelectedImage = null;
19+
ImageGalleryCardViewModel.SelectedImageIndex = -1;
20+
21+
ImageGalleryCardViewModel.ImageSources.Clear();
22+
23+
foreach (var imageSource in imageSources)
24+
{
25+
ImageGalleryCardViewModel.ImageSources.Add(imageSource);
26+
}
2127

22-
ImageGalleryCardViewModel.SelectedImage = imageSources.FirstOrDefault();
28+
ImageGalleryCardViewModel.SelectedImageIndex = imageSources.Length > 0 ? 0 : -1;
29+
ImageGalleryCardViewModel.SelectedImage = imageSources.FirstOrDefault();
30+
});
2331
}
2432
}

StabilityMatrix.Core/Api/ICivitTRPCApi.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,25 @@ Task<CivitUserProfileResponse> GetUserProfile(
2020

2121
[QueryUriFormat(UriFormat.UriEscaped)]
2222
[Get("/api/trpc/buzz.getUserAccount")]
23-
Task<CivitTrpcResponse<CivitUserAccountResponse>> GetUserAccount(
23+
Task<CivitTrpcArrayResponse<CivitUserAccountResponse>> GetUserAccount(
2424
[Query] string input,
2525
[Authorize] string bearerToken,
2626
CancellationToken cancellationToken = default
2727
);
2828

29-
Task<CivitTrpcResponse<CivitUserAccountResponse>> GetUserAccountDefault(
29+
[QueryUriFormat(UriFormat.UriEscaped)]
30+
[Get("/api/trpc/buzz.getUserAccount")]
31+
Task<CivitTrpcArrayResponse<CivitUserAccountResponse>> GetUserAccount(
32+
[Authorize] string bearerToken,
33+
CancellationToken cancellationToken = default
34+
);
35+
36+
/// <summary>
37+
/// Calls <see cref="GetUserAccount(string, string, CancellationToken)"/> with default JSON input.
38+
/// Not required and returns 401 since Oct 2025 since civit changes.
39+
/// Mainly just use <see cref="GetUserAccount(string, CancellationToken)"/> instead.
40+
/// </summary>
41+
Task<CivitTrpcArrayResponse<CivitUserAccountResponse>> GetUserAccountDefault(
3042
string bearerToken,
3143
CancellationToken cancellationToken = default
3244
)

0 commit comments

Comments
 (0)