diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs index 2f225f855..ba2fc87cc 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFileViewModel.cs @@ -310,50 +310,38 @@ private async Task RenameAsync() [RelayCommand] private async Task OpenSafetensorMetadataViewer() { - if (!CheckpointFile.SafetensorMetadataParsed) + if ( + !settingsManager.IsLibraryDirSet + || new DirectoryPath(settingsManager.ModelsDirectory) is not { Exists: true } modelsDir + ) { - if ( - !settingsManager.IsLibraryDirSet - || new DirectoryPath(settingsManager.ModelsDirectory) is not { Exists: true } modelsDir - ) - { - return; - } + return; + } - try + try + { + var safetensorPath = CheckpointFile.GetFullPath(modelsDir); + var metadata = await SafetensorMetadata.ParseAsync(safetensorPath); + + var vm = vmFactory.Get(vm => { - var safetensorPath = CheckpointFile.GetFullPath(modelsDir); + vm.ModelName = CheckpointFile.DisplayModelName; + vm.Metadata = metadata; + }); - var metadata = await SafetensorMetadata.ParseAsync(safetensorPath); + var dialog = vm.GetDialog(); + dialog.MinDialogHeight = 800; + dialog.MinDialogWidth = 700; + dialog.CloseButtonText = "Close"; + dialog.DefaultButton = ContentDialogButton.Close; - CheckpointFile.SafetensorMetadataParsed = true; - CheckpointFile.SafetensorMetadata = metadata; - } - catch (Exception ex) - { - logger.LogWarning(ex, "Failed to parse safetensor metadata"); - return; - } + await dialog.ShowAsync(); } - - if (!CheckpointFile.SafetensorMetadataParsed) + catch (Exception ex) { + logger.LogWarning(ex, "Failed to parse safetensor metadata"); return; } - - var vm = vmFactory.Get(vm => - { - vm.ModelName = CheckpointFile.DisplayModelName; - vm.Metadata = CheckpointFile.SafetensorMetadata; - }); - - var dialog = vm.GetDialog(); - dialog.MinDialogHeight = 800; - dialog.MinDialogWidth = 700; - dialog.CloseButtonText = "Close"; - dialog.DefaultButton = ContentDialogButton.Close; - - await dialog.ShowAsync(); } [RelayCommand] diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index e68af6d41..1955fd02b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -358,6 +358,7 @@ or nameof(SortConnectedModelsFirst) x ) ) + .DisposeMany() .SortAndBind(Models, comparerObservable) .WhenPropertyChanged(p => p.IsSelected) .Throttle(TimeSpan.FromMilliseconds(50)) @@ -841,11 +842,16 @@ public async Task ImportFilesAsync(IEnumerable files, DirectoryPath dest .FirstOrDefault(x => x.Path == destinationFolder.FullPath); } - public async Task MoveBetweenFolders(List? sourceFiles, DirectoryPath destinationFolder) + public async Task MoveBetweenFolders( + List? sourceFiles, + DirectoryPath destinationFolder + ) { if (sourceFiles != null && sourceFiles.Count() > 0) { - var sourceDirectory = Path.GetDirectoryName(sourceFiles[0].CheckpointFile.GetFullPath(settingsManager.ModelsDirectory)); + var sourceDirectory = Path.GetDirectoryName( + sourceFiles[0].CheckpointFile.GetFullPath(settingsManager.ModelsDirectory) + ); foreach (CheckpointFileViewModel sourceFile in sourceFiles) { if ( @@ -863,13 +869,27 @@ public async Task MoveBetweenFolders(List? sourceFiles, try { - var sourcePath = new FilePath(sourceFile.CheckpointFile.GetFullPath(settingsManager.ModelsDirectory)); + var sourcePath = new FilePath( + sourceFile.CheckpointFile.GetFullPath(settingsManager.ModelsDirectory) + ); var fileNameWithoutExt = Path.GetFileNameWithoutExtension(sourcePath); - var sourceCmInfoPath = Path.Combine(sourcePath.Directory!, $"{fileNameWithoutExt}.cm-info.json"); - var sourcePreviewPath = Path.Combine(sourcePath.Directory!, $"{fileNameWithoutExt}.preview.jpeg"); + var sourceCmInfoPath = Path.Combine( + sourcePath.Directory!, + $"{fileNameWithoutExt}.cm-info.json" + ); + var sourcePreviewPath = Path.Combine( + sourcePath.Directory!, + $"{fileNameWithoutExt}.preview.jpeg" + ); var destinationFilePath = Path.Combine(destinationFolder, sourcePath.Name); - var destinationCmInfoPath = Path.Combine(destinationFolder, $"{fileNameWithoutExt}.cm-info.json"); - var destinationPreviewPath = Path.Combine(destinationFolder, $"{fileNameWithoutExt}.preview.jpeg"); + var destinationCmInfoPath = Path.Combine( + destinationFolder, + $"{fileNameWithoutExt}.cm-info.json" + ); + var destinationPreviewPath = Path.Combine( + destinationFolder, + $"{fileNameWithoutExt}.preview.jpeg" + ); // Move files if (File.Exists(sourcePath)) diff --git a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs index 92ae245a6..129f937b3 100644 --- a/StabilityMatrix.Core/Models/Database/LocalModelFile.cs +++ b/StabilityMatrix.Core/Models/Database/LocalModelFile.cs @@ -154,12 +154,6 @@ public override int GetHashCode() [MemberNotNullWhen(true, nameof(ConnectedModelInfo))] public bool HasCivitMetadata => HasConnectedModel && ConnectedModelInfo.ModelId != null; - [BsonIgnore] - public SafetensorMetadata? SafetensorMetadata { get; set; } - - [BsonIgnore] - public bool SafetensorMetadataParsed { get; set; } - public string GetFullPath(string rootModelDirectory) { return Path.Combine(rootModelDirectory, RelativePath); diff --git a/StabilityMatrix.Core/Services/ModelIndexService.cs b/StabilityMatrix.Core/Services/ModelIndexService.cs index 53943a5cb..48216624d 100644 --- a/StabilityMatrix.Core/Services/ModelIndexService.cs +++ b/StabilityMatrix.Core/Services/ModelIndexService.cs @@ -544,86 +544,6 @@ await liteDbContext ); EventManager.Instance.OnModelIndexChanged(); - - Task.Run(LoadSafetensorMetadataAsync) - .SafeFireAndForget(ex => - { - logger.LogError(ex, "Error loading safetensor metadata"); - }); - } - - private async Task LoadSafetensorMetadataAsync() - { - if (!settingsManager.IsLibraryDirSet) - { - logger.LogTrace("Safetensor metadata loading skipped, library directory not set"); - return; - } - - if (new DirectoryPath(settingsManager.ModelsDirectory) is not { Exists: true } modelsDir) - { - logger.LogTrace("Safetensor metadata loading skipped, model directory does not exist"); - return; - } - - await safetensorMetadataParseLock.WaitAsync().ConfigureAwait(false); - try - { - var stopwatch = Stopwatch.StartNew(); - var readSuccess = 0; - var readFail = 0; - logger.LogInformation("Loading safetensor metadata..."); - - var models = ModelIndex - .Values.SelectMany(x => x) - .Where(m => !m.SafetensorMetadataParsed && m.RelativePath.EndsWith(".safetensors")); - - await Parallel - .ForEachAsync( - models, - new ParallelOptions - { - MaxDegreeOfParallelism = Math.Max(1, Math.Min(Environment.ProcessorCount / 2, 6)), - TaskScheduler = TaskScheduler.Default, - }, - async (model, token) => - { - if (model.SafetensorMetadataParsed) - return; - - if (!model.RelativePath.EndsWith(".safetensors")) - return; - - try - { - var safetensorPath = model.GetFullPath(modelsDir); - var metadata = await SafetensorMetadata - .ParseAsync(safetensorPath) - .ConfigureAwait(false); - model.SafetensorMetadata = metadata; - model.SafetensorMetadataParsed = true; - - Interlocked.Increment(ref readSuccess); - } - catch - { - Interlocked.Increment(ref readFail); - } - } - ) - .ConfigureAwait(false); - - logger.LogInformation( - "Loaded safetensor metadata for {Success} models, failed to load for {Fail} models in {Time:F2}ms", - readSuccess, - readFail, - stopwatch.Elapsed.TotalMilliseconds - ); - } - finally - { - safetensorMetadataParseLock.Release(); - } } ///