From c8c336cf7aad28dec19f28eb43ab0dc188e79419 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Tue, 11 Aug 2026 12:14:22 +0200 Subject: [PATCH] Added batch processing settings --- .../Assistants/AssistantBase.razor.cs | 7 + .../AssistantBatchProcessing.razor | 23 +- .../AssistantBatchProcessing.razor.Prompts.cs | 3 +- ...sistantBatchProcessing.razor.Validation.cs | 2 + .../AssistantBatchProcessing.razor.cs | 196 ++++++++++++++++-- .../SettingsDialogBatchProcessing.razor | 58 ++++++ .../SettingsDialogBatchProcessing.razor.cs | 48 +++++ .../Plugins/configuration/plugin.lua | 59 +++++- .../Settings/DataModel/Data.cs | 7 +- .../Settings/DataModel/DataBatchProcessing.cs | 52 +++++ .../Tools/ComponentsExtensions.cs | 11 +- .../Tools/PluginSystem/PluginConfiguration.cs | 19 +- 12 files changed, 454 insertions(+), 31 deletions(-) create mode 100644 app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor create mode 100644 app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs create mode 100644 app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index 395f8055..04e69221 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -180,6 +180,7 @@ public abstract partial class AssistantBase : AssistantLowerBase wher this.ProviderSettings = this.SettingsManager.GetPreselectedProvider(this.Component); this.CurrentProfile = this.SettingsManager.GetPreselectedProfile(this.Component); this.CurrentChatTemplate = this.SettingsManager.GetPreselectedChatTemplate(this.Component); + await this.OnDefaultsAppliedAsync(); this.assistantSessionKey = new(this.Component, this.AssistantSessionInstanceId); await this.AttachAssistantSessionIfAvailable(); await this.ConsumeMediaOutcomeAsync(); @@ -311,6 +312,11 @@ public abstract partial class AssistantBase : AssistantLowerBase wher /// the user has stopped typing or selecting options. /// protected virtual Task OnFormChange() => Task.CompletedTask; + + /// + /// Allows assistants to finish asynchronous work after their configured defaults were applied. + /// + protected virtual Task OnDefaultsAppliedAsync() => Task.CompletedTask; /// /// Add an issue to the UI. @@ -668,6 +674,7 @@ public abstract partial class AssistantBase : AssistantLowerBase wher this.ResetForm(); this.ResetProviderAndProfileSelection(); + await this.OnDefaultsAppliedAsync(); this.InputIsValid = false; this.InputIssues = []; diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor index c1363de4..6cb03bc1 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor @@ -1,5 +1,5 @@ @attribute [Route(Routes.ASSISTANT_BATCH_PROCESSING)] -@inherits AssistantBaseCore +@inherits AssistantBaseCore @using AIStudio.Settings.DataModel @@ -16,7 +16,7 @@ @T("Instructions") - + @foreach (var source in Enum.GetValues()) { @@ -31,7 +31,17 @@ } else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT) { - + + + @if (!string.IsNullOrWhiteSpace(this.promptFilePath)) + { + @(string.Format(T("Configured instructions file: {0}"), this.promptFilePath)) + } + + @if (!string.IsNullOrWhiteSpace(this.promptFileLoadIssue)) + { + @this.promptFileLoadIssue + } @T("The content of the selected file is used as the instructions for every single document of the batch run.") @@ -39,6 +49,11 @@ else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT) } else { + @if (this.ConfiguredPolicyIsMissing) + { + @T("The configured default policy no longer exists. Please select another document analysis policy.") + } + @if (this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Count is 0) { @@ -50,7 +65,7 @@ else } else { - + @foreach (var policy in this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies) { diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Prompts.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Prompts.cs index cd2cbae8..bba9fc50 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Prompts.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Prompts.cs @@ -1,6 +1,5 @@ using AIStudio.Chat; using AIStudio.Provider; -using AIStudio.Settings; namespace AIStudio.Assistants.BatchProcessing; @@ -92,7 +91,7 @@ public partial class AssistantBatchProcessing { IncludeDateTime = false, SelectedProvider = this.ProviderSettings.Id, - SelectedProfile = Profile.NO_PROFILE.Id, + SelectedProfile = this.CurrentProfile.Id, SystemPrompt = this.SystemPrompt, WorkspaceId = Guid.Empty, ChatId = Guid.NewGuid(), diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs index ad3d90ca..9197feff 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs @@ -47,7 +47,9 @@ public partial class AssistantBatchProcessing /// private string? ValidateInstructionSource() => this.promptSource switch { + BatchProcessingPromptSource.POLICY when this.ConfiguredPolicyIsMissing => T("The configured default policy no longer exists. Please select another document analysis policy."), BatchProcessingPromptSource.POLICY when this.selectedPolicy is null => T("Please select a document analysis policy."), + BatchProcessingPromptSource.FILE_IMPORT when !string.IsNullOrWhiteSpace(this.promptFileLoadIssue) => this.promptFileLoadIssue, BatchProcessingPromptSource.FILE_IMPORT when string.IsNullOrWhiteSpace(this.importedPrompt) => T("Please select the file which contains your instructions."), _ => null, diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs index 26223327..09ad9aff 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs @@ -1,17 +1,17 @@ using AIStudio.Dialogs.Settings; using AIStudio.Provider; +using AIStudio.Settings; using AIStudio.Settings.DataModel; using Microsoft.AspNetCore.Components; namespace AIStudio.Assistants.BatchProcessing; -public partial class AssistantBatchProcessing : AssistantBaseCore +public partial class AssistantBatchProcessing : AssistantBaseCore { [Inject] private IDialogService DialogService { get; init; } = null!; - private const string DEFAULT_FILE_PATTERNS = "*.pdf;*.docx;*.pptx;*.xlsx;*.md;*.txt"; private const string DEFAULT_OUTPUT_DIRECTORY_NAME = "ai-results"; private const string DEFAULT_RESULTS_FILENAME = "batch-results.csv"; private const string CSV_EXTENSION = ".csv"; @@ -40,7 +40,7 @@ public partial class AssistantBatchProcessing : AssistantBaseCore false; - protected override bool AllowProfiles => false; + protected override bool AllowProfiles => true; protected override bool ShowSendTo => false; @@ -51,31 +51,39 @@ public partial class AssistantBatchProcessing : AssistantBaseCore false; + protected override bool MightPreselectValues() + { + if (!this.SettingsManager.ConfigurationData.BatchProcessing.PreselectOptions) + return false; + + this.ApplyFormDefaults(); + return true; + } + + protected override async Task OnDefaultsAppliedAsync() + { + await this.LoadConfiguredPromptFileAsync(); + this.ApplyPolicyPreselection(); + } private string inputDirectory = string.Empty; private string outputDirectory = string.Empty; - private string filePatterns = DEFAULT_FILE_PATTERNS; + private string filePatterns = DataBatchProcessing.DEFAULT_FILE_PATTERNS; private bool includeSubdirectories; private BatchProcessingPromptSource promptSource = BatchProcessingPromptSource.FREE_PROMPT; private string freePrompt = string.Empty; private string importedPrompt = string.Empty; + private string promptFilePath = string.Empty; + private string promptFileLoadIssue = string.Empty; private DataDocumentAnalysisPolicy? selectedPolicy; private BatchProcessingOutputMode outputMode = BatchProcessingOutputMode.MARKDOWN_FILES; private string resultColumnHeader = string.Empty; @@ -92,11 +100,163 @@ public partial class AssistantBatchProcessing : AssistantBaseCore private string ResultColumnHeader => string.IsNullOrWhiteSpace(this.resultColumnHeader) ? T("Result") : this.resultColumnHeader.Trim(); + /// + /// Updates the manually imported prompt and stops presenting an obsolete + /// configured path or load error once the user has selected another file. + /// + private string ImportedPrompt + { + get => this.importedPrompt; + set + { + this.importedPrompt = value; + this.promptFilePath = string.Empty; + this.promptFileLoadIssue = string.Empty; + } + } + + private bool ConfiguredPolicyIsMissing + { + get + { + var settings = this.SettingsManager.ConfigurationData.BatchProcessing; + return settings.PreselectOptions + && this.promptSource is BatchProcessingPromptSource.POLICY + && !string.IsNullOrWhiteSpace(settings.PreselectedPolicyId) + && this.selectedPolicy is null; + } + } + private ConfidenceLevel GetMinimumConfidenceLevel() { - if (this.promptSource is BatchProcessingPromptSource.POLICY && this.selectedPolicy is not null) - return this.selectedPolicy.MinimumProviderConfidence; + var minimumLevel = this.SettingsManager.GetMinimumConfidenceLevel(this.Component); + if (this.promptSource is BatchProcessingPromptSource.POLICY + && this.selectedPolicy is not null + && this.selectedPolicy.MinimumProviderConfidence > minimumLevel) + minimumLevel = this.selectedPolicy.MinimumProviderConfidence; - return ConfidenceLevel.NONE; + return minimumLevel; + } + + private void ApplyFormDefaults() + { + var settings = this.SettingsManager.ConfigurationData.BatchProcessing; + if (!settings.PreselectOptions) + { + this.inputDirectory = string.Empty; + this.outputDirectory = string.Empty; + this.filePatterns = DataBatchProcessing.DEFAULT_FILE_PATTERNS; + this.includeSubdirectories = false; + this.promptSource = BatchProcessingPromptSource.FREE_PROMPT; + this.freePrompt = string.Empty; + this.promptFilePath = string.Empty; + this.selectedPolicy = null; + this.outputMode = BatchProcessingOutputMode.MARKDOWN_FILES; + this.resultColumnHeader = string.Empty; + this.csvFileName = string.Empty; + return; + } + + this.inputDirectory = settings.InputDirectory; + this.outputDirectory = settings.OutputDirectory; + this.filePatterns = settings.FilePatterns; + this.includeSubdirectories = settings.IncludeSubdirectories; + this.promptSource = settings.PromptSource; + this.freePrompt = settings.FreePrompt; + this.promptFilePath = settings.PromptFilePath; + this.selectedPolicy = this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies + .FirstOrDefault(policy => policy.Id == settings.PreselectedPolicyId); + this.outputMode = settings.OutputMode; + this.resultColumnHeader = settings.ResultColumnHeader; + this.csvFileName = settings.CsvFileName; + } + + private async Task LoadConfiguredPromptFileAsync() + { + this.promptFileLoadIssue = string.Empty; + if (this.promptSource is not BatchProcessingPromptSource.FILE_IMPORT || string.IsNullOrWhiteSpace(this.promptFilePath)) + return; + + this.importedPrompt = string.Empty; + if (!string.Equals(Path.GetExtension(this.promptFilePath), ".md", StringComparison.OrdinalIgnoreCase)) + { + this.promptFileLoadIssue = T("The configured instructions file must be a Markdown file (*.md)."); + return; + } + + if (!File.Exists(this.promptFilePath)) + { + this.promptFileLoadIssue = T("The configured instructions file no longer exists."); + return; + } + + try + { + this.importedPrompt = await File.ReadAllTextAsync(this.promptFilePath); + if (string.IsNullOrWhiteSpace(this.importedPrompt)) + this.promptFileLoadIssue = T("The configured instructions file is empty."); + } + catch (Exception exception) + { + this.Logger.LogError(exception, "Could not load the configured batch instructions file '{PromptFilePath}'.", this.promptFilePath); + this.promptFileLoadIssue = T("The configured instructions file could not be read."); + } + } + + private void PromptSourceChanged(BatchProcessingPromptSource source) + { + this.promptSource = source; + if (source is BatchProcessingPromptSource.POLICY) + this.ApplyPolicyPreselection(); + else + this.ResetProviderAndProfileSelection(); + } + + private void SelectedPolicyChanged(DataDocumentAnalysisPolicy? policy) + { + this.selectedPolicy = policy; + this.ApplyPolicyPreselection(); + } + + private void ApplyPolicyPreselection() + { + if (this.promptSource is not BatchProcessingPromptSource.POLICY || this.selectedPolicy is null) + return; + + var minimumLevel = this.GetMinimumConfidenceLevel(); + var policyProvider = this.SettingsManager.GetPreselectedProvider(this.Component, this.selectedPolicy.PreselectedProvider); + if (policyProvider != Settings.Provider.NONE + && policyProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level >= minimumLevel) + this.ProviderSettings = policyProvider; + else + { + var fallbackProvider = this.SettingsManager.GetPreselectedProvider(this.Component, usePreselectionBeforeCurrentProvider: true); + this.ProviderSettings = fallbackProvider != Settings.Provider.NONE + && fallbackProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level >= minimumLevel + ? fallbackProvider + : Settings.Provider.NONE; + } + + this.CurrentProfile = this.ResolvePolicyProfile(); + } + + private Profile ResolvePolicyProfile() + { + if (this.selectedPolicy is null) + return this.SettingsManager.GetPreselectedProfile(this.Component); + + var policyProfile = ProfilePreselection.FromStoredValue(this.selectedPolicy.PreselectedProfile); + if (policyProfile.DoNotPreselectProfile) + return Profile.NO_PROFILE; + + if (policyProfile.UseSpecificProfile) + { + var profile = this.SettingsManager.ConfigurationData.Profiles + .FirstOrDefault(candidate => candidate.Id == policyProfile.SpecificProfileId); + if (profile is not null) + return profile; + } + + return this.SettingsManager.GetPreselectedProfile(this.Component); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor new file mode 100644 index 00000000..2807e156 --- /dev/null +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor @@ -0,0 +1,58 @@ +@using AIStudio.Assistants.BatchProcessing +@using AIStudio.Settings +@inherits SettingsDialogBase + + + + + + @T("Assistant: Batch Processing defaults") + + + + + + + @T("Input") + + + + + @T("Instructions") + + @if (this.SettingsManager.ConfigurationData.BatchProcessing.PromptSource is BatchProcessingPromptSource.FREE_PROMPT) + { + + } + else if (this.SettingsManager.ConfigurationData.BatchProcessing.PromptSource is BatchProcessingPromptSource.FILE_IMPORT) + { + + } + else + { + + @if (this.SelectedPolicyMissing) + { + @T("The configured default policy no longer exists. Select another policy before starting a policy-based batch run.") + } + } + + @T("Output") + + @if (this.SettingsManager.ConfigurationData.BatchProcessing.OutputMode is BatchProcessingOutputMode.TABLE_ONLY) + { + + + } + + + @T("AI selection") + + + + + + + @T("Close") + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs new file mode 100644 index 00000000..178ed741 --- /dev/null +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs @@ -0,0 +1,48 @@ +using AIStudio.Assistants.BatchProcessing; +using AIStudio.Settings; + +namespace AIStudio.Dialogs.Settings; + +public partial class SettingsDialogBatchProcessing : SettingsDialogBase +{ + private bool DefaultsDisabled() => !this.SettingsManager.ConfigurationData.BatchProcessing.PreselectOptions; + + private IReadOnlyList> PromptSourceData => + [ + .. Enum + .GetValues() + .Select(value => new ConfigurationSelectData(value.Name(), value)) + ]; + + private IReadOnlyList> OutputModeData => + [ + .. Enum + .GetValues() + .Select(value => new ConfigurationSelectData(value.Name(), value)) + ]; + + private IReadOnlyList> PolicyData + { + get + { + var selectedPolicyId = this.SettingsManager.ConfigurationData.BatchProcessing.PreselectedPolicyId; + var policies = this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies + .Select(policy => new ConfigurationSelectData(policy.PolicyName, policy.Id)) + .ToList(); + + if (this.SelectedPolicyMissing) + policies.Add(new(string.Format(T("Missing policy ({0})"), selectedPolicyId), selectedPolicyId)); + + return policies; + } + } + + private bool SelectedPolicyMissing + { + get + { + var selectedPolicyId = this.SettingsManager.ConfigurationData.BatchProcessing.PreselectedPolicyId; + return !string.IsNullOrWhiteSpace(selectedPolicyId) && this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.All(policy => policy.Id != selectedPolicyId); + } + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua index a3a3e68a..0104e634 100644 --- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua +++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua @@ -394,6 +394,62 @@ CONFIG["SETTINGS"] = {} -- CONFIG["SETTINGS"]["DataChat.PreselectedDataSourceIds.AllowUserOverride"] = true -- CONFIG["SETTINGS"]["DataChat.SendToChatDataSourceBehavior.AllowUserOverride"] = true +-- Configure defaults for the Batch Processing Assistant. +-- Preselection must be enabled for the remaining batch settings to take effect. +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectOptions"] = true +-- +-- Configure the default input and output folders. +-- Leave the input folder empty to require a selection for every new batch run. +-- Leave the output folder empty to use the ai-results subfolder of the input folder. +-- CONFIG["SETTINGS"]["DataBatchProcessing.InputDirectory"] = "" +-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputDirectory"] = "" +-- +-- Configure the default file patterns and whether subfolders are included. +-- Separate multiple patterns with semicolons. +-- CONFIG["SETTINGS"]["DataBatchProcessing.FilePatterns"] = "*.pdf;*.docx;*.pptx;*.xlsx;*.md;*.txt" +-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeSubdirectories"] = false +-- +-- Configure the default instruction source. +-- Allowed values are: FREE_PROMPT, FILE_IMPORT, POLICY +-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptSource"] = "FREE_PROMPT" +-- CONFIG["SETTINGS"]["DataBatchProcessing.FreePrompt"] = "Summarize each document." +-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptFilePath"] = "" +-- +-- The policy ID must reference an entry in CONFIG["DOCUMENT_ANALYSIS_POLICIES"] or a +-- user-configured policy. It is used only when PromptSource is POLICY. +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedPolicyId"] = "" +-- +-- Configure the default output mode. +-- Allowed values are: MARKDOWN_FILES, TABLE_ONLY +-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputMode"] = "MARKDOWN_FILES" +-- CONFIG["SETTINGS"]["DataBatchProcessing.CsvFileName"] = "batch-results.csv" +-- CONFIG["SETTINGS"]["DataBatchProcessing.ResultColumnHeader"] = "Result" +-- +-- Configure the minimum provider confidence and the default provider and profile. +-- Allowed confidence values are: NONE, UNTRUSTED, UNKNOWN, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH +-- A policy can require a higher minimum confidence; the stricter level wins. +-- CONFIG["SETTINGS"]["DataBatchProcessing.MinimumProviderConfidence"] = "NONE" +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedProvider"] = "00000000-0000-0000-0000-000000000000" +-- Please note: an empty profile ID uses the app default profile; the all-zero ID uses no profile. +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedProfile"] = "" +-- +-- Allow users to change individual managed batch defaults locally. +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectOptions.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.InputDirectory.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputDirectory.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.FilePatterns.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeSubdirectories.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptSource.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.FreePrompt.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptFilePath.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedPolicyId.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputMode.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.CsvFileName.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.ResultColumnHeader.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.MinimumProviderConfidence.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedProvider.AllowUserOverride"] = true +-- CONFIG["SETTINGS"]["DataBatchProcessing.PreselectedProfile.AllowUserOverride"] = true + -- Configure the transcription provider for voice-to-text functionality. -- It must be one of the transcription provider IDs defined in CONFIG["TRANSCRIPTION_PROVIDERS"]. -- Without a selected transcription provider, dictation and transcription features will be disabled. @@ -407,7 +463,8 @@ CONFIG["SETTINGS"] = {} -- CODING_ASSISTANT, TEXT_SUMMARIZER_ASSISTANT, EMAIL_ASSISTANT, -- LEGAL_CHECK_ASSISTANT, SYNONYMS_ASSISTANT, MY_TASKS_ASSISTANT, -- JOB_POSTING_ASSISTANT, BIAS_DAY_ASSISTANT, ERI_ASSISTANT, --- DOCUMENT_ANALYSIS_ASSISTANT, SLIDE_BUILDER_ASSISTANT, VISUAL_BRIEFING_ASSISTANT, I18N_ASSISTANT, +-- DOCUMENT_ANALYSIS_ASSISTANT, BATCH_PROCESSING_ASSISTANT, SLIDE_BUILDER_ASSISTANT, +-- VISUAL_BRIEFING_ASSISTANT, I18N_ASSISTANT, -- LOG_VIEWER_ASSISTANT -- -- Replaces, does not merge: a configuration with a higher priority replaces this list diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs index 9909b3af..bae5dace 100644 --- a/app/MindWork AI Studio/Settings/DataModel/Data.cs +++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs @@ -136,6 +136,11 @@ public sealed class Data public DataDocumentAnalysis DocumentAnalysis { get; init; } = new(); + /// + /// Gets the managed Batch Processing Assistant defaults. + /// + public DataBatchProcessing BatchProcessing { get; init; } = new(x => x.BatchProcessing); + public DataMandatoryInformation MandatoryInformation { get; init; } = new(); public DataTextSummarizer TextSummarizer { get; init; } = new(); @@ -176,4 +181,4 @@ public sealed class Data public DataBiasOfTheDay BiasOfTheDay { get; init; } = new(); public DataI18N I18N { get; init; } = new(); -} +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs b/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs new file mode 100644 index 00000000..d15843a5 --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs @@ -0,0 +1,52 @@ +using System.Linq.Expressions; + +using AIStudio.Assistants.BatchProcessing; +using AIStudio.Provider; + +namespace AIStudio.Settings.DataModel; + +/// +/// Stores managed defaults for the Batch Processing Assistant. +/// +/// The managed-configuration selector. +public sealed class DataBatchProcessing(Expression>? configSelection = null) +{ + public const string DEFAULT_FILE_PATTERNS = "*.pdf;*.docx;*.pptx;*.xlsx;*.md;*.txt"; + + /// + /// Initializes an unmanaged Batch Processing settings instance. + /// + public DataBatchProcessing() : this(null) + { + } + + public bool PreselectOptions { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PreselectOptions, false); + + public string InputDirectory { get; set; } = ManagedConfiguration.Register(configSelection, value => value.InputDirectory, string.Empty); + + public string OutputDirectory { get; set; } = ManagedConfiguration.Register(configSelection, value => value.OutputDirectory, string.Empty); + + public string FilePatterns { get; set; } = ManagedConfiguration.Register(configSelection, value => value.FilePatterns, DEFAULT_FILE_PATTERNS); + + public bool IncludeSubdirectories { get; set; } = ManagedConfiguration.Register(configSelection, value => value.IncludeSubdirectories, false); + + public BatchProcessingPromptSource PromptSource { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PromptSource, BatchProcessingPromptSource.FREE_PROMPT); + + public string FreePrompt { get; set; } = ManagedConfiguration.Register(configSelection, value => value.FreePrompt, string.Empty); + + public string PromptFilePath { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PromptFilePath, string.Empty); + + public string PreselectedPolicyId { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PreselectedPolicyId, string.Empty); + + public BatchProcessingOutputMode OutputMode { get; set; } = ManagedConfiguration.Register(configSelection, value => value.OutputMode, BatchProcessingOutputMode.MARKDOWN_FILES); + + public string CsvFileName { get; set; } = ManagedConfiguration.Register(configSelection, value => value.CsvFileName, string.Empty); + + public string ResultColumnHeader { get; set; } = ManagedConfiguration.Register(configSelection, value => value.ResultColumnHeader, string.Empty); + + public ConfidenceLevel MinimumProviderConfidence { get; set; } = ManagedConfiguration.Register(configSelection, value => value.MinimumProviderConfidence, ConfidenceLevel.NONE); + + public string PreselectedProvider { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PreselectedProvider, string.Empty); + + public string PreselectedProfile { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PreselectedProfile, string.Empty); +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs index 3a3f9162..0b22662b 100644 --- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs +++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs @@ -157,9 +157,9 @@ public static class ComponentsExtensions // We do this inside the Document Analysis Assistant component: Components.DOCUMENT_ANALYSIS_ASSISTANT => ConfidenceLevel.NONE, - // The minimum confidence for the Batch Processing Assistant is set per policy - // as well. We do this inside the Batch Processing Assistant component: - Components.BATCH_PROCESSING_ASSISTANT => ConfidenceLevel.NONE, + // A policy-specific minimum is merged with this component default inside + // the Batch Processing Assistant; the stricter level wins. + Components.BATCH_PROCESSING_ASSISTANT => settingsManager.ConfigurationData.BatchProcessing.PreselectOptions ? settingsManager.ConfigurationData.BatchProcessing.MinimumProviderConfidence : default, _ => default, }; @@ -192,6 +192,8 @@ public static class ComponentsExtensions // The provider is selected per policy instead. We do this inside the Document Analysis Assistant component. Components.DOCUMENT_ANALYSIS_ASSISTANT => Settings.Provider.NONE, + Components.BATCH_PROCESSING_ASSISTANT => settingsManager.ConfigurationData.BatchProcessing.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.BatchProcessing.PreselectedProvider) : null, + Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProvider) : null, Components.AGENT_TEXT_CONTENT_CLEANER => settingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.TextContentCleaner.PreselectedAgentProvider) : null, @@ -218,6 +220,7 @@ public static class ComponentsExtensions Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.ERI.PreselectedProfile : string.Empty, Components.SLIDE_BUILDER_ASSISTANT => settingsManager.ConfigurationData.SlideBuilder.PreselectOptions ? settingsManager.ConfigurationData.SlideBuilder.PreselectedProfile : string.Empty, Components.VISUAL_BRIEFING_ASSISTANT => settingsManager.ConfigurationData.VisualBriefing.PreselectedProfile, + Components.BATCH_PROCESSING_ASSISTANT => settingsManager.ConfigurationData.BatchProcessing.PreselectOptions ? settingsManager.ConfigurationData.BatchProcessing.PreselectedProfile : string.Empty, Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Chat.PreselectedProfile : string.Empty, // The Document Analysis Assistant does not have a preselected profile at the component level. @@ -236,4 +239,4 @@ public static class ComponentsExtensions _ => ChatTemplate.NO_CHAT_TEMPLATE, }; -} +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs index 4134ed60..655fb2e9 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs @@ -337,6 +337,23 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT ManagedConfiguration.TryProcessConfiguration(x => x.Chat, x => x.PreselectedDataSourceIds, this.Id, settingsTable, dryRun); ManagedConfiguration.TryProcessConfiguration(x => x.Chat, x => x.SendToChatDataSourceBehavior, this.Id, settingsTable, dryRun); + // Config: Batch Processing Assistant defaults? + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PreselectOptions, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.InputDirectory, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.OutputDirectory, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.FilePatterns, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.IncludeSubdirectories, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PromptSource, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.FreePrompt, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PromptFilePath, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PreselectedPolicyId, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.OutputMode, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.CsvFileName, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.ResultColumnHeader, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.MinimumProviderConfidence, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PreselectedProvider, Guid.Empty, this.Id, settingsTable, dryRun); + ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PreselectedProfile, this.Id, settingsTable, dryRun); + // Config: transcription provider? ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.UseTranscriptionProvider, Guid.Empty, this.Id, settingsTable, dryRun); @@ -572,4 +589,4 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT LOG.LogWarning("The table 'INTRODUCTIONS' entry at index {Index} does not contain a valid introduction (config plugin id: {ConfigPluginId}).", i, this.Id); } } -} +} \ No newline at end of file