Skip to content

Commit f4b4a53

Browse files
authored
Merge pull request LykosAI#1194 from ionite34/backport/main/pr-1193
[dev to main] backport: Fix bugs n stuff (1193)
2 parents 4f5ecb3 + 4142dd9 commit f4b4a53

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1618
-415
lines changed

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,27 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
99
### Added
1010
- Added NVIDIA driver version warning when launching ComfyUI with CUDA 13.0 (cu130) and driver versions below 580.x
1111
- Added legacy Python warning when launching InvokeAI installations using Python 3.10.11
12+
- Added Tiled VAE Decode to the Inference video workflows - thanks to @NeuralFault!
1213
### Changed
1314
- Disabled update checking for legacy InvokeAI installations using Python 3.10.11
14-
### Fixed
1515
- Hide rating stars in the Civitai browser page if no rating is available
16+
- Updated uv to v0.9.26
17+
- Updated PortableGit to v2.52.0.windows.1
18+
- Updated Sage/Triton/Nunchaku installers to use GitHub API to fetch latest releases
19+
- Updated ComfyUI installations and updates to automatically install ComfyUI Manager
20+
- Updated gfx110X Windows ROCm nightly index - thanks to @NeuralFault!
21+
- Updated ComfyUI-Zluda install to more closely match the author's intended installation method - thanks to @NeuralFault!
22+
- Updated Forge Classic installs/updates to use the upstream install script for better version compatibility with torch/sage/triton/nunchaku
23+
### Fixed
24+
- Fixed [#1529](https://github.com/LykosAI/StabilityMatrix/issues/1529) - "Selected commit is null" error when installing packages and rate limited by GitHub
25+
- Fixed [#1525](https://github.com/LykosAI/StabilityMatrix/issues/1525) - Crash after downloading a model
26+
- Fixed [#1523](https://github.com/LykosAI/StabilityMatrix/issues/1523), [#1499](https://github.com/LykosAI/StabilityMatrix/issues/1499), [#1494](https://github.com/LykosAI/StabilityMatrix/issues/1494) - Automatic1111 using old stable diffusion repo
27+
- Fixed [#1518](https://github.com/LykosAI/StabilityMatrix/issues/1518), [#1513](https://github.com/LykosAI/StabilityMatrix/issues/1513), [#1488](https://github.com/LykosAI/StabilityMatrix/issues/1488) - Forge Neo update breaking things
28+
- Fixed [#1505](https://github.com/LykosAI/StabilityMatrix/issues/1505) - incorrect port argument for Wan2GP
29+
- Possibly fix [#1502](https://github.com/LykosAI/StabilityMatrix/issues/1502) - English fonts not displaying correctly on Linux in Chinese environments
30+
- Fixed [#1476](https://github.com/LykosAI/StabilityMatrix/issues/1476) - Incorrect shared output folder for Forge Classic/Neo
31+
- Fixed [#1466](https://github.com/LykosAI/StabilityMatrix/issues/1466) - crash after moving portable install
32+
- Fixed [#1445](https://github.com/LykosAI/StabilityMatrix/issues/1445) - Linux app updates not actually updating - thanks to @NeuralFault!
1633

1734
## v2.15.5
1835
### Added

StabilityMatrix.Avalonia/App.axaml.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,28 @@ public FontFamily GetPlatformDefaultFontFamily()
250250
fonts.Add("Helvetica Neue");
251251
fonts.Add("Helvetica");
252252
}
253+
else if (Compat.IsLinux)
254+
{
255+
// For Chinese locales, prioritize CJK-capable fonts first
256+
if (Cultures.Current?.Name is "zh-Hans" or "zh-Hant")
257+
{
258+
// Common Chinese fonts on Linux systems
259+
fonts.Add("Noto Sans CJK SC");
260+
fonts.Add("Noto Sans CJK TC");
261+
fonts.Add("Source Han Sans");
262+
fonts.Add("WenQuanYi Micro Hei");
263+
fonts.Add("WenQuanYi Zen Hei");
264+
}
265+
266+
// Add common Linux fonts
267+
fonts.Add("Ubuntu");
268+
fonts.Add("DejaVu Sans");
269+
270+
// Fallback to system default
271+
fonts.Add(FontFamily.Default.Name);
272+
273+
return new FontFamily(string.Join(",", fonts));
274+
}
253275
else
254276
{
255277
return FontFamily.Default;
@@ -281,6 +303,9 @@ private void Setup()
281303
Logger.Debug("ActivatableLifetime available, setting up activation protocol handlers");
282304
activatableLifetime.Activated += OnActivated;
283305
}
306+
307+
// Update font when culture/language changes
308+
EventManager.Instance.CultureChanged += (_, _) => SetFontFamily(GetPlatformDefaultFontFamily());
284309
}
285310

286311
private void ShowMainWindow()

StabilityMatrix.Avalonia/DesignData/MockLaunchPageViewModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ IServiceManager<ViewModelBase> dialogFactory
3636
public override BasePackage? SelectedBasePackage =>
3737
SelectedPackage?.PackageName != "dank-diffusion"
3838
? base.SelectedBasePackage
39-
: new DankDiffusion(null!, null!, null!, null!, null!);
39+
: new DankDiffusion(null!, null!, null!, null!, null!, null!);
4040

4141
protected override Task LaunchImpl(string? command)
4242
{
4343
IsLaunchTeachingTipsOpen = false;
4444

45-
RunningPackage = new PackagePair(null!, new DankDiffusion(null!, null!, null!, null!, null!));
45+
RunningPackage = new PackagePair(null!, new DankDiffusion(null!, null!, null!, null!, null!, null!));
4646

4747
Console.Document.Insert(
4848
0,

StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ IPyInstallationManager pyInstallationManager
3535
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
3636

3737
private const string UvMacDownloadUrl =
38-
"https://github.com/astral-sh/uv/releases/download/0.8.4/uv-aarch64-apple-darwin.tar.gz";
38+
"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin.tar.gz";
3939
private const string UvLinuxDownloadUrl =
40-
"https://github.com/astral-sh/uv/releases/download/0.8.4/uv-x86_64-unknown-linux-gnu.tar.gz";
40+
"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz";
4141

4242
private DirectoryPath HomeDir => settingsManager.LibraryDir;
4343
private DirectoryPath AssetsDir => HomeDir.JoinDir("Assets");
@@ -75,7 +75,7 @@ private bool IsPythonVersionInstalled(PyVersion version) =>
7575
// Cached store of whether or not git is installed
7676
private bool? isGitInstalled;
7777

78-
private string ExpectedUvVersion => "0.8.4";
78+
private string ExpectedUvVersion => "0.9.26";
7979

8080
public bool IsVcBuildToolsInstalled => false;
8181
public bool IsHipSdkInstalled => false;
@@ -272,7 +272,13 @@ private async Task RunGit(ProcessArgs args, string? workingDirectory = null)
272272
var result = await ProcessRunner.RunBashCommand(
273273
command,
274274
workingDirectory ?? string.Empty,
275-
new Dictionary<string, string> { { "GIT_TERMINAL_PROMPT", "0" } }
275+
new Dictionary<string, string>
276+
{
277+
{ "GIT_TERMINAL_PROMPT", "0" },
278+
// Set UTF-8 locale to handle Unicode characters in paths
279+
{ "LC_ALL", "C.UTF-8" },
280+
{ "LANG", "C.UTF-8" },
281+
}
276282
);
277283
if (result.ExitCode != 0)
278284
{
@@ -375,7 +381,16 @@ public async Task InstallPythonIfNecessary(PyVersion version, IProgress<Progress
375381

376382
public Task<ProcessResult> GetGitOutput(ProcessArgs args, string? workingDirectory = null)
377383
{
378-
return ProcessRunner.RunBashCommand(args.Prepend("git"), workingDirectory ?? "");
384+
return ProcessRunner.RunBashCommand(
385+
args.Prepend("git"),
386+
workingDirectory ?? "",
387+
new Dictionary<string, string>
388+
{
389+
// Set UTF-8 locale to handle Unicode characters in paths
390+
{ "LC_ALL", "C.UTF-8" },
391+
{ "LANG", "C.UTF-8" },
392+
}
393+
);
379394
}
380395

381396
private async Task<string> RunNode(

StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ IPyInstallationManager pyInstallationManager
2727
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
2828

2929
private const string PortableGitDownloadUrl =
30-
"https://github.com/git-for-windows/git/releases/download/v2.41.0.windows.1/PortableGit-2.41.0-64-bit.7z.exe";
30+
"https://github.com/git-for-windows/git/releases/download/v2.52.0.windows.1/PortableGit-2.52.0-64-bit.7z.exe";
31+
private const string ExpectedGitVersion = "2.52.0";
3132

3233
private const string VcRedistDownloadUrl = "https://aka.ms/vs/16/release/vc_redist.x64.exe";
3334

@@ -49,7 +50,7 @@ IPyInstallationManager pyInstallationManager
4950
private const string PythonLibsDownloadUrl = "https://cdn.lykos.ai/python_libs_for_sage.zip";
5051

5152
private const string UvWindowsDownloadUrl =
52-
"https://github.com/astral-sh/uv/releases/download/0.8.4/uv-x86_64-pc-windows-msvc.zip";
53+
"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-pc-windows-msvc.zip";
5354

5455
private string HomeDir => settingsManager.LibraryDir;
5556

@@ -115,7 +116,7 @@ private string GetPythonLibraryZipPath(PyVersion version) =>
115116
private string UvExtractPath => Path.Combine(AssetsDir, "uv");
116117
public string UvExePath => Path.Combine(UvExtractPath, "uv.exe");
117118
public bool IsUvInstalled => File.Exists(UvExePath);
118-
private string ExpectedUvVersion => "0.8.4";
119+
private string ExpectedUvVersion => "0.9.26";
119120

120121
public string GitBinPath => Path.Combine(PortableGitInstallDir, "bin");
121122
public bool IsVcBuildToolsInstalled => Directory.Exists(VcBuildToolsExistsPath);
@@ -155,6 +156,10 @@ public async Task RunGit(
155156
{
156157
{ "PATH", Compat.GetEnvPathWithExtensions(GitBinPath) },
157158
{ "GIT_TERMINAL_PROMPT", "0" },
159+
// Set UTF-8 locale to handle Unicode characters in paths
160+
// This helps Git load libcurl-4.dll when paths contain non-ASCII characters
161+
{ "LC_ALL", "C.UTF-8" },
162+
{ "LANG", "C.UTF-8" },
158163
}
159164
);
160165
await process.WaitForExitAsync().ConfigureAwait(false);
@@ -173,6 +178,10 @@ public Task<ProcessResult> GetGitOutput(ProcessArgs args, string? workingDirecto
173178
environmentVariables: new Dictionary<string, string>
174179
{
175180
{ "PATH", Compat.GetEnvPathWithExtensions(GitBinPath) },
181+
// Set UTF-8 locale to handle Unicode characters in paths
182+
// This helps Git load libcurl-4.dll when paths contain non-ASCII characters
183+
{ "LC_ALL", "C.UTF-8" },
184+
{ "LANG", "C.UTF-8" },
176185
}
177186
);
178187
}
@@ -605,11 +614,31 @@ public async Task InstallGitIfNecessary(IProgress<ProgressReport>? progress = nu
605614
{
606615
if (File.Exists(GitExePath))
607616
{
608-
Logger.Debug("Git already installed at {GitExePath}", GitExePath);
609-
return;
617+
var installedVersion = await GetInstalledGitVersionAsync();
618+
if (installedVersion.Contains(ExpectedGitVersion))
619+
{
620+
Logger.Debug(
621+
"Git {Version} already installed at {GitExePath}",
622+
ExpectedGitVersion,
623+
GitExePath
624+
);
625+
return;
626+
}
627+
628+
Logger.Info(
629+
"Git version mismatch. Installed: {Installed}, Expected: {Expected}. Upgrading...",
630+
installedVersion.Trim(),
631+
ExpectedGitVersion
632+
);
633+
634+
// Delete existing installation to upgrade
635+
if (Directory.Exists(PortableGitInstallDir))
636+
{
637+
await new DirectoryPath(PortableGitInstallDir).DeleteAsync(true);
638+
}
610639
}
611640

612-
Logger.Info("Git not found at {GitExePath}, downloading...", GitExePath);
641+
Logger.Info("Git not found or outdated at {GitExePath}, downloading...", GitExePath);
613642

614643
// Download
615644
if (!File.Exists(PortableGitDownloadPath))
@@ -1139,6 +1168,20 @@ private async Task<string> GetInstalledUvVersionAsync()
11391168
}
11401169
}
11411170

1171+
private async Task<string> GetInstalledGitVersionAsync()
1172+
{
1173+
try
1174+
{
1175+
var result = await GetGitOutput(["--version"]);
1176+
return result.StandardOutput ?? string.Empty;
1177+
}
1178+
catch (Exception e)
1179+
{
1180+
Logger.Warn(e, "Failed to get Git version");
1181+
return string.Empty;
1182+
}
1183+
}
1184+
11421185
private async Task<bool> EnsurePythonVersion(PyVersion pyVersion)
11431186
{
11441187
var result = await pyInstallationManager.GetInstallationAsync(pyVersion);

StabilityMatrix.Avalonia/Services/InferenceClientManager.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,22 @@ ICompletionProvider completionProvider
331331
if (!settingsManager.IsLibraryDirSet)
332332
return;
333333

334-
ResetSharedProperties();
335-
336-
if (IsConnected)
334+
// Dispatch to UI thread to prevent race conditions with Avalonia's selection model.
335+
// The ModelIndexChanged event may be raised from a background thread, and modifying
336+
// observable collections from a non-UI thread can cause ArgumentOutOfRangeException
337+
// when the selection model tries to enumerate selected items.
338+
Dispatcher.UIThread.Post(() =>
337339
{
338-
LoadSharedPropertiesAsync()
339-
.SafeFireAndForget(onException: ex =>
340-
logger.LogError(ex, "Error loading shared properties")
341-
);
342-
}
340+
ResetSharedProperties();
341+
342+
if (IsConnected)
343+
{
344+
LoadSharedPropertiesAsync()
345+
.SafeFireAndForget(onException: ex =>
346+
logger.LogError(ex, "Error loading shared properties")
347+
);
348+
}
349+
});
343350
};
344351
}
345352

StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -321,41 +321,35 @@ private async Task RenameAsync()
321321
[RelayCommand]
322322
private async Task OpenSafetensorMetadataViewer()
323323
{
324-
if (!CheckpointFile.SafetensorMetadataParsed)
324+
if (
325+
!settingsManager.IsLibraryDirSet
326+
|| new DirectoryPath(settingsManager.ModelsDirectory) is not { Exists: true } modelsDir
327+
)
325328
{
326-
if (
327-
!settingsManager.IsLibraryDirSet
328-
|| new DirectoryPath(settingsManager.ModelsDirectory) is not { Exists: true } modelsDir
329-
)
330-
{
331-
return;
332-
}
333-
334-
try
335-
{
336-
var safetensorPath = CheckpointFile.GetFullPath(modelsDir);
337-
338-
var metadata = await SafetensorMetadata.ParseAsync(safetensorPath);
339-
340-
CheckpointFile.SafetensorMetadataParsed = true;
341-
CheckpointFile.SafetensorMetadata = metadata;
342-
}
343-
catch (Exception ex)
344-
{
345-
logger.LogWarning(ex, "Failed to parse safetensor metadata");
346-
return;
347-
}
329+
return;
348330
}
349331

350-
if (!CheckpointFile.SafetensorMetadataParsed)
332+
SafetensorMetadata? metadata;
333+
try
334+
{
335+
var safetensorPath = CheckpointFile.GetFullPath(modelsDir);
336+
metadata = await SafetensorMetadata.ParseAsync(safetensorPath);
337+
}
338+
catch (Exception ex)
351339
{
340+
logger.LogWarning(ex, "Failed to parse safetensor metadata");
341+
notificationService.Show(
342+
"No Metadata Found",
343+
"This safetensor file does not contain any embedded metadata.",
344+
NotificationType.Warning
345+
);
352346
return;
353347
}
354348

355349
var vm = vmFactory.Get<SafetensorMetadataViewModel>(vm =>
356350
{
357351
vm.ModelName = CheckpointFile.DisplayModelName;
358-
vm.Metadata = CheckpointFile.SafetensorMetadata;
352+
vm.Metadata = metadata;
359353
});
360354

361355
var dialog = vm.GetDialog();

StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,16 @@ or nameof(SortConnectedModelsFirst)
403403

404404
EventManager.Instance.ModelIndexChanged += (_, _) =>
405405
{
406-
RefreshCategories();
407-
ModelsCache.EditDiff(
408-
modelIndexService.ModelIndex.Values.SelectMany(x => x),
409-
LocalModelFile.RelativePathConnectedModelInfoComparer
410-
);
406+
// Dispatch to UI thread to prevent race conditions with Avalonia's selection model.
407+
// The ModelIndexChanged event may be raised from a background thread.
408+
Dispatcher.UIThread.Post(() =>
409+
{
410+
RefreshCategories();
411+
ModelsCache.EditDiff(
412+
modelIndexService.ModelIndex.Values.SelectMany(x => x),
413+
LocalModelFile.RelativePathConnectedModelInfoComparer
414+
);
415+
});
411416
};
412417

413418
AddDisposable(

StabilityMatrix.Avalonia/ViewModels/Dialogs/CivitFileViewModel.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.ObjectModel;
33
using System.Threading.Tasks;
4+
using Avalonia.Threading;
45
using CommunityToolkit.Mvvm.ComponentModel;
56
using CommunityToolkit.Mvvm.Input;
67
using FluentAvalonia.UI.Controls;
@@ -90,9 +91,13 @@ public CivitFileViewModel(
9091

9192
private void ModelIndexChanged(object? sender, EventArgs e)
9293
{
93-
IsInstalled =
94-
CivitFile is { Type: CivitFileType.Model, Hashes.BLAKE3: not null }
95-
&& modelIndexService.ModelIndexBlake3Hashes.Contains(CivitFile.Hashes.BLAKE3);
94+
// Dispatch to UI thread since the event may be raised from a background thread
95+
Dispatcher.UIThread.Post(() =>
96+
{
97+
IsInstalled =
98+
CivitFile is { Type: CivitFileType.Model, Hashes.BLAKE3: not null }
99+
&& modelIndexService.ModelIndexBlake3Hashes.Contains(CivitFile.Hashes.BLAKE3);
100+
});
96101
}
97102

98103
[RelayCommand(CanExecute = nameof(CanExecuteDownload))]

StabilityMatrix.Avalonia/ViewModels/Dialogs/ModelVersionViewModel.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using CommunityToolkit.Mvvm.ComponentModel;
1+
using Avalonia.Threading;
2+
using CommunityToolkit.Mvvm.ComponentModel;
23
using StabilityMatrix.Avalonia.ViewModels.Base;
34
using StabilityMatrix.Core.Helper;
45
using StabilityMatrix.Core.Models.Api;
@@ -42,7 +43,8 @@ public void RefreshInstallStatus()
4243

4344
private void ModelIndexChanged(object? sender, EventArgs e)
4445
{
45-
RefreshInstallStatus();
46+
// Dispatch to UI thread since the event may be raised from a background thread
47+
Dispatcher.UIThread.Post(RefreshInstallStatus);
4648
}
4749

4850
protected override void Dispose(bool disposing)

0 commit comments

Comments
 (0)