feat: Update FaceAiTabView to support output file selection and validation for .pkl files

This commit is contained in:
MaddoScientisto 2026-03-12 23:24:44 +01:00
commit fa09f7c324
2 changed files with 83 additions and 19 deletions

View file

@ -4,7 +4,7 @@
<ScrollViewer>
<StackPanel Margin="4" Spacing="6">
<TextBlock Text="Face Recognition Encoder" FontWeight="Bold" />
<TextBlock Text="Esegue face_encoder.exe usando la cartella Destinazione corrente come --images."
<TextBlock Text="Esegue face_encoder.exe usando la cartella Destinazione corrente come --images e un file .pkl come --out."
TextWrapping="Wrap" Opacity="0.8" />
<TextBlock Text="Eseguibile" FontWeight="Bold" Margin="0,4,0,0" />
@ -15,11 +15,17 @@
<Button Grid.Column="3" Name="FaceOpenExecutableButton" Content="Apri" Click="OpenFaceExecutableFolder_Click" Width="56" Margin="6,0,0,0" />
</Grid>
<Grid ColumnDefinitions="Auto,*,Auto,Auto" ColumnSpacing="6">
<TextBlock Grid.Column="0" Text="Sorgente:" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Name="FaceDestinationPathTextBox" Text="{Binding DestinationPath, Mode=OneWay}" IsReadOnly="True" />
<Button Grid.Column="3" Name="FaceOpenDestinationButton" Content="Apri" Click="OpenFaceDestinationFolder_Click" Width="56" Margin="6,0,0,0" />
</Grid>
<TextBlock Text="Output encodings" FontWeight="Bold" Margin="0,4,0,0" />
<Grid ColumnDefinitions="Auto,*,Auto,Auto" ColumnSpacing="6">
<TextBlock Grid.Column="0" Text="Cartella out:" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Name="FaceOutputFolderTextBox" Text="{Binding FaceOutputFolderPath, Mode=TwoWay}" Watermark="C:\\output\\encodings" />
<Button Grid.Column="2" Name="FaceSelectOutputButton" Content="Scegli..." Click="SelectFaceOutputFolder_Click" Width="88" Margin="6,0,0,0" />
<TextBlock Grid.Column="0" Text="File out (.pkl):" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Name="FaceOutputFolderTextBox" Text="{Binding FaceOutputFolderPath, Mode=TwoWay}" Watermark="C:\\output\\encodings.pkl" />
<Button Grid.Column="2" Name="FaceSelectOutputButton" Content="Scegli..." Click="SelectFaceOutputFile_Click" Width="88" Margin="6,0,0,0" />
<Button Grid.Column="3" Name="FaceOpenOutputButton" Content="Apri" Click="OpenFaceOutputFolder_Click" Width="56" Margin="6,0,0,0" />
</Grid>

View file

@ -57,7 +57,7 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
}
}
private async void SelectFaceOutputFolder_Click(object? sender, RoutedEventArgs e)
private async void SelectFaceOutputFile_Click(object? sender, RoutedEventArgs e)
{
var outputBox = this.FindControl<Avalonia.Controls.TextBox>("FaceOutputFolderTextBox");
if (outputBox is null)
@ -72,14 +72,21 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
var folders = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
var files = await storageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
Title = "Seleziona cartella output encodings"
Title = "Seleziona file output encodings (.pkl)",
SuggestedFileName = "encodings.pkl",
DefaultExtension = "pkl",
FileTypeChoices =
[
new FilePickerFileType("Pickle file") { Patterns = ["*.pkl"] }
],
ShowOverwritePrompt = true
});
if (folders.Count > 0)
if (files is not null)
{
outputBox.Text = folders[0].Path.LocalPath;
outputBox.Text = files.Path.LocalPath;
if (DataContext is DataModel model)
{
model.FaceOutputFolderPath = outputBox.Text;
@ -119,7 +126,38 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
OpenInExplorer(outputBox.Text);
var outputPath = outputBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(outputPath))
{
return;
}
if (File.Exists(outputPath))
{
OpenInExplorer(outputPath);
return;
}
var directory = Path.GetDirectoryName(outputPath);
OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? outputPath : directory);
}
private void OpenFaceDestinationFolder_Click(object? sender, RoutedEventArgs e)
{
var destBox = this.FindControl<Avalonia.Controls.TextBox>("FaceDestinationPathTextBox");
string? path = destBox?.Text?.Trim();
if (string.IsNullOrWhiteSpace(path) && DataContext is DataModel model)
{
path = (model.DestinationPath ?? string.Empty).Trim();
}
if (string.IsNullOrWhiteSpace(path))
{
return;
}
var directory = Path.GetDirectoryName(path);
OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? path : directory);
}
private async void RunFaceEncoder_Click(object? sender, RoutedEventArgs e)
@ -142,11 +180,11 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
}
var executablePath = executableBox.Text?.Trim().Trim('"') ?? string.Empty;
var outputFolder = outputFolderBox.Text?.Trim().Trim('"') ?? string.Empty;
var outputFilePath = outputFolderBox.Text?.Trim().Trim('"') ?? string.Empty;
var imagesFolder = (model.DestinationPath ?? string.Empty).Trim().Trim('"');
model.FaceExecutablePath = executablePath;
model.FaceOutputFolderPath = outputFolder;
model.FaceOutputFolderPath = outputFilePath;
if (string.IsNullOrWhiteSpace(executablePath) || !File.Exists(executablePath))
{
@ -160,20 +198,30 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
if (string.IsNullOrWhiteSpace(outputFolder))
if (string.IsNullOrWhiteSpace(outputFilePath))
{
statusBlock.Text = "Inserisci la cartella di output.";
statusBlock.Text = "Inserisci il file di output .pkl.";
return;
}
if (!string.Equals(Path.GetExtension(outputFilePath), ".pkl", StringComparison.OrdinalIgnoreCase))
{
statusBlock.Text = "Il file di output deve avere estensione .pkl.";
return;
}
try
{
Directory.CreateDirectory(outputFolder);
var outputDirectory = Path.GetDirectoryName(outputFilePath);
if (!string.IsNullOrWhiteSpace(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Unable to create face output folder: {OutputFolder}", outputFolder);
statusBlock.Text = "Impossibile creare la cartella di output.";
_logger.LogError(ex, "Unable to create face output directory for file: {OutputFilePath}", outputFilePath);
statusBlock.Text = "Impossibile creare la cartella del file di output.";
return;
}
@ -187,7 +235,7 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
try
{
var imagesFolderArg = NormalizeDirectoryPathArgument(imagesFolder);
var outputFolderArg = NormalizeDirectoryPathArgument(outputFolder);
var outputFileArg = NormalizeFilePathArgument(outputFilePath);
var processStartInfo = new ProcessStartInfo
{
@ -201,7 +249,7 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
processStartInfo.ArgumentList.Add("--images");
processStartInfo.ArgumentList.Add(imagesFolderArg);
processStartInfo.ArgumentList.Add("--out");
processStartInfo.ArgumentList.Add(outputFolderArg);
processStartInfo.ArgumentList.Add(outputFileArg);
using var process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true };
process.OutputDataReceived += (_, args) =>
@ -314,4 +362,14 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return normalized;
}
private static string NormalizeFilePathArgument(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
return value.Trim().Trim('"');
}
}