Ionite
1 year ago
8 changed files with 346 additions and 112 deletions
@ -1,13 +1,77 @@
|
||||
using System.Windows.Controls; |
||||
using System.Diagnostics; |
||||
using System.Threading; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Media; |
||||
using System.Windows.Media.Effects; |
||||
using StabilityMatrix.ViewModels; |
||||
using Wpf.Ui.Controls; |
||||
|
||||
namespace StabilityMatrix; |
||||
|
||||
public partial class CheckpointManagerPage : Page |
||||
{ |
||||
private readonly CheckpointManagerViewModel viewModel; |
||||
public CheckpointManagerPage(CheckpointManagerViewModel viewModel) |
||||
{ |
||||
this.viewModel = viewModel; |
||||
InitializeComponent(); |
||||
DataContext = viewModel; |
||||
} |
||||
|
||||
private void FolderCard_OnPreviewDrop(object sender, DragEventArgs e) |
||||
{ |
||||
Debug.WriteLine($"PreviewDrop: {sender}, {e}"); |
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop)) |
||||
{ |
||||
var files = e.Data.GetData(DataFormats.FileDrop) as string[]; |
||||
var firstFile = files?[0]; |
||||
// Make title by title casing the file name |
||||
var title = System.IO.Path.GetFileNameWithoutExtension(firstFile); |
||||
title = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(title!); |
||||
viewModel.CheckpointFolders[0].CheckpointFiles.Add(new() |
||||
{ |
||||
Title = title, |
||||
FileName = firstFile!, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
private void FolderCard_OnDrop(object sender, DragEventArgs e) |
||||
{ |
||||
Debug.WriteLine($"Drop: {sender}, {e}"); |
||||
} |
||||
|
||||
private void FolderCard_OnPreviewDragOver(object sender, DragEventArgs e) |
||||
{ |
||||
Debug.WriteLine($"PreviewDragOver: {sender}, {e}"); |
||||
} |
||||
|
||||
private void FolderCard_OnPreviewDragLeave(object sender, DragEventArgs e) |
||||
{ |
||||
var senderCard = (CardExpander) sender; |
||||
senderCard.Header = "Stable Diffusion"; |
||||
Debug.WriteLine($"PreviewDragLeave: {sender}, {e}"); |
||||
} |
||||
|
||||
private void FolderCard_OnPreviewDragEnter(object sender, DragEventArgs e) |
||||
{ |
||||
var senderCard = (CardExpander) sender; |
||||
senderCard.Header = "Drag here to add a checkpoint"; |
||||
// Apply a hover-over effect |
||||
senderCard.Effect = new DropShadowEffect |
||||
{ |
||||
Color = Colors.Black, |
||||
Direction = 0, |
||||
ShadowDepth = 0, |
||||
Opacity = 0.5, |
||||
BlurRadius = 10 |
||||
}; |
||||
Debug.WriteLine($"PreviewDragEnter: {sender}, {e}"); |
||||
} |
||||
|
||||
private async void CheckpointManagerPage_OnLoaded(object sender, RoutedEventArgs e) |
||||
{ |
||||
await viewModel.OnLoaded(); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,59 @@
|
||||
using System.ComponentModel; |
||||
using StabilityMatrix.ViewModels; |
||||
|
||||
namespace StabilityMatrix.DesignData; |
||||
|
||||
[DesignOnly(true)] |
||||
public class MockCheckpointManagerViewModel : CheckpointManagerViewModel |
||||
{ |
||||
public MockCheckpointManagerViewModel() |
||||
{ |
||||
CheckpointFolders = new() |
||||
{ |
||||
new() |
||||
{ |
||||
Title = "Stable Diffusion", |
||||
CheckpointFiles = new() |
||||
{ |
||||
new() |
||||
{ |
||||
Title = "Stable Diffusion v1.5", |
||||
FileName = "v1-5-pruned-emaonly.safetensors", |
||||
}, |
||||
new() |
||||
{ |
||||
Title = "Scenery Mix", |
||||
FileName = "scenery-mix.pt", |
||||
}, |
||||
new() |
||||
{ |
||||
Title = "Example Realistic", |
||||
FileName = "exr-v21.safetensors", |
||||
}, |
||||
new() |
||||
{ |
||||
Title = "Painting e12", |
||||
FileName = "painting-e12.pt", |
||||
}, |
||||
} |
||||
}, |
||||
new() |
||||
{ |
||||
Title = "Lora", |
||||
CheckpointFiles = new() |
||||
{ |
||||
new() |
||||
{ |
||||
Title = "Detail Tweaker LoRA", |
||||
FileName = "add_detail.safetensors", |
||||
}, |
||||
new() |
||||
{ |
||||
Title = "Armor Suit LoRa", |
||||
FileName = "ArmorSuit_v1.safetensors", |
||||
}, |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -1,16 +0,0 @@
|
||||
using System.Windows.Media.Imaging; |
||||
using CommunityToolkit.Mvvm.ComponentModel; |
||||
|
||||
namespace StabilityMatrix.Models; |
||||
|
||||
public partial class CheckpointCard : ObservableObject |
||||
{ |
||||
[ObservableProperty] |
||||
private BitmapImage? image; |
||||
|
||||
[ObservableProperty] |
||||
private string name; |
||||
|
||||
[ObservableProperty] |
||||
private string fileName; |
||||
} |
@ -0,0 +1,88 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Immutable; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Windows.Media.Imaging; |
||||
using CommunityToolkit.Mvvm.ComponentModel; |
||||
|
||||
namespace StabilityMatrix.Models; |
||||
|
||||
public partial class CheckpointFile : ObservableObject |
||||
{ |
||||
/// <summary> |
||||
/// Absolute path to the checkpoint file. |
||||
/// </summary> |
||||
[ObservableProperty] |
||||
private string filePath; |
||||
|
||||
/// <summary> |
||||
/// Custom title for UI. |
||||
/// </summary> |
||||
[ObservableProperty] |
||||
private string title; |
||||
|
||||
[ObservableProperty] |
||||
private string? previewImagePath; |
||||
|
||||
[ObservableProperty] |
||||
private BitmapImage? previewImage; |
||||
|
||||
public bool IsPreviewImageLoaded => PreviewImage != null; |
||||
|
||||
[ObservableProperty] |
||||
private string fileName; |
||||
|
||||
private static readonly string[] SupportedCheckpointExtensions = { ".safetensors", ".pt" }; |
||||
private static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg" }; |
||||
|
||||
|
||||
/// <summary> |
||||
/// Indexes directory and yields all checkpoint files. |
||||
/// First we match all files with supported extensions. |
||||
/// If found, we also look for |
||||
/// - {filename}.preview.{image-extensions} |
||||
/// </summary> |
||||
public static IEnumerable<CheckpointFile> FromDirectoryIndex(string directory, SearchOption searchOption = SearchOption.TopDirectoryOnly) |
||||
{ |
||||
// Get all files with supported extensions |
||||
var allExtensions = SupportedCheckpointExtensions.Concat(SupportedImageExtensions).ToImmutableHashSet(); |
||||
|
||||
var files = allExtensions.AsParallel() |
||||
.SelectMany(pattern => Directory.EnumerateFiles(directory, $"*{pattern}", searchOption)).ToDictionary<string, string>(Path.GetFileName); |
||||
|
||||
foreach (var file in files.Keys.Where(k => SupportedCheckpointExtensions.Contains(Path.GetExtension(k)))) |
||||
{ |
||||
var checkpointFile = new CheckpointFile |
||||
{ |
||||
Title = Path.GetFileNameWithoutExtension(file), |
||||
FilePath = Path.Combine(directory, file), |
||||
FileName = file, |
||||
}; |
||||
|
||||
// Check for preview image |
||||
var previewImage = SupportedImageExtensions.Select(ext => $"{checkpointFile.FileName}.preview.{ext}").FirstOrDefault(files.ContainsKey); |
||||
if (previewImage != null) |
||||
{ |
||||
checkpointFile.PreviewImage = new BitmapImage(new Uri(Path.Combine(directory, previewImage))); |
||||
} |
||||
|
||||
yield return checkpointFile; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Index with progress reporting. |
||||
/// </summary> |
||||
public static IEnumerable<CheckpointFile> FromDirectoryIndex(string directory, IProgress<ProgressReport> progress, |
||||
SearchOption searchOption = SearchOption.TopDirectoryOnly) |
||||
{ |
||||
var current = 0ul; |
||||
foreach (var checkpointFile in FromDirectoryIndex(directory, searchOption)) |
||||
{ |
||||
current++; |
||||
progress.Report(new ProgressReport(current, "Indexing", checkpointFile.FileName)); |
||||
yield return checkpointFile; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,49 @@
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Threading.Tasks; |
||||
using CommunityToolkit.Mvvm.ComponentModel; |
||||
|
||||
namespace StabilityMatrix.Models; |
||||
|
||||
public partial class CheckpointFolder : ObservableObject |
||||
{ |
||||
/// <summary> |
||||
/// Absolute path to the folder. |
||||
/// </summary> |
||||
[ObservableProperty] |
||||
private string directoryPath; |
||||
|
||||
/// <summary> |
||||
/// Custom title for UI. |
||||
/// </summary> |
||||
[ObservableProperty] |
||||
private string title; |
||||
|
||||
/// <summary> |
||||
/// State of indexing. |
||||
/// </summary> |
||||
[ObservableProperty] |
||||
private LoadState indexState = LoadState.NotLoaded; |
||||
|
||||
public ObservableCollection<CheckpointFile> CheckpointFiles { get; set; } = new(); |
||||
|
||||
/// <summary> |
||||
/// Indexes the folder for checkpoint files. |
||||
/// </summary> |
||||
public async Task IndexAsync(IProgress<ProgressReport>? progress = default) |
||||
{ |
||||
IndexState = LoadState.Loading; |
||||
var checkpointFiles = await (progress switch |
||||
{ |
||||
null => Task.Run(() => CheckpointFile.FromDirectoryIndex(DirectoryPath)), |
||||
_ => Task.Run(() => CheckpointFile.FromDirectoryIndex(DirectoryPath, progress)) |
||||
}); |
||||
|
||||
CheckpointFiles.Clear(); |
||||
foreach (var checkpointFile in checkpointFiles) |
||||
{ |
||||
CheckpointFiles.Add(checkpointFile); |
||||
} |
||||
IndexState = LoadState.Loaded; |
||||
} |
||||
} |
@ -1,34 +0,0 @@
|
||||
using System.Collections.ObjectModel; |
||||
using CommunityToolkit.Mvvm.ComponentModel; |
||||
|
||||
namespace StabilityMatrix.Models; |
||||
|
||||
public partial class CheckpointFolderCard : ObservableObject |
||||
{ |
||||
[ObservableProperty] |
||||
private string name; |
||||
|
||||
public ObservableCollection<CheckpointCard> CheckpointCards { get; set; } = new() |
||||
{ |
||||
new CheckpointCard |
||||
{ |
||||
Name = "Stable Diffusion v1.5", |
||||
FileName = "v1-5-pruned-emaonly.safetensors", |
||||
}, |
||||
new CheckpointCard |
||||
{ |
||||
Name = "Stable Diffusion v1.5 (EMA)", |
||||
FileName = "v1-5-emaonly.safetensors", |
||||
}, |
||||
new CheckpointCard |
||||
{ |
||||
Name = "Stable Diffusion v1.5 (EMA, 512x512)", |
||||
FileName = "v1-5-emaonly-512.safetensors", |
||||
}, |
||||
new CheckpointCard |
||||
{ |
||||
Name = "Stable Diffusion v2.0", |
||||
FileName = "v2-0-pruned-emaonly.safetensors", |
||||
}, |
||||
}; |
||||
} |
Loading…
Reference in new issue