11using System . Collections . ObjectModel ;
2+ using System . Collections . Specialized ;
23using System . ComponentModel . DataAnnotations ;
34using System . Text . Json . Nodes ;
45using CommunityToolkit . Mvvm . ComponentModel ;
1415using StabilityMatrix . Avalonia . ViewModels . Dialogs ;
1516using StabilityMatrix . Avalonia . ViewModels . Inference . Modules ;
1617using StabilityMatrix . Core . Attributes ;
18+ using StabilityMatrix . Core . Extensions ;
1719using StabilityMatrix . Core . Models ;
1820using StabilityMatrix . Core . Models . Api . Comfy . Nodes ;
1921using StabilityMatrix . Core . Models . Api . Comfy . NodeTypes ;
@@ -32,6 +34,10 @@ TabContext tabContext
3234{
3335 [ ObservableProperty ]
3436 [ NotifyPropertyChangedFor ( nameof ( SelectedUnifiedModel ) ) ]
37+ [ NotifyPropertyChangedFor ( nameof ( WorkflowFilteredModels ) ) ]
38+ [ NotifyPropertyChangedFor ( nameof ( WorkflowProfileStatusText ) ) ]
39+ [ NotifyPropertyChangedFor ( nameof ( ShowWorkflowProfileStatus ) ) ]
40+ [ NotifyPropertyChangedFor ( nameof ( RecommendedDefaultsToolTip ) ) ]
3541 private HybridModelFile ? selectedModel ;
3642
3743 [ ObservableProperty ]
@@ -40,7 +46,11 @@ TabContext tabContext
4046 nameof ( ShowPrecisionSelection ) ,
4147 nameof ( SelectedUnifiedModel ) ,
4248 nameof ( HasActiveAdvancedOptions ) ,
43- nameof ( AdvancedOptionsHeader )
49+ nameof ( AdvancedOptionsHeader ) ,
50+ nameof ( WorkflowFilteredModels ) ,
51+ nameof ( WorkflowProfileStatusText ) ,
52+ nameof ( ShowWorkflowProfileStatus ) ,
53+ nameof ( RecommendedDefaultsToolTip )
4454 ) ]
4555 private HybridModelFile ? selectedUnetModel ;
4656
@@ -118,7 +128,11 @@ public HybridModelFile? SelectedUnifiedModel
118128 nameof ( ShowPrecisionSelection ) ,
119129 nameof ( ShowEncoderSection ) ,
120130 nameof ( HasActiveAdvancedOptions ) ,
121- nameof ( AdvancedOptionsHeader )
131+ nameof ( AdvancedOptionsHeader ) ,
132+ nameof ( WorkflowFilteredModels ) ,
133+ nameof ( WorkflowProfileStatusText ) ,
134+ nameof ( ShowWorkflowProfileStatus ) ,
135+ nameof ( RecommendedDefaultsToolTip )
122136 ) ]
123137 private ModelLoader selectedModelLoader ;
124138
@@ -160,7 +174,11 @@ public HybridModelFile? SelectedUnifiedModel
160174 nameof ( IsHiDreamWorkflow ) ,
161175 nameof ( ShowShift ) ,
162176 nameof ( ShowEncoderTypeSelection ) ,
163- nameof ( HasRecommendedDefaults )
177+ nameof ( HasRecommendedDefaults ) ,
178+ nameof ( WorkflowFilteredModels ) ,
179+ nameof ( WorkflowProfileStatusText ) ,
180+ nameof ( ShowWorkflowProfileStatus ) ,
181+ nameof ( RecommendedDefaultsToolTip )
164182 ) ]
165183 private string ? selectedClipType ;
166184
@@ -170,7 +188,11 @@ public HybridModelFile? SelectedUnifiedModel
170188 nameof ( IsHiDreamWorkflow ) ,
171189 nameof ( ShowShift ) ,
172190 nameof ( ShowEncoderTypeSelection ) ,
173- nameof ( HasRecommendedDefaults )
191+ nameof ( HasRecommendedDefaults ) ,
192+ nameof ( WorkflowFilteredModels ) ,
193+ nameof ( WorkflowProfileStatusText ) ,
194+ nameof ( ShowWorkflowProfileStatus ) ,
195+ nameof ( RecommendedDefaultsToolTip )
174196 ) ]
175197 private InferenceWorkflowProfile selectedWorkflowProfile = InferenceWorkflowProfile . Auto ;
176198
@@ -273,6 +295,29 @@ or InferenceWorkflowProfile.Flux2
273295 or InferenceWorkflowProfile . ZImageBase
274296 or InferenceWorkflowProfile . ZImageTurbo
275297 or InferenceWorkflowProfile . Anima ;
298+ public bool ShowWorkflowProfileStatus =>
299+ SelectedWorkflowProfile is InferenceWorkflowProfile . Auto
300+ && SelectedUnifiedModel is not null
301+ && ResolvedWorkflowProfile is not InferenceWorkflowProfile . Custom ;
302+ public string WorkflowProfileStatusText => $ "Detected: { ResolvedWorkflowProfile . GetStringValue ( ) } ";
303+ public string RecommendedDefaultsToolTip =>
304+ ResolvedWorkflowProfile switch
305+ {
306+ InferenceWorkflowProfile . DefaultCheckpoint =>
307+ "Apply recommended sampler defaults: Euler Ancestral / Normal / 30 steps / CFG 5" ,
308+ InferenceWorkflowProfile . Flux =>
309+ "Apply recommended sampler defaults: Euler / Simple / 20 steps / CFG 3.5" ,
310+ InferenceWorkflowProfile . Flux2 =>
311+ "Apply recommended sampler defaults: Euler / Flux2Scheduler / 20 steps / CFG 5" ,
312+ InferenceWorkflowProfile . ZImageBase =>
313+ "Apply recommended sampler defaults: Res Multistep / Simple / 30 steps / CFG 4" ,
314+ InferenceWorkflowProfile . ZImageTurbo =>
315+ "Apply recommended sampler defaults: Res Multistep / Simple / 8 steps / CFG 1" ,
316+ InferenceWorkflowProfile . Anima =>
317+ "Apply recommended sampler defaults: ER SDE / Simple / 30 steps / CFG 4" ,
318+ _ => "No recommended sampler defaults for this workflow" ,
319+ } ;
320+ public IReadOnlyList < HybridModelFile > WorkflowFilteredModels => GetWorkflowFilteredModels ( ) ;
276321
277322 public event Action < InferenceWorkflowProfile > ? RecommendedDefaultsRequested ;
278323
@@ -286,19 +331,27 @@ protected override void OnInitialLoaded()
286331 {
287332 SetDefaultEncoderCount ( ) ;
288333 }
334+
335+ ClientManager . AllModels . CollectionChanged += AllModelsOnCollectionChanged ;
289336 }
290337
291338 public override void OnUnloaded ( )
292339 {
293340 base . OnUnloaded ( ) ;
294341 ExtraNetworksStackCardViewModel . CardAdded -= ExtraNetworksStackCardViewModelOnCardAdded ;
342+ ClientManager . AllModels . CollectionChanged -= AllModelsOnCollectionChanged ;
295343 }
296344
297345 private void ExtraNetworksStackCardViewModelOnCardAdded ( object ? sender , LoadableViewModelBase e )
298346 {
299347 OnSelectedModelChanged ( SelectedModel ) ;
300348 }
301349
350+ private void AllModelsOnCollectionChanged ( object ? sender , NotifyCollectionChangedEventArgs e )
351+ {
352+ OnPropertyChanged ( nameof ( WorkflowFilteredModels ) ) ;
353+ }
354+
302355 [ RelayCommand ]
303356 private static async Task OnConfigClickAsync ( )
304357 {
@@ -327,6 +380,7 @@ private async Task OpenModelPickerAsync()
327380 using var pickerScope = vmFactory . CreateScope ( ) ;
328381 var pickerVm = pickerScope . ServiceManager . Get < ModelPickerDialogViewModel > ( ) ;
329382 pickerVm . Title = "Select Model" ;
383+ pickerVm . PreferredWorkflowProfile = SelectedWorkflowProfile ;
330384
331385 if ( await pickerVm . GetDialog ( ) . ShowAsync ( ) == ContentDialogResult . Primary )
332386 {
@@ -596,10 +650,18 @@ public override void LoadStateFromJsonObject(JsonObject state)
596650
597651 private InferenceWorkflowProfile InferWorkflowProfile ( )
598652 {
599- if ( SelectedModelLoader is not ModelLoader . Unet )
653+ return InferWorkflowProfile (
654+ SelectedUnifiedModel ,
655+ SelectedModelLoader is ModelLoader . Unet
656+ || SelectedUnifiedModel ? . Local ? . SharedFolderType is SharedFolderType . DiffusionModels
657+ ) ;
658+ }
659+
660+ private static InferenceWorkflowProfile InferWorkflowProfile ( HybridModelFile ? model , bool isUnetModel )
661+ {
662+ if ( ! isUnetModel )
600663 return InferenceWorkflowProfile . DefaultCheckpoint ;
601664
602- var model = SelectedUnetModel ;
603665 var baseModel = model ? . Local ? . ConnectedModelInfo ? . BaseModel ;
604666
605667 if ( ! string . IsNullOrWhiteSpace ( baseModel ) )
@@ -636,7 +698,11 @@ private InferenceWorkflowProfile InferWorkflowProfile()
636698 : InferenceWorkflowProfile . ZImageBase ;
637699 }
638700
639- if ( name . Contains ( "flux2" , StringComparison . OrdinalIgnoreCase ) )
701+ if (
702+ name . Contains ( "flux2" , StringComparison . OrdinalIgnoreCase )
703+ || name . Contains ( "flux-2" , StringComparison . OrdinalIgnoreCase )
704+ || name . Contains ( "flux_2" , StringComparison . OrdinalIgnoreCase )
705+ )
640706 return InferenceWorkflowProfile . Flux2 ;
641707
642708 if ( name . Contains ( "flux" , StringComparison . OrdinalIgnoreCase ) )
@@ -651,6 +717,44 @@ private InferenceWorkflowProfile InferWorkflowProfile()
651717 return InferenceWorkflowProfile . DefaultCheckpoint ;
652718 }
653719
720+ private IReadOnlyList < HybridModelFile > GetWorkflowFilteredModels ( )
721+ {
722+ var allModels = ClientManager . AllModels . ToList ( ) ;
723+
724+ if ( SelectedWorkflowProfile is InferenceWorkflowProfile . Auto or InferenceWorkflowProfile . Custom )
725+ return allModels ;
726+
727+ var filteredModels = allModels
728+ . Where ( model => IsModelCompatibleWithWorkflow ( model , SelectedWorkflowProfile ) )
729+ . ToList ( ) ;
730+
731+ if ( filteredModels . Count == 0 )
732+ return allModels ;
733+
734+ if (
735+ SelectedUnifiedModel is { } selected
736+ && filteredModels . All ( model => ! HybridModelFile . Comparer . Equals ( model , selected ) )
737+ )
738+ {
739+ filteredModels . Insert ( 0 , selected ) ;
740+ }
741+
742+ return filteredModels ;
743+ }
744+
745+ private static bool IsModelCompatibleWithWorkflow ( HybridModelFile model , InferenceWorkflowProfile profile )
746+ {
747+ var isUnetModel = model . Local ? . SharedFolderType is SharedFolderType . DiffusionModels ;
748+
749+ if ( profile is InferenceWorkflowProfile . DefaultCheckpoint )
750+ return ! isUnetModel ;
751+
752+ if ( ! isUnetModel )
753+ return false ;
754+
755+ return InferWorkflowProfile ( model , true ) == profile ;
756+ }
757+
654758 /// <summary>
655759 /// Loads text encoders from the saved model state, supporting both new and legacy formats.
656760 /// </summary>
@@ -870,6 +974,10 @@ private void RefreshWorkflowProfileState()
870974 OnPropertyChanged ( nameof ( ShowShift ) ) ;
871975 OnPropertyChanged ( nameof ( ShowEncoderTypeSelection ) ) ;
872976 OnPropertyChanged ( nameof ( HasRecommendedDefaults ) ) ;
977+ OnPropertyChanged ( nameof ( WorkflowFilteredModels ) ) ;
978+ OnPropertyChanged ( nameof ( WorkflowProfileStatusText ) ) ;
979+ OnPropertyChanged ( nameof ( ShowWorkflowProfileStatus ) ) ;
980+ OnPropertyChanged ( nameof ( RecommendedDefaultsToolTip ) ) ;
873981
874982 if ( ! isLoadingState )
875983 {
0 commit comments