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 StabilityMatrix.ViewModels; |
||||||
|
using Wpf.Ui.Controls; |
||||||
|
|
||||||
namespace StabilityMatrix; |
namespace StabilityMatrix; |
||||||
|
|
||||||
public partial class CheckpointManagerPage : Page |
public partial class CheckpointManagerPage : Page |
||||||
{ |
{ |
||||||
|
private readonly CheckpointManagerViewModel viewModel; |
||||||
public CheckpointManagerPage(CheckpointManagerViewModel viewModel) |
public CheckpointManagerPage(CheckpointManagerViewModel viewModel) |
||||||
{ |
{ |
||||||
|
this.viewModel = viewModel; |
||||||
InitializeComponent(); |
InitializeComponent(); |
||||||
DataContext = viewModel; |
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