Skip to content

Commit 27b30f1

Browse files
authored
Merge pull request #1140 from ionite34/fixes-n-stuff
Fixed AI Toolkit error on job start, show at least 30 results in civit…
2 parents dfac5ed + e1b752e commit 27b30f1

File tree

6 files changed

+122
-23
lines changed

6 files changed

+122
-23
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ 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.1
9+
### Fixed
10+
- Fixed [#1372](https://github.com/LykosAI/StabilityMatrix/issues/1372) - LiteAsyncException upon starting Stability Matrix v2.15.0
11+
- Fixed [#1391](https://github.com/LykosAI/StabilityMatrix/issues/1391) - "Failed to parse" error when upgrading pip packages with extra index url
12+
- Fixed "cannot access local variable 'job' where it is not associated with a value" error when running jobs in AI Toolkit
13+
- Fixed Civitai browser not always returning at least 30 results when possible on initial search
14+
815
## v2.15.0
916
### Added
1017
- Added new package - [AI Toolkit](https://github.com/ostris/ai-toolkit/)

StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
5252

5353
private readonly SourceCache<OrderedValue<CivitModel>, int> modelCache = new(static ov => ov.Value.Id);
5454

55+
private const int TargetPageItemCount = 30;
56+
5557
[ObservableProperty]
5658
private IObservableCollection<CheckpointBrowserCardViewModel> modelCards =
5759
new ObservableCollectionExtended<CheckpointBrowserCardViewModel>();
@@ -453,8 +455,46 @@ private async Task CivitModelQuery(CivitModelsRequest request, bool isInfiniteSc
453455
}
454456
else
455457
{
456-
modelsResponse = await civitApi.GetModels(request);
457-
models = modelsResponse.Items;
458+
// Auto-paginate via cursor until we fill the target page size or run out
459+
var collectedById = new HashSet<int>();
460+
var targetCount = request.Limit ?? TargetPageItemCount;
461+
var safetyGuard = 0;
462+
463+
while (true)
464+
{
465+
var resp = await civitApi.GetModels(request);
466+
modelsResponse = resp;
467+
468+
if (resp.Items != null)
469+
{
470+
foreach (var item in resp.Items)
471+
{
472+
if (collectedById.Add(item.Id))
473+
{
474+
models.Add(item);
475+
}
476+
}
477+
}
478+
479+
// Check how many items survive local filtering
480+
var filteredCount = models
481+
.Where(m => m.Type.ConvertTo<SharedFolderType>() > 0)
482+
.Count(m => m.Mode == null);
483+
484+
var next = resp.Metadata?.NextCursor;
485+
if (filteredCount >= targetCount || string.IsNullOrEmpty(next))
486+
{
487+
break;
488+
}
489+
490+
request.Cursor = next;
491+
492+
if (++safetyGuard >= 10)
493+
{
494+
// Avoid unbounded looping on unexpected cursors
495+
break;
496+
}
497+
}
458498
}
459499

460500
if (models is null)
@@ -634,6 +674,7 @@ private async Task SearchModels(bool isInfiniteScroll = false)
634674
// Build request
635675
var modelRequest = new CivitModelsRequest
636676
{
677+
Limit = TargetPageItemCount + 20, // Fetch a few extra to account for local filtering
637678
Nsfw = "true", // Handled by local view filter
638679
Sort = SortMode,
639680
Period = SelectedPeriod,

StabilityMatrix.Avalonia/ViewModels/Dialogs/PythonPackagesViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ private async Task UpgradePackageVersion(
239239

240240
if (extraIndexUrl != null)
241241
{
242-
args = args.AddArg(("--extra-index-url", extraIndexUrl));
242+
args = args.AddArgs("--extra-index-url", extraIndexUrl);
243243
}
244244

245245
var steps = new List<IPackageStep>

StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ public override void LoadStateFromJsonObject(JsonObject state)
309309
? HybridModelFile.None
310310
: ClientManager.ClipModels.FirstOrDefault(x => x.RelativePath == model.SelectedClip3Name);
311311

312-
SelectedClip4 = model.SelectedClip3Name is null
312+
SelectedClip4 = model.SelectedClip4Name is null
313313
? HybridModelFile.None
314314
: ClientManager.ClipModels.FirstOrDefault(x => x.RelativePath == model.SelectedClip4Name);
315315

StabilityMatrix.Core/Database/LiteDbContext.cs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using StabilityMatrix.Core.Models.Api;
1111
using StabilityMatrix.Core.Models.Configs;
1212
using StabilityMatrix.Core.Models.Database;
13+
using StabilityMatrix.Core.Models.FileInterfaces;
1314
using StabilityMatrix.Core.Services;
1415

1516
namespace StabilityMatrix.Core.Database;
@@ -63,18 +64,25 @@ IOptions<DebugOptions> debugOptions
6364

6465
private LiteDatabaseAsync CreateDatabase()
6566
{
66-
LiteDatabaseAsync? db = null;
67+
// Try at most twice:
68+
// - attempt 0: open/repair if needed
69+
// - on "Detected loop in FindAll": dispose, delete file, try once more
70+
const int maxAttempts = 2;
71+
var dbPath = Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db");
6772

68-
if (debugOptions.TempDatabase)
73+
for (var attempt = 0; attempt < maxAttempts; attempt++)
6974
{
70-
db = new LiteDatabaseAsync(":temp:");
71-
}
72-
else
73-
{
74-
// Attempt to create connection, might be in use
75+
LiteDatabaseAsync? db = null;
76+
7577
try
7678
{
77-
var dbPath = Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db");
79+
if (debugOptions.TempDatabase)
80+
{
81+
db = new LiteDatabaseAsync(":temp:");
82+
RegisterRefs();
83+
return db;
84+
}
85+
7886
db = new LiteDatabaseAsync(
7987
new ConnectionString { Filename = dbPath, Connection = ConnectionType.Shared }
8088
);
@@ -86,33 +94,73 @@ private LiteDatabaseAsync CreateDatabase()
8694
"Database collation is not Ordinal ({SortOption}), rebuilding...",
8795
sortOption
8896
);
89-
9097
var options = new RebuildOptions
9198
{
9299
Collation = new Collation(CultureInfo.InvariantCulture.LCID, CompareOptions.Ordinal),
93100
};
94-
95101
db.RebuildAsync(options).GetAwaiter().GetResult();
96102
}
103+
104+
RegisterRefs();
105+
return db;
97106
}
98-
catch (IOException e)
107+
catch (LiteAsyncException ex)
108+
when (ex.InnerException is LiteException e
109+
&& e.Message.Contains("Detected loop in FindAll", StringComparison.OrdinalIgnoreCase)
110+
)
111+
{
112+
logger.LogWarning("Database corruption detected ({Message}), rebuilding...", e.Message);
113+
114+
try
115+
{
116+
db?.Dispose();
117+
}
118+
catch
119+
{
120+
// ignored
121+
}
122+
123+
try
124+
{
125+
// Backup then delete, in case we want to inspect later.
126+
var corruptPath = dbPath + ".old-" + DateTime.UtcNow.ToString("yyyyMMddHHmmss");
127+
if (File.Exists(dbPath))
128+
{
129+
File.Copy(dbPath, corruptPath, overwrite: false);
130+
File.Delete(dbPath);
131+
}
132+
}
133+
catch (Exception delEx)
134+
{
135+
logger.LogWarning("Failed to delete corrupt DB: {Message}", delEx.Message);
136+
// If we can't delete, no point retrying; break to fallback.
137+
break;
138+
}
139+
}
140+
catch (IOException ioEx)
99141
{
100142
logger.LogWarning(
101143
"Database in use or not accessible ({Message}), using temporary database",
102-
e.Message
144+
ioEx.Message
103145
);
146+
break; // fall through to temp
104147
}
105148
}
106149

107150
// Fallback to temporary database
108-
db ??= new LiteDatabaseAsync(":temp:");
109-
110-
// Register reference fields
111-
LiteDBExtensions.Register<CivitModel, CivitModelVersion>(m => m.ModelVersions, "CivitModelVersions");
112-
LiteDBExtensions.Register<CivitModelQueryCacheEntry, CivitModel>(e => e.Items, "CivitModels");
113-
LiteDBExtensions.Register<LocalModelFile, CivitModel>(e => e.LatestModelInfo, "CivitModels");
151+
var tempDb = new LiteDatabaseAsync(":temp:");
152+
RegisterRefs();
153+
return tempDb;
114154

115-
return db;
155+
void RegisterRefs()
156+
{
157+
LiteDBExtensions.Register<CivitModel, CivitModelVersion>(
158+
m => m.ModelVersions,
159+
"CivitModelVersions"
160+
);
161+
LiteDBExtensions.Register<CivitModelQueryCacheEntry, CivitModel>(e => e.Items, "CivitModels");
162+
LiteDBExtensions.Register<LocalModelFile, CivitModel>(e => e.LatestModelInfo, "CivitModels");
163+
}
116164
}
117165

118166
public async Task<(CivitModel?, CivitModelVersion?)> FindCivitModelFromFileHashAsync(string hashBlake3)

StabilityMatrix.Core/Models/Packages/AiToolkit.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ await npmProcess
183183

184184
private ImmutableDictionary<string, string> GetEnvVars(ImmutableDictionary<string, string> env)
185185
{
186+
// set SETUPTOOLS_USE_DISTUTILS=setuptools to avoid job errors
187+
env = env.SetItem("SETUPTOOLS_USE_DISTUTILS", "setuptools");
188+
186189
var pathBuilder = new EnvPathBuilder();
187190

188191
if (env.TryGetValue("PATH", out var value))

0 commit comments

Comments
 (0)