From f6091be1b0c8b2c7ac752a0104336739ede3590c Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 31 Jan 2026 20:50:10 +0100 Subject: [PATCH] Add support for document analysis policy configuration --- .../DocumentAnalysisAssistant.razor | 2 +- .../DocumentAnalysisAssistant.razor.cs | 2 + .../Plugins/configuration/plugin.lua | 29 +++++ .../Settings/DataModel/Data.cs | 5 + .../DataModel/DataDocumentAnalysisPolicy.cs | 106 ++++++++++++++++-- .../Tools/PluginSystem/PluginConfiguration.cs | 3 + .../PluginSystem/PluginConfigurationObject.cs | 2 + .../PluginConfigurationObjectType.cs | 1 + .../PluginSystem/PluginFactory.Loading.cs | 4 + .../wwwroot/changelog/v26.2.1.md | 1 + 10 files changed, 145 insertions(+), 10 deletions(-) diff --git a/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor b/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor index c1c1d8f1..4f57754d 100644 --- a/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor +++ b/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor @@ -64,7 +64,7 @@ else - + @T("Analysis and output rules") diff --git a/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor.cs b/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor.cs index 94ad313a..bbdcb994 100644 --- a/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor.cs +++ b/app/MindWork AI Studio/Assistants/DocumentAnalysis/DocumentAnalysisAssistant.razor.cs @@ -283,6 +283,8 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore public uint NextChatTemplateNum { get; set; } = 1; + + /// + /// The next document analysis policy number to use. + /// + public uint NextDocumentAnalysisPolicyNum { get; set; } = 1; public DataApp App { get; init; } = new(x => x.App); diff --git a/app/MindWork AI Studio/Settings/DataModel/DataDocumentAnalysisPolicy.cs b/app/MindWork AI Studio/Settings/DataModel/DataDocumentAnalysisPolicy.cs index aae8ede1..bbfee658 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataDocumentAnalysisPolicy.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataDocumentAnalysisPolicy.cs @@ -1,16 +1,37 @@ using AIStudio.Provider; +using AIStudio.Tools.PluginSystem; + +using Lua; namespace AIStudio.Settings.DataModel; -public sealed class DataDocumentAnalysisPolicy +public sealed record DataDocumentAnalysisPolicy : ConfigurationBaseObject { + private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(); + + /// + public override string Id { get; init; } = string.Empty; + + /// + public override uint Num { get; init; } + + /// + public override string Name + { + get => this.PolicyName; + init => this.PolicyName = value; + } + + /// + public override bool IsEnterpriseConfiguration { get; init; } + /// - /// Preselect the policy name? + /// The name of the document analysis policy. /// public string PolicyName { get; set; } = string.Empty; /// - /// Preselect the policy description? + /// The description of the document analysis policy. /// public string PolicyDescription { get; set; } = string.Empty; @@ -18,12 +39,9 @@ public sealed class DataDocumentAnalysisPolicy /// Is this policy protected? If so, it cannot be deleted or modified by the user. /// public bool IsProtected { get; set; } - - /// - /// Is this a managed policy? Managed policies are created and managed by the organization - /// and cannot be modified or deleted by the user. - /// - public bool IsManaged { get; set; } + + /// + public override Guid EnterpriseConfigurationPluginId { get; init; } = Guid.Empty; /// /// The rules for the document analysis policy. @@ -49,4 +67,74 @@ public sealed class DataDocumentAnalysisPolicy /// Preselect a profile? /// public string PreselectedProfile { get; set; } = string.Empty; + + public static bool TryProcessConfiguration(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject policy) + { + policy = new DataDocumentAnalysisPolicy(); + if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead(out var idText) || !Guid.TryParse(idText, out var id)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} does not contain a valid ID. The ID must be a valid GUID.", idx); + return false; + } + + if (!table.TryGetValue("PolicyName", out var nameValue) || !nameValue.TryRead(out var name) || string.IsNullOrWhiteSpace(name)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} does not contain a valid PolicyName field.", idx); + return false; + } + + if (!table.TryGetValue("PolicyDescription", out var descriptionValue) || !descriptionValue.TryRead(out var description) || string.IsNullOrWhiteSpace(description)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} does not contain a valid PolicyDescription field.", idx); + return false; + } + + if (!table.TryGetValue("AnalysisRules", out var analysisRulesValue) || !analysisRulesValue.TryRead(out var analysisRules) || string.IsNullOrWhiteSpace(analysisRules)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} does not contain valid AnalysisRules field.", idx); + return false; + } + + if (!table.TryGetValue("OutputRules", out var outputRulesValue) || !outputRulesValue.TryRead(out var outputRules) || string.IsNullOrWhiteSpace(outputRules)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} does not contain valid OutputRules field.", idx); + return false; + } + + var minimumConfidence = ConfidenceLevel.NONE; + if (table.TryGetValue("MinimumProviderConfidence", out var minConfValue) && minConfValue.TryRead(out var minConfText)) + { + if (!Enum.TryParse(minConfText, true, out minimumConfidence)) + { + LOG.LogWarning("The configured document analysis policy {PolicyIndex} contains an invalid MinimumProviderConfidence: {ConfidenceLevel}.", idx, minConfText); + minimumConfidence = ConfidenceLevel.NONE; + } + } + + var preselectedProvider = string.Empty; + if (table.TryGetValue("PreselectedProvider", out var providerValue) && providerValue.TryRead(out var providerId)) + preselectedProvider = providerId; + + var preselectedProfile = string.Empty; + if (table.TryGetValue("PreselectedProfile", out var profileValue) && profileValue.TryRead(out var profileId)) + preselectedProfile = profileId; + + policy = new DataDocumentAnalysisPolicy + { + Id = id.ToString(), + Num = 0, // will be set later by the PluginConfigurationObject + PolicyName = name, + PolicyDescription = description, + AnalysisRules = analysisRules, + OutputRules = outputRules, + MinimumProviderConfidence = minimumConfidence, + PreselectedProvider = preselectedProvider, + PreselectedProfile = preselectedProfile, + IsProtected = true, + IsEnterpriseConfiguration = true, + EnterpriseConfigurationPluginId = configPluginId, + }; + + return true; + } } \ 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 e85c8eba..29d95e76 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs @@ -88,6 +88,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT // Handle configured profiles: PluginConfigurationObject.TryParse(PluginConfigurationObjectType.PROFILE, x => x.Profiles, x => x.NextProfileNum, mainTable, this.Id, ref this.configObjects, dryRun); + // Handle configured document analysis policies: + PluginConfigurationObject.TryParse(PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY, x => x.DocumentAnalysis.Policies, x => x.NextDocumentAnalysisPolicyNum, mainTable, this.Id, ref this.configObjects, dryRun); + // Config: preselected profile? ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.PreselectedProfile, Guid.Empty, this.Id, settingsTable, dryRun); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs index da5c46c2..647c79bf 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs @@ -70,6 +70,7 @@ public sealed record PluginConfigurationObject PluginConfigurationObjectType.EMBEDDING_PROVIDER => "EMBEDDING_PROVIDERS", PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER => "TRANSCRIPTION_PROVIDERS", PluginConfigurationObjectType.PROFILE => "PROFILES", + PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY => "DOCUMENT_ANALYSIS_POLICIES", _ => null, }; @@ -105,6 +106,7 @@ public sealed record PluginConfigurationObject PluginConfigurationObjectType.PROFILE => (Profile.TryParseProfileTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Profile.NO_PROFILE, configurationObject), PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER => (TranscriptionProvider.TryParseTranscriptionProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != TranscriptionProvider.NONE, configurationObject), PluginConfigurationObjectType.EMBEDDING_PROVIDER => (EmbeddingProvider.TryParseEmbeddingProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != EmbeddingProvider.NONE, configurationObject), + PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY => (DataDocumentAnalysisPolicy.TryProcessConfiguration(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject is DataDocumentAnalysisPolicy, configurationObject), _ => (false, NoConfigurationObject.INSTANCE) }; diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectType.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectType.cs index 82931873..4236af12 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectType.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectType.cs @@ -11,4 +11,5 @@ public enum PluginConfigurationObjectType CHAT_TEMPLATE, EMBEDDING_PROVIDER, TRANSCRIPTION_PROVIDER, + DOCUMENT_ANALYSIS_POLICY, } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs index bdfdba81..b2b45aba 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs @@ -148,6 +148,10 @@ public static partial class PluginFactory // Check profiles: if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.PROFILE, x => x.Profiles, AVAILABLE_PLUGINS, configObjectList)) wasConfigurationChanged = true; + + // Check document analysis policies: + if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY, x => x.DocumentAnalysis.Policies, AVAILABLE_PLUGINS, configObjectList)) + wasConfigurationChanged = true; // Check for a preselected profile: if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.PreselectedProfile, AVAILABLE_PLUGINS)) diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.2.1.md b/app/MindWork AI Studio/wwwroot/changelog/v26.2.1.md index e1c8b7c2..9d465ece 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.2.1.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.2.1.md @@ -1,3 +1,4 @@ # v26.2.1, build 233 (2026-02-xx xx:xx UTC) - Added the ability to individually configure the minimum confidence level, standard profile, and default provider for each policy in the Document Analysis Assistant (in preview). +- Added support for defining document analysis policies (in preview) by configuration plugins, enabling centralized management of policies across entire departments or organizations. - Fixed a bug where the global minimum confidence level was not being applied to the assistants. \ No newline at end of file