JT
12 months ago
23 changed files with 1038 additions and 14 deletions
@ -0,0 +1,122 @@ |
|||||||
|
<Styles xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:controls="using:StabilityMatrix.Avalonia.Controls" |
||||||
|
x:DataType="video:SvdImgToVidConditioningViewModel" |
||||||
|
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
|
xmlns:video="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference.Video" |
||||||
|
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" |
||||||
|
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"> |
||||||
|
<Design.PreviewWith> |
||||||
|
<Grid MinWidth="400"> |
||||||
|
<controls:VideoGenerationSettingsCard DataContext="{x:Static mocks:DesignData.SvdImgToVidConditioningViewModel}" /> |
||||||
|
</Grid> |
||||||
|
</Design.PreviewWith> |
||||||
|
|
||||||
|
<Style Selector="controls|VideoGenerationSettingsCard"> |
||||||
|
<!-- Set Defaults --> |
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" /> |
||||||
|
<Setter Property="Template"> |
||||||
|
<ControlTemplate> |
||||||
|
<controls:Card Padding="8" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"> |
||||||
|
<Grid Margin="4" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, *"> |
||||||
|
<TextBlock |
||||||
|
Grid.Row="0" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,0,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Frames" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Grid.Row="0" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding NumFrames}" |
||||||
|
Margin="8,0,0,0" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,8,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Frames Per Second" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding Fps}" |
||||||
|
Margin="8,8,0,0" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Grid.Row="2" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,8,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Min CFG" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Margin="8,8,0,0" |
||||||
|
Grid.Row="2" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding MinCfg}" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Margin="0,8,8,0" |
||||||
|
Grid.Row="3" |
||||||
|
Grid.Column="0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Motion Bucket ID" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Margin="8,8,0,0" |
||||||
|
Grid.Row="3" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding MotionBucketId}" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<StackPanel Grid.Column="0" |
||||||
|
Grid.ColumnSpan="2" |
||||||
|
Grid.Row="4" |
||||||
|
Margin="0,16,0,0"> |
||||||
|
<Grid ColumnDefinitions="*,Auto"> |
||||||
|
<TextBlock |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Augmentation Level"/> |
||||||
|
<controls1:NumberBox |
||||||
|
Grid.Column="1" |
||||||
|
Margin="4,0,0,0" |
||||||
|
ValidationMode="InvalidInputOverwritten" |
||||||
|
SmallChange="0.01" |
||||||
|
SimpleNumberFormat="F2" |
||||||
|
Value="{Binding AugmentationLevel}" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
MinWidth="100" |
||||||
|
SpinButtonPlacementMode="Compact"/> |
||||||
|
</Grid> |
||||||
|
<Slider |
||||||
|
Minimum="0" |
||||||
|
Maximum="10" |
||||||
|
Value="{Binding AugmentationLevel}" |
||||||
|
TickFrequency="1" |
||||||
|
Margin="0,0,0,-4" |
||||||
|
TickPlacement="BottomRight"/> |
||||||
|
</StackPanel> |
||||||
|
</Grid> |
||||||
|
</controls:Card> |
||||||
|
</ControlTemplate> |
||||||
|
</Setter> |
||||||
|
</Style> |
||||||
|
</Styles> |
@ -0,0 +1,7 @@ |
|||||||
|
using Avalonia.Controls.Primitives; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
[Transient] |
||||||
|
public class VideoGenerationSettingsCard : TemplatedControl { } |
@ -0,0 +1,86 @@ |
|||||||
|
<Styles xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:controls="using:StabilityMatrix.Avalonia.Controls" |
||||||
|
x:DataType="video:VideoOutputSettingsCardViewModel" |
||||||
|
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
|
xmlns:video="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference.Video" |
||||||
|
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" |
||||||
|
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"> |
||||||
|
<Design.PreviewWith> |
||||||
|
<Grid MinWidth="400"> |
||||||
|
<controls:VideoOutputSettingsCard DataContext="{x:Static mocks:DesignData.SvdImgToVidConditioningViewModel}" /> |
||||||
|
</Grid> |
||||||
|
</Design.PreviewWith> |
||||||
|
|
||||||
|
<Style Selector="controls|VideoOutputSettingsCard"> |
||||||
|
<!-- Set Defaults --> |
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" /> |
||||||
|
<Setter Property="Template"> |
||||||
|
<ControlTemplate> |
||||||
|
<controls:Card Padding="8" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"> |
||||||
|
<Grid Margin="4" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, *"> |
||||||
|
<TextBlock |
||||||
|
Grid.Row="0" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,0,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Frames Per Second" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Grid.Row="0" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding Fps}" |
||||||
|
Margin="8,0,0,0" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,8,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Lossless" /> |
||||||
|
<CheckBox |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="1" |
||||||
|
IsChecked="{Binding Lossless}" |
||||||
|
Margin="8,8,0,0" |
||||||
|
HorizontalAlignment="Stretch"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Grid.Row="2" |
||||||
|
Grid.Column="0" |
||||||
|
Margin="0,8,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Quality" /> |
||||||
|
<controls1:NumberBox |
||||||
|
Margin="8,8,0,0" |
||||||
|
Grid.Row="2" |
||||||
|
Grid.Column="1" |
||||||
|
SelectionHighlightColor="Transparent" |
||||||
|
Value="{Binding Quality}" |
||||||
|
SimpleNumberFormat="F0" |
||||||
|
SmallChange="1" |
||||||
|
Maximum="100" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
SpinButtonPlacementMode="Inline"/> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Margin="0,8,8,0" |
||||||
|
Grid.Row="3" |
||||||
|
Grid.Column="0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Method" /> |
||||||
|
<ComboBox Grid.Row="3" Grid.Column="1" |
||||||
|
Margin="8,8,0,0" |
||||||
|
MinWidth="100" |
||||||
|
ItemsSource="{Binding AvailableMethods}" |
||||||
|
SelectedIndex="{Binding SelectedMethod}"/> |
||||||
|
</Grid> |
||||||
|
</controls:Card> |
||||||
|
</ControlTemplate> |
||||||
|
</Setter> |
||||||
|
</Style> |
||||||
|
</Styles> |
@ -0,0 +1,7 @@ |
|||||||
|
using Avalonia.Controls.Primitives; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
[Transient] |
||||||
|
public class VideoOutputSettingsCard : TemplatedControl { } |
@ -0,0 +1,8 @@ |
|||||||
|
namespace StabilityMatrix.Avalonia.Models.Inference; |
||||||
|
|
||||||
|
public enum VideoOutputMethod |
||||||
|
{ |
||||||
|
Fastest, |
||||||
|
Default, |
||||||
|
Slowest, |
||||||
|
} |
@ -0,0 +1,243 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
using System.Drawing; |
||||||
|
using System.Linq; |
||||||
|
using System.Text.Json.Nodes; |
||||||
|
using System.Text.Json.Serialization; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using NLog; |
||||||
|
using StabilityMatrix.Avalonia.Extensions; |
||||||
|
using StabilityMatrix.Avalonia.Models; |
||||||
|
using StabilityMatrix.Avalonia.Models.Inference; |
||||||
|
using StabilityMatrix.Avalonia.Services; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Inference.Modules; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Inference.Video; |
||||||
|
using StabilityMatrix.Avalonia.Views.Inference; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.Nodes; |
||||||
|
using StabilityMatrix.Core.Services; |
||||||
|
|
||||||
|
#pragma warning disable CS0657 // Not a valid attribute location for this declaration |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Inference; |
||||||
|
|
||||||
|
[View(typeof(InferenceImageToVideoView), persistent: true)] |
||||||
|
[ManagedService] |
||||||
|
[Transient] |
||||||
|
public class InferenceImageToVideoViewModel |
||||||
|
: InferenceGenerationViewModelBase, |
||||||
|
IParametersLoadableState |
||||||
|
{ |
||||||
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); |
||||||
|
|
||||||
|
private readonly INotificationService notificationService; |
||||||
|
private readonly IModelIndexService modelIndexService; |
||||||
|
|
||||||
|
[JsonIgnore] |
||||||
|
public StackCardViewModel StackCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("Model")] |
||||||
|
public ImgToVidModelCardViewModel ModelCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("Sampler")] |
||||||
|
public SamplerCardViewModel SamplerCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("BatchSize")] |
||||||
|
public BatchSizeCardViewModel BatchSizeCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("Seed")] |
||||||
|
public SeedCardViewModel SeedCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("ImageLoader")] |
||||||
|
public SelectImageCardViewModel SelectImageCardViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("Conditioning")] |
||||||
|
public SvdImgToVidConditioningViewModel SvdImgToVidConditioningViewModel { get; } |
||||||
|
|
||||||
|
[JsonPropertyName("VideoOutput")] |
||||||
|
public VideoOutputSettingsCardViewModel VideoOutputSettingsCardViewModel { get; } |
||||||
|
|
||||||
|
public InferenceImageToVideoViewModel( |
||||||
|
INotificationService notificationService, |
||||||
|
IInferenceClientManager inferenceClientManager, |
||||||
|
ISettingsManager settingsManager, |
||||||
|
ServiceManager<ViewModelBase> vmFactory, |
||||||
|
IModelIndexService modelIndexService |
||||||
|
) |
||||||
|
: base(vmFactory, inferenceClientManager, notificationService, settingsManager) |
||||||
|
{ |
||||||
|
this.notificationService = notificationService; |
||||||
|
this.modelIndexService = modelIndexService; |
||||||
|
|
||||||
|
// Get sub view models from service manager |
||||||
|
|
||||||
|
SeedCardViewModel = vmFactory.Get<SeedCardViewModel>(); |
||||||
|
SeedCardViewModel.GenerateNewSeed(); |
||||||
|
|
||||||
|
ModelCardViewModel = vmFactory.Get<ImgToVidModelCardViewModel>(); |
||||||
|
|
||||||
|
SamplerCardViewModel = vmFactory.Get<SamplerCardViewModel>(samplerCard => |
||||||
|
{ |
||||||
|
samplerCard.IsDimensionsEnabled = true; |
||||||
|
samplerCard.IsCfgScaleEnabled = true; |
||||||
|
samplerCard.IsSamplerSelectionEnabled = true; |
||||||
|
samplerCard.IsSchedulerSelectionEnabled = true; |
||||||
|
}); |
||||||
|
|
||||||
|
BatchSizeCardViewModel = vmFactory.Get<BatchSizeCardViewModel>(); |
||||||
|
|
||||||
|
SelectImageCardViewModel = vmFactory.Get<SelectImageCardViewModel>(); |
||||||
|
SvdImgToVidConditioningViewModel = vmFactory.Get<SvdImgToVidConditioningViewModel>(); |
||||||
|
VideoOutputSettingsCardViewModel = vmFactory.Get<VideoOutputSettingsCardViewModel>(); |
||||||
|
|
||||||
|
StackCardViewModel = vmFactory.Get<StackCardViewModel>(); |
||||||
|
StackCardViewModel.AddCards( |
||||||
|
ModelCardViewModel, |
||||||
|
SvdImgToVidConditioningViewModel, |
||||||
|
SamplerCardViewModel, |
||||||
|
SeedCardViewModel, |
||||||
|
VideoOutputSettingsCardViewModel, |
||||||
|
BatchSizeCardViewModel |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
protected override void BuildPrompt(BuildPromptEventArgs args) |
||||||
|
{ |
||||||
|
base.BuildPrompt(args); |
||||||
|
|
||||||
|
var builder = args.Builder; |
||||||
|
|
||||||
|
builder.Connections.Seed = args.SeedOverride switch |
||||||
|
{ |
||||||
|
{ } seed => Convert.ToUInt64(seed), |
||||||
|
_ => Convert.ToUInt64(SeedCardViewModel.Seed) |
||||||
|
}; |
||||||
|
|
||||||
|
// Load models |
||||||
|
ModelCardViewModel.ApplyStep(args); |
||||||
|
|
||||||
|
// Setup latent from image |
||||||
|
var imageLoad = builder.Nodes.AddTypedNode( |
||||||
|
new ComfyNodeBuilder.LoadImage |
||||||
|
{ |
||||||
|
Name = builder.Nodes.GetUniqueName("ControlNet_LoadImage"), |
||||||
|
Image = |
||||||
|
SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference") |
||||||
|
?? throw new ValidationException() |
||||||
|
} |
||||||
|
); |
||||||
|
builder.Connections.Primary = imageLoad.Output1; |
||||||
|
builder.Connections.PrimarySize = |
||||||
|
SelectImageCardViewModel.CurrentBitmapSize |
||||||
|
?? new Size(SamplerCardViewModel.Width, SamplerCardViewModel.Height); |
||||||
|
|
||||||
|
// Setup img2vid stuff |
||||||
|
// Set width & height from SamplerCard |
||||||
|
SvdImgToVidConditioningViewModel.Width = SamplerCardViewModel.Width; |
||||||
|
SvdImgToVidConditioningViewModel.Height = SamplerCardViewModel.Height; |
||||||
|
SvdImgToVidConditioningViewModel.ApplyStep(args); |
||||||
|
|
||||||
|
// Setup Sampler and Refiner if enabled |
||||||
|
SamplerCardViewModel.ApplyStep(args); |
||||||
|
|
||||||
|
// Animated webp output |
||||||
|
VideoOutputSettingsCardViewModel.ApplyStep(args); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
protected override IEnumerable<ImageSource> GetInputImages() |
||||||
|
{ |
||||||
|
if (SelectImageCardViewModel.ImageSource is { } image) |
||||||
|
{ |
||||||
|
yield return image; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
protected override async Task GenerateImageImpl( |
||||||
|
GenerateOverrides overrides, |
||||||
|
CancellationToken cancellationToken |
||||||
|
) |
||||||
|
{ |
||||||
|
if (!await CheckClientConnectedWithPrompt() || !ClientManager.IsConnected) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// If enabled, randomize the seed |
||||||
|
var seedCard = StackCardViewModel.GetCard<SeedCardViewModel>(); |
||||||
|
if (overrides is not { UseCurrentSeed: true } && seedCard.IsRandomizeEnabled) |
||||||
|
{ |
||||||
|
seedCard.GenerateNewSeed(); |
||||||
|
} |
||||||
|
|
||||||
|
var batches = BatchSizeCardViewModel.BatchCount; |
||||||
|
|
||||||
|
var batchArgs = new List<ImageGenerationEventArgs>(); |
||||||
|
|
||||||
|
for (var i = 0; i < batches; i++) |
||||||
|
{ |
||||||
|
var seed = seedCard.Seed + i; |
||||||
|
|
||||||
|
var buildPromptArgs = new BuildPromptEventArgs |
||||||
|
{ |
||||||
|
Overrides = overrides, |
||||||
|
SeedOverride = seed |
||||||
|
}; |
||||||
|
BuildPrompt(buildPromptArgs); |
||||||
|
|
||||||
|
var generationArgs = new ImageGenerationEventArgs |
||||||
|
{ |
||||||
|
Client = ClientManager.Client, |
||||||
|
Nodes = buildPromptArgs.Builder.ToNodeDictionary(), |
||||||
|
OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(), |
||||||
|
Parameters = SaveStateToParameters(new GenerationParameters()), |
||||||
|
Project = InferenceProjectDocument.FromLoadable(this), |
||||||
|
// Only clear output images on the first batch |
||||||
|
ClearOutputImages = i == 0 |
||||||
|
}; |
||||||
|
|
||||||
|
batchArgs.Add(generationArgs); |
||||||
|
} |
||||||
|
|
||||||
|
// Run batches |
||||||
|
foreach (var args in batchArgs) |
||||||
|
{ |
||||||
|
await RunGeneration(args, cancellationToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public void LoadStateFromParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
SamplerCardViewModel.LoadStateFromParameters(parameters); |
||||||
|
ModelCardViewModel.LoadStateFromParameters(parameters); |
||||||
|
|
||||||
|
SeedCardViewModel.Seed = Convert.ToInt64(parameters.Seed); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public GenerationParameters SaveStateToParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
parameters = SamplerCardViewModel.SaveStateToParameters(parameters); |
||||||
|
parameters = ModelCardViewModel.SaveStateToParameters(parameters); |
||||||
|
|
||||||
|
parameters.Seed = (ulong)SeedCardViewModel.Seed; |
||||||
|
|
||||||
|
return parameters; |
||||||
|
} |
||||||
|
|
||||||
|
// Migration for v2 deserialization |
||||||
|
public override void LoadStateFromJsonObject(JsonObject state, int version) |
||||||
|
{ |
||||||
|
if (version > 2) |
||||||
|
{ |
||||||
|
LoadStateFromJsonObject(state); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Models.Inference; |
||||||
|
using StabilityMatrix.Avalonia.Services; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.Nodes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Inference.Video; |
||||||
|
|
||||||
|
[View(typeof(ModelCard))] |
||||||
|
[ManagedService] |
||||||
|
[Transient] |
||||||
|
public class ImgToVidModelCardViewModel : ModelCardViewModel |
||||||
|
{ |
||||||
|
public ImgToVidModelCardViewModel(IInferenceClientManager clientManager) |
||||||
|
: base(clientManager) |
||||||
|
{ |
||||||
|
DisableSettings = true; |
||||||
|
} |
||||||
|
|
||||||
|
public override void ApplyStep(ModuleApplyStepEventArgs e) |
||||||
|
{ |
||||||
|
var imgToVidLoader = e.Nodes.AddTypedNode( |
||||||
|
new ComfyNodeBuilder.ImageOnlyCheckpointLoader |
||||||
|
{ |
||||||
|
Name = "ImageOnlyCheckpointLoader", |
||||||
|
CkptName = |
||||||
|
SelectedModel?.RelativePath |
||||||
|
?? throw new ValidationException("Model not selected") |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
e.Builder.Connections.BaseModel = imgToVidLoader.Output1; |
||||||
|
e.Builder.Connections.BaseClipVision = imgToVidLoader.Output2; |
||||||
|
e.Builder.Connections.BaseVAE = imgToVidLoader.Output3; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Models; |
||||||
|
using StabilityMatrix.Avalonia.Models.Inference; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.Nodes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Inference.Video; |
||||||
|
|
||||||
|
[View(typeof(VideoGenerationSettingsCard))] |
||||||
|
[ManagedService] |
||||||
|
[Transient] |
||||||
|
public partial class SvdImgToVidConditioningViewModel |
||||||
|
: LoadableViewModelBase, |
||||||
|
IParametersLoadableState, |
||||||
|
IComfyStep |
||||||
|
{ |
||||||
|
[ObservableProperty] |
||||||
|
private int width = 1024; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private int height = 576; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private int numFrames = 14; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private int motionBucketId = 127; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private int fps = 6; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private double augmentationLevel; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private double minCfg = 1.0d; |
||||||
|
|
||||||
|
public void LoadStateFromParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
} |
||||||
|
|
||||||
|
public GenerationParameters SaveStateToParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
return parameters; |
||||||
|
} |
||||||
|
|
||||||
|
public void ApplyStep(ModuleApplyStepEventArgs e) |
||||||
|
{ |
||||||
|
// do VideoLinearCFGGuidance stuff first |
||||||
|
var cfgGuidanceNode = e.Nodes.AddTypedNode( |
||||||
|
new ComfyNodeBuilder.VideoLinearCFGGuidance |
||||||
|
{ |
||||||
|
Name = e.Nodes.GetUniqueName("LinearCfgGuidance"), |
||||||
|
Model = |
||||||
|
e.Builder.Connections.BaseModel |
||||||
|
?? throw new ValidationException("Model not selected"), |
||||||
|
MinCfg = MinCfg |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
e.Builder.Connections.BaseModel = cfgGuidanceNode.Output; |
||||||
|
|
||||||
|
// then do the SVD stuff |
||||||
|
var svdImgToVidConditioningNode = e.Nodes.AddTypedNode( |
||||||
|
new ComfyNodeBuilder.SVD_img2vid_Conditioning |
||||||
|
{ |
||||||
|
ClipVision = e.Builder.Connections.BaseClipVision!, |
||||||
|
InitImage = e.Builder.GetPrimaryAsImage(), |
||||||
|
Vae = e.Builder.Connections.BaseVAE!, |
||||||
|
Name = e.Nodes.GetUniqueName("SvdImgToVidConditioning"), |
||||||
|
Width = Width, |
||||||
|
Height = Height, |
||||||
|
VideoFrames = NumFrames, |
||||||
|
MotionBucketId = MotionBucketId, |
||||||
|
Fps = Fps, |
||||||
|
AugmentationLevel = AugmentationLevel |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
e.Builder.Connections.BaseConditioning = svdImgToVidConditioningNode.Output1; |
||||||
|
e.Builder.Connections.BaseNegativeConditioning = svdImgToVidConditioningNode.Output2; |
||||||
|
e.Builder.Connections.Primary = svdImgToVidConditioningNode.Output3; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Models; |
||||||
|
using StabilityMatrix.Avalonia.Models.Inference; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.Nodes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Inference.Video; |
||||||
|
|
||||||
|
[View(typeof(VideoOutputSettingsCard))] |
||||||
|
[ManagedService] |
||||||
|
[Transient] |
||||||
|
public partial class VideoOutputSettingsCardViewModel |
||||||
|
: LoadableViewModelBase, |
||||||
|
IParametersLoadableState, |
||||||
|
IComfyStep |
||||||
|
{ |
||||||
|
[ObservableProperty] |
||||||
|
private double fps = 6; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private bool lossless = true; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private int quality = 85; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private VideoOutputMethod selectedMethod = VideoOutputMethod.Default; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private List<VideoOutputMethod> availableMethods = Enum.GetValues<VideoOutputMethod>().ToList(); |
||||||
|
|
||||||
|
public void LoadStateFromParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
} |
||||||
|
|
||||||
|
public GenerationParameters SaveStateToParameters(GenerationParameters parameters) |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
return parameters; |
||||||
|
} |
||||||
|
|
||||||
|
public void ApplyStep(ModuleApplyStepEventArgs e) |
||||||
|
{ |
||||||
|
if (e.Builder.Connections.Primary is null) |
||||||
|
throw new ArgumentException("No Primary"); |
||||||
|
|
||||||
|
var image = e.Builder.Connections.Primary.Match( |
||||||
|
_ => |
||||||
|
e.Builder.GetPrimaryAsImage( |
||||||
|
e.Builder.Connections.PrimaryVAE |
||||||
|
?? e.Builder.Connections.RefinerVAE |
||||||
|
?? e.Builder.Connections.BaseVAE |
||||||
|
?? throw new ArgumentException("No Primary, Refiner, or Base VAE") |
||||||
|
), |
||||||
|
image => image |
||||||
|
); |
||||||
|
|
||||||
|
var outputStep = e.Nodes.AddTypedNode( |
||||||
|
new ComfyNodeBuilder.SaveAnimatedWEBP |
||||||
|
{ |
||||||
|
Name = e.Nodes.GetUniqueName("SaveAnimatedWEBP"), |
||||||
|
Images = image, |
||||||
|
FilenamePrefix = "InferenceVideo", |
||||||
|
Fps = Fps, |
||||||
|
Lossless = Lossless, |
||||||
|
Quality = Quality, |
||||||
|
Method = SelectedMethod.ToString().ToLowerInvariant() |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
e.Builder.Connections.OutputNodes.Add(outputStep); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,221 @@ |
|||||||
|
<dock:DockUserControlBase |
||||||
|
x:Class="StabilityMatrix.Avalonia.Views.Inference.InferenceImageToVideoView" |
||||||
|
xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||||
|
xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" |
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||||
|
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
|
xmlns:vmInference="using:StabilityMatrix.Avalonia.ViewModels.Inference" |
||||||
|
xmlns:dock="clr-namespace:StabilityMatrix.Avalonia.Controls.Dock" |
||||||
|
xmlns:modelsInference="clr-namespace:StabilityMatrix.Avalonia.Models.Inference" |
||||||
|
d:DataContext="{x:Static mocks:DesignData.InferenceImageToVideoViewModel}" |
||||||
|
d:DesignHeight="800" |
||||||
|
d:DesignWidth="1000" |
||||||
|
x:DataType="vmInference:InferenceImageToVideoViewModel" |
||||||
|
Focusable="True" |
||||||
|
mc:Ignorable="d"> |
||||||
|
|
||||||
|
<Grid Margin="2,0,2,8"> |
||||||
|
<DockControl |
||||||
|
x:Name="Dock" |
||||||
|
InitializeFactory="True" |
||||||
|
InitializeLayout="True"> |
||||||
|
<DockControl.Factory> |
||||||
|
<Factory /> |
||||||
|
</DockControl.Factory> |
||||||
|
|
||||||
|
<RootDock |
||||||
|
x:Name="Root" |
||||||
|
DefaultDockable="{Binding #MainLayout}" |
||||||
|
Id="Root" |
||||||
|
IsCollapsable="False"> |
||||||
|
|
||||||
|
<ProportionalDock |
||||||
|
x:Name="MainLayout" |
||||||
|
Id="MainLayout" |
||||||
|
Orientation="Horizontal"> |
||||||
|
<!-- Left Pane --> |
||||||
|
<ProportionalDock |
||||||
|
Proportion="0.3" |
||||||
|
Orientation="Vertical"> |
||||||
|
<ToolDock |
||||||
|
x:Name="SelectImagePane" |
||||||
|
Alignment="Left" |
||||||
|
Id="ConfigPane" |
||||||
|
Proportion="0.3"> |
||||||
|
<Tool |
||||||
|
x:Name="SelectImageTool" |
||||||
|
Title="Image Input" |
||||||
|
x:DataType="Tool" |
||||||
|
Id="ConfigTool" |
||||||
|
CanClose="False"> |
||||||
|
<controls:SelectImageCard |
||||||
|
DataContext="{Binding #Dock.((vmInference:InferenceImageToVideoViewModel)DataContext).SelectImageCardViewModel}" /> |
||||||
|
</Tool> |
||||||
|
</ToolDock> |
||||||
|
<ToolDock |
||||||
|
x:Name="ConfigPane" |
||||||
|
Alignment="Left" |
||||||
|
Id="ConfigPane" |
||||||
|
Proportion="0.6"> |
||||||
|
<Tool |
||||||
|
x:Name="ConfigTool" |
||||||
|
Title="Config" |
||||||
|
x:DataType="Tool" |
||||||
|
Id="ConfigTool" |
||||||
|
CanClose="False"> |
||||||
|
<controls:StackCard |
||||||
|
Opacity="1" |
||||||
|
DataContext="{ReflectionBinding ElementName=Dock, Path=DataContext.StackCardViewModel}" /> |
||||||
|
</Tool> |
||||||
|
</ToolDock> |
||||||
|
</ProportionalDock> |
||||||
|
<ProportionalDockSplitter x:Name="Splitter1" Id="Splitter1" /> |
||||||
|
|
||||||
|
<!-- Middle Pane --> |
||||||
|
<ProportionalDock |
||||||
|
Proportion="0.5" |
||||||
|
Orientation="Vertical"> |
||||||
|
<ToolDock |
||||||
|
x:Name="ImageGalleryPane" |
||||||
|
Alignment="Right" |
||||||
|
Id="ImageGalleryPane" |
||||||
|
Proportion="0.9"> |
||||||
|
<Tool |
||||||
|
x:Name="ImageGalleryTool" |
||||||
|
Title="Image Output" |
||||||
|
x:DataType="Tool" |
||||||
|
Id="ImageGalleryTool" |
||||||
|
CanClose="False"> |
||||||
|
|
||||||
|
<Grid |
||||||
|
x:CompileBindings="False" |
||||||
|
DataContext="{Binding ElementName=Dock, Path=DataContext}"> |
||||||
|
<controls:ImageGalleryCard |
||||||
|
Grid.Row="0" |
||||||
|
DataContext="{Binding ImageGalleryCardViewModel}" /> |
||||||
|
|
||||||
|
<StackPanel |
||||||
|
DataContext="{Binding OutputProgress}" |
||||||
|
Margin="2,1,2,4" |
||||||
|
Spacing="4" |
||||||
|
VerticalAlignment="Top"> |
||||||
|
<ProgressBar |
||||||
|
IsVisible="{Binding IsProgressVisible}" |
||||||
|
IsIndeterminate="{Binding IsIndeterminate}" |
||||||
|
Maximum="{Binding Maximum}" |
||||||
|
Value="{Binding Value}" /> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
Margin="0,10,0,0" |
||||||
|
IsVisible="{Binding IsTextVisible}" |
||||||
|
TextAlignment="Center" |
||||||
|
Text="{Binding Text}" /> |
||||||
|
</StackPanel> |
||||||
|
</Grid> |
||||||
|
</Tool> |
||||||
|
</ToolDock> |
||||||
|
<ToolDock x:Name="GeneratePane" |
||||||
|
Alignment="Top" |
||||||
|
Id="ConfigPane" |
||||||
|
Proportion="0.1"> |
||||||
|
<Tool |
||||||
|
x:Name="GenerateTool" |
||||||
|
Title="Generate" |
||||||
|
x:DataType="Tool" |
||||||
|
Id="GenerateTool" |
||||||
|
CanClose="False"> |
||||||
|
<!-- Generate Buttons --> |
||||||
|
<StackPanel Margin="0,6,0,0" |
||||||
|
x:CompileBindings="False" |
||||||
|
DataContext="{Binding ElementName=Dock, Path=DataContext}"> |
||||||
|
<controls:Card Padding="8"> |
||||||
|
<Grid |
||||||
|
HorizontalAlignment="Center" |
||||||
|
ColumnDefinitions="Auto,*,Auto" |
||||||
|
RowDefinitions="Auto,*"> |
||||||
|
<Grid.Styles> |
||||||
|
<Style Selector="Button"> |
||||||
|
<Setter Property="MinHeight" Value="32" /> |
||||||
|
</Style> |
||||||
|
</Grid.Styles> |
||||||
|
|
||||||
|
<!-- Main Generate Button --> |
||||||
|
<Button |
||||||
|
x:Name="GenerateButton" |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="1" |
||||||
|
Width="130" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
Classes="accent" |
||||||
|
Command="{Binding GenerateImageCommand}" |
||||||
|
CommandParameter="{x:Static modelsInference:GenerateFlags.None}" |
||||||
|
IsVisible="{Binding !GenerateImageCommand.CanBeCanceled}"> |
||||||
|
<Panel> |
||||||
|
<TextBlock IsVisible="{Binding #GenerateButton.IsEnabled}" |
||||||
|
Text="Generate Image" /> |
||||||
|
<controls:ProgressRing IsIndeterminate="True" |
||||||
|
IsVisible="{Binding !#GenerateButton.IsEnabled}" /> |
||||||
|
</Panel> |
||||||
|
</Button> |
||||||
|
<!-- Cancel Button --> |
||||||
|
<Button |
||||||
|
x:Name="CancelButton" |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="1" |
||||||
|
Width="130" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
icons:Attached.Icon="fa-solid fa-stop" |
||||||
|
Command="{Binding GenerateImageCancelCommand}" |
||||||
|
IsVisible="{Binding GenerateImageCommand.CanBeCanceled}" /> |
||||||
|
|
||||||
|
<Button |
||||||
|
Grid.Row="1" |
||||||
|
Grid.Column="2" |
||||||
|
Margin="4,0" |
||||||
|
Padding="12,8" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
icons:Attached.Icon="fa-solid fa-repeat" |
||||||
|
Classes="transparent" |
||||||
|
Command="{Binding GenerateImageCommand}" |
||||||
|
CommandParameter="{x:Static modelsInference:GenerateFlags.UseCurrentSeed}" |
||||||
|
ToolTip.Tip="Generate with current seed" /> |
||||||
|
</Grid> |
||||||
|
</controls:Card> |
||||||
|
</StackPanel> |
||||||
|
</Tool> |
||||||
|
</ToolDock> |
||||||
|
</ProportionalDock> |
||||||
|
|
||||||
|
<ProportionalDockSplitter x:Name="Splitter3" Id="Splitter3" /> |
||||||
|
|
||||||
|
<!-- Right Pane --> |
||||||
|
<ToolDock |
||||||
|
x:Name="ImageFolderPane" |
||||||
|
Alignment="Right" |
||||||
|
Id="ImageFolderPane" |
||||||
|
Proportion="0.2"> |
||||||
|
<Tool |
||||||
|
x:Name="ImageFolderTool" |
||||||
|
x:DataType="Tool" |
||||||
|
Title="Gallery" |
||||||
|
Id="ImageFolderTool" |
||||||
|
CanClose="False"> |
||||||
|
|
||||||
|
<Grid |
||||||
|
x:CompileBindings="False" |
||||||
|
DataContext="{Binding ElementName=Dock, Path=DataContext}"> |
||||||
|
<controls:ImageFolderCard |
||||||
|
DataContext="{Binding ImageFolderCardViewModel}" /> |
||||||
|
</Grid> |
||||||
|
</Tool> |
||||||
|
</ToolDock> |
||||||
|
|
||||||
|
</ProportionalDock> |
||||||
|
</RootDock> |
||||||
|
|
||||||
|
</DockControl> |
||||||
|
</Grid> |
||||||
|
</dock:DockUserControlBase> |
@ -0,0 +1,13 @@ |
|||||||
|
using StabilityMatrix.Avalonia.Controls.Dock; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Views.Inference; |
||||||
|
|
||||||
|
[Transient] |
||||||
|
public partial class InferenceImageToVideoView : DockUserControlBase |
||||||
|
{ |
||||||
|
public InferenceImageToVideoView() |
||||||
|
{ |
||||||
|
InitializeComponent(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue