Browse Source

Add download dialog for controlnet model

pull/333/head
Ionite 1 year ago
parent
commit
4dcbec2657
No known key found for this signature in database
  1. 40
      StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml
  2. 49
      StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml.cs
  3. 8
      StabilityMatrix.Avalonia/Controls/HybridModelTemplateSelector.cs
  4. 21
      StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
  5. 54
      StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs

40
StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml

@ -8,6 +8,8 @@
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference" xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
x:DataType="vmInference:ControlNetCardViewModel"> x:DataType="vmInference:ControlNetCardViewModel">
<Design.PreviewWith> <Design.PreviewWith>
<StackPanel Width="350" Height="400"> <StackPanel Width="350" Height="400">
@ -59,12 +61,48 @@
Text="{x:Static lang:Resources.Label_Model}" Text="{x:Static lang:Resources.Label_Model}"
TextAlignment="Left" /> TextAlignment="Left" />
<ui:FAComboBox <ui:FAComboBox
x:Name="PART_ModelComboBox"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding ClientManager.ControlNetModels}" ItemsSource="{Binding ClientManager.ControlNetModels}"
SelectedItem="{Binding SelectedModel}" SelectedItem="{Binding SelectedModel}"
Theme="{StaticResource FAComboBoxHybridModelTheme}" /> ItemContainerTheme="{StaticResource FAComboBoxItemHybridModelTheme}">
<ui:FAComboBox.Resources>
<input:StandardUICommand
x:Key="RemoteDownloadCommand"
Command="{Binding RemoteDownloadCommand}"/>
</ui:FAComboBox.Resources>
<ui:FAComboBox.DataTemplates>
<controls:HybridModelTemplateSelector>
<DataTemplate DataType="models:HybridModelFile" x:Key="{x:Static models:HybridModelType.Downloadable}">
<Grid ColumnDefinitions="*,Auto">
<TextBlock
Text="{Binding ShortDisplayName}"
Foreground="{DynamicResource ThemeGreyColor}"/>
<Button
Grid.Column="1"
Classes="transparent-full"
Margin="8,0,0,0"
Padding="0">
<fluentIcons:SymbolIcon
VerticalAlignment="Center"
FontSize="18"
Foreground="{DynamicResource ThemeGreyColor}"
IsFilled="True"
Symbol="CloudArrowDown" />
</Button>
</Grid>
</DataTemplate>
<DataTemplate DataType="models:HybridModelFile" x:Key="{x:Static models:HybridModelType.None}">
<TextBlock Text="{Binding ShortDisplayName}"/>
</DataTemplate>
</controls:HybridModelTemplateSelector>
</ui:FAComboBox.DataTemplates>
</ui:FAComboBox>
<sg:SpacedGrid <sg:SpacedGrid
RowDefinitions="Auto,Auto,Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto"

49
StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml.cs

@ -1,7 +1,52 @@
using Avalonia.Controls.Primitives; using AsyncAwaitBestPractices;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;
namespace StabilityMatrix.Avalonia.Controls; namespace StabilityMatrix.Avalonia.Controls;
[Transient] [Transient]
public class ControlNetCard : TemplatedControl { } public class ControlNetCard : TemplatedControl
{
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var upscalerComboBox = e.NameScope.Find("PART_ModelComboBox") as FAComboBox;
upscalerComboBox!.SelectionChanged += UpscalerComboBox_OnSelectionChanged;
}
private void UpscalerComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 0)
return;
var item = e.AddedItems[0];
if (item is HybridModelFile { IsDownloadable: true })
{
// Reset the selection
e.Handled = true;
if (
e.RemovedItems.Count > 0
&& e.RemovedItems[0] is HybridModelFile { IsDownloadable: false } removedItem
)
{
(sender as FAComboBox)!.SelectedItem = removedItem;
}
else
{
(sender as FAComboBox)!.SelectedItem = null;
}
// Show dialog to download the model
(DataContext as ControlNetCardViewModel)!.RemoteDownloadCommand
.ExecuteAsync(item)
.SafeFireAndForget();
}
}
}

8
StabilityMatrix.Avalonia/Controls/HybridModelTemplateSelector.cs

@ -24,15 +24,15 @@ public class HybridModelTemplateSelector : IDataTemplate
// Build the DataTemplate here // Build the DataTemplate here
public Control Build(object? data) public Control Build(object? data)
{ {
if (data is not HybridModelTemplateSelector card) if (data is not HybridModelFile modelFile)
throw new ArgumentException(null, nameof(data)); throw new ArgumentException(null, nameof(data));
if (Templates.TryGetValue(card.Type, out var type)) if (Templates.TryGetValue(modelFile.Type, out var type))
{ {
return type.Build(card)!; return type.Build(modelFile)!;
} }
// Fallback to Local // Fallback to Local
return Templates[HybridModelType.Local].Build(card)!; return Templates[HybridModelType.None].Build(modelFile)!;
} }
} }

21
StabilityMatrix.Avalonia/Services/InferenceClientManager.cs

@ -69,6 +69,9 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
private readonly SourceCache<HybridModelFile, string> controlNetModelsSource = private readonly SourceCache<HybridModelFile, string> controlNetModelsSource =
new(p => p.GetId()); new(p => p.GetId());
private readonly SourceCache<HybridModelFile, string> downloadableControlNetModelsSource =
new(p => p.GetId());
public IObservableCollection<HybridModelFile> ControlNetModels { get; } = public IObservableCollection<HybridModelFile> ControlNetModels { get; } =
new ObservableCollectionExtended<HybridModelFile>(); new ObservableCollectionExtended<HybridModelFile>();
@ -119,10 +122,11 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
controlNetModelsSource controlNetModelsSource
.Connect() .Connect()
.SortBy( .Or(downloadableControlNetModelsSource.Connect())
f => f.ShortDisplayName, .Sort(
SortDirection.Ascending, SortExpressionComparer<HybridModelFile>
SortOptimisations.ComparesImmutableValuesOnly .Ascending(f => f.Type)
.ThenByAscending(f => f.ShortDisplayName)
) )
.DeferUntilLoaded() .DeferUntilLoaded()
.Bind(ControlNetModels) .Bind(ControlNetModels)
@ -274,6 +278,15 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
HybridModelFile.Comparer HybridModelFile.Comparer
); );
// Downloadable ControlNet models
var downloadableControlNets = RemoteModels.ControlNetModels.Where(
u => !modelUpscalersSource.Lookup(u.GetId()).HasValue
);
downloadableControlNetModelsSource.EditDiff(
downloadableControlNets,
HybridModelFile.Comparer
);
// Load local VAE models // Load local VAE models
vaeModelsSource.EditDiff( vaeModelsSource.EditDiff(
modelIndexService modelIndexService

54
StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs

@ -1,10 +1,19 @@
using System.ComponentModel.DataAnnotations; using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.ViewModels.Inference; namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@ -13,6 +22,10 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
[Transient] [Transient]
public partial class ControlNetCardViewModel : LoadableViewModelBase public partial class ControlNetCardViewModel : LoadableViewModelBase
{ {
private readonly ITrackedDownloadService trackedDownloadService;
private readonly ISettingsManager settingsManager;
private readonly ServiceManager<ViewModelBase> vmFactory;
[ObservableProperty] [ObservableProperty]
[Required] [Required]
private HybridModelFile? selectedModel; private HybridModelFile? selectedModel;
@ -41,11 +54,50 @@ public partial class ControlNetCardViewModel : LoadableViewModelBase
public IInferenceClientManager ClientManager { get; } public IInferenceClientManager ClientManager { get; }
public ControlNetCardViewModel( public ControlNetCardViewModel(
ITrackedDownloadService trackedDownloadService,
ISettingsManager settingsManager,
IInferenceClientManager clientManager, IInferenceClientManager clientManager,
ServiceManager<ViewModelBase> vmFactory ServiceManager<ViewModelBase> vmFactory
) )
{ {
this.trackedDownloadService = trackedDownloadService;
this.settingsManager = settingsManager;
this.vmFactory = vmFactory;
ClientManager = clientManager; ClientManager = clientManager;
SelectImageCardViewModel = vmFactory.Get<SelectImageCardViewModel>(); SelectImageCardViewModel = vmFactory.Get<SelectImageCardViewModel>();
} }
[RelayCommand]
private async Task RemoteDownload(HybridModelFile? modelFile)
{
if (modelFile?.DownloadableResource is not { } resource)
return;
var sharedFolderType =
resource.ContextType as SharedFolderType?
?? throw new InvalidOperationException("ContextType is not SharedFolderType");
var confirmDialog = vmFactory.Get<DownloadResourceViewModel>();
confirmDialog.Resource = resource;
confirmDialog.FileName = modelFile.FileName;
if (await confirmDialog.GetDialog().ShowAsync() != ContentDialogResult.Primary)
{
return;
}
var modelsDir = new DirectoryPath(settingsManager.ModelsDirectory).JoinDir(
sharedFolderType.GetStringValue()
);
var download = trackedDownloadService.NewDownload(
resource.Url,
modelsDir.JoinFile(modelFile.FileName)
);
download.ContextAction = new ModelPostDownloadContextAction();
download.Start();
EventManager.Instance.OnToggleProgressFlyout();
}
} }

Loading…
Cancel
Save