mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 16:32:10 +00:00
Improved batch input handling
This commit is contained in:
parent
59c952e7d4
commit
cd8ec4cbb9
@ -1,6 +1,7 @@
|
||||
@attribute [Route(Routes.ASSISTANT_BATCH_PROCESSING)]
|
||||
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogBatchProcessing>
|
||||
@using AIStudio.Settings.DataModel
|
||||
@using AIStudio.Tools.Rust
|
||||
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@T("Input")
|
||||
@ -12,6 +13,13 @@
|
||||
|
||||
<MudTextSwitch Label="@T("Include subfolders?")" Disabled="@this.isProcessingBatch" Value="@this.includeSubdirectories" ValueChanged="@(v => this.includeSubdirectories = v)" LabelOn="@T("Yes, process files in subfolders as well")" LabelOff="@T("No, only process files in the selected folder")"/>
|
||||
|
||||
@if (this.includeSubdirectories)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead.")
|
||||
</MudJustifiedText>
|
||||
}
|
||||
|
||||
<MudText Typo="Typo.h5" Class="mb-3 mt-6">
|
||||
@T("Instructions")
|
||||
</MudText>
|
||||
@ -27,11 +35,13 @@
|
||||
|
||||
@if (this.promptSource is BatchProcessingPromptSource.FREE_PROMPT)
|
||||
{
|
||||
<ReadFileContent Text="@T("Load prompt from file")" @bind-FileContent="@this.freePrompt" Disabled="@this.isProcessingBatch"/>
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.freePrompt" Validation="@this.ValidateFreePrompt" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("What should the AI do with each document?")" HelperText="@T("These instructions are applied to every single document of the batch run.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
}
|
||||
else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT)
|
||||
{
|
||||
<ReadFileContent Text="@T("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" ShowAttachedDocumentState="@true" Disabled="@this.isProcessingBatch"/>
|
||||
<ReadFileContent Text="@T("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" Filter="@([FileTypes.MARKDOWN])" ShowAttachedDocumentState="@true" Disabled="@this.isProcessingBatch"/>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(this.promptFilePath))
|
||||
{
|
||||
|
||||
@ -20,6 +20,25 @@ public partial class AssistantBatchProcessing
|
||||
if (string.IsNullOrWhiteSpace(patterns))
|
||||
return T("Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon.");
|
||||
|
||||
var individualPatterns = patterns.Split(';');
|
||||
if (individualPatterns.Any(string.IsNullOrWhiteSpace))
|
||||
return T("Please remove empty file patterns. Separate valid patterns with a single semicolon.");
|
||||
|
||||
foreach (var patternEntry in individualPatterns)
|
||||
{
|
||||
var pattern = patternEntry.Trim();
|
||||
if (pattern is "." or ".."
|
||||
|| pattern.EndsWith("..", StringComparison.Ordinal)
|
||||
|| pattern.IndexOfAny([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '/', '\\']) >= 0)
|
||||
return T("Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx.");
|
||||
|
||||
var invalidCharacters = Path.GetInvalidFileNameChars()
|
||||
.Where(character => character is not '*' and not '?')
|
||||
.ToArray();
|
||||
if (pattern.IndexOfAny(invalidCharacters) >= 0)
|
||||
return T("One of the file patterns contains an invalid character.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,13 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool CatchAllDocuments { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optionally restricts the file types offered by the native file picker
|
||||
/// and accepted by this component.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public FileTypeFilter[]? Filter { get; set; }
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
@ -252,7 +259,7 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
this.isFileDialogOpen = true;
|
||||
try
|
||||
{
|
||||
var selectedFile = await this.RustService.SelectFile(T("Select file to read its content"));
|
||||
var selectedFile = await this.RustService.SelectFile(T("Select file to read its content"), this.Filter);
|
||||
if (selectedFile.UserCancelled)
|
||||
{
|
||||
this.Logger.LogInformation("User cancelled the file selection");
|
||||
@ -310,6 +317,13 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.Filter is { Length: > 0 } && !FileTypes.IsAllowedPath(filePath, this.Filter))
|
||||
{
|
||||
this.Logger.LogWarning("Selected file does not match the configured file type filter: '{FilePath}'", filePath);
|
||||
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, this.T("Please select a file with a supported file type.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.AUDIO) || FileTypes.IsAllowedPath(filePath, FileTypes.VIDEO))
|
||||
return await this.LoadMediaTranscriptAsync(filePath);
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
@using AIStudio.Assistants.BatchProcessing
|
||||
@using AIStudio.Settings
|
||||
@using AIStudio.Tools.Rust
|
||||
@inherits SettingsDialogBase
|
||||
|
||||
<MudDialog>
|
||||
@ -26,7 +27,7 @@
|
||||
}
|
||||
else if (this.SettingsManager.ConfigurationData.BatchProcessing.PromptSource is BatchProcessingPromptSource.FILE_IMPORT)
|
||||
{
|
||||
<ConfigurationText OptionDescription="@T("Default Markdown instructions file")" Disabled="@this.DefaultsDisabled" Icon="@Icons.Material.Filled.Description" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.PromptFilePath)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.PromptFilePath = value)" OptionHelp="@T("The current content of this Markdown file is loaded whenever the defaults are applied.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.PromptFilePath, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationFile OptionDescription="@T("Default Markdown instructions file")" Disabled="@this.DefaultsDisabled" Icon="@Icons.Material.Filled.Description" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.PromptFilePath)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.PromptFilePath = value)" FileDialogTitle="@T("Select the default Markdown instructions file")" Filter="@([FileTypes.MARKDOWN])" OptionHelp="@T("The current content of this Markdown file is loaded whenever the defaults are applied.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.PromptFilePath, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -54,4 +55,4 @@
|
||||
<DialogActions>
|
||||
<MudButton OnClick="@this.Close" Variant="Variant.Filled">@T("Close")</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
</MudDialog>
|
||||
|
||||
@ -50,6 +50,7 @@ public static class FileTypes
|
||||
|
||||
// Document hierarchy
|
||||
public static readonly FileTypeFilter PDF = FileTypeFilter.Leaf("PDF", "pdf");
|
||||
public static readonly FileTypeFilter MARKDOWN = FileTypeFilter.Leaf("Markdown", "md");
|
||||
public static readonly FileTypeFilter TEXT = FileTypeFilter.Leaf(TB("Text"), "txt", "md", "rtf");
|
||||
public static readonly FileTypeFilter TABULAR = FileTypeFilter.Leaf(TB("Tabular text"), "csv", "tsv");
|
||||
public static readonly FileTypeFilter MS_WORD = FileTypeFilter.Leaf("Microsoft Word", "docx");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user