From dcf6cd3728eb21b149918342b8ae992653375d17 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Thu, 5 Feb 2026 10:35:20 +0100 Subject: [PATCH] Added configuration export for providers --- .../Components/Settings/SettingsPanelBase.cs | 3 + .../Settings/SettingsPanelEmbeddings.razor | 3 + .../Settings/SettingsPanelEmbeddings.razor.cs | 13 +++ .../Settings/SettingsPanelProviders.razor | 3 + .../Settings/SettingsPanelProviders.razor.cs | 13 +++ .../Settings/SettingsPanelTranscription.razor | 3 + .../SettingsPanelTranscription.razor.cs | 13 +++ .../Tools/PluginSystem/ConfigurationExport.cs | 95 +++++++++++++++++++ .../wwwroot/changelog/v26.2.2.md | 1 + 9 files changed, 147 insertions(+) create mode 100644 app/MindWork AI Studio/Tools/PluginSystem/ConfigurationExport.cs diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelBase.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelBase.cs index bad3fca3..871d8353 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelBase.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelBase.cs @@ -15,4 +15,7 @@ public abstract class SettingsPanelBase : MSGComponentBase [Inject] protected RustService RustService { get; init; } = null!; + + [Inject] + protected ISnackbar Snackbar { get; init; } = null!; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor index 874bc3c9..85f69ca2 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor @@ -53,6 +53,9 @@ + + + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs index 94878987..76e4355a 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs @@ -1,5 +1,6 @@ using AIStudio.Dialogs; using AIStudio.Settings; +using AIStudio.Tools.PluginSystem; using Microsoft.AspNetCore.Components; @@ -114,6 +115,18 @@ public partial class SettingsPanelEmbeddings : SettingsPanelBase await this.UpdateEmbeddingProviders(); await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); } + + private async Task ExportEmbeddingProvider(EmbeddingProvider provider) + { + if (provider == EmbeddingProvider.NONE) + return; + + var luaCode = ConfigurationExport.ExportEmbeddingProvider(provider); + if (string.IsNullOrWhiteSpace(luaCode)) + return; + + await this.RustService.CopyText2Clipboard(this.Snackbar, luaCode); + } private async Task UpdateEmbeddingProviders() { diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor index 3d359408..d555a31a 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor @@ -45,6 +45,9 @@ + + + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs index 2272959d..91518fab 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using AIStudio.Dialogs; using AIStudio.Provider; using AIStudio.Settings; +using AIStudio.Tools.PluginSystem; using Microsoft.AspNetCore.Components; @@ -134,6 +135,18 @@ public partial class SettingsPanelProviders : SettingsPanelBase await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); } + private async Task ExportLLMProvider(AIStudio.Settings.Provider provider) + { + if (provider == AIStudio.Settings.Provider.NONE) + return; + + var luaCode = ConfigurationExport.ExportProvider(provider); + if (string.IsNullOrWhiteSpace(luaCode)) + return; + + await this.RustService.CopyText2Clipboard(this.Snackbar, luaCode); + } + private string GetLLMProviderModelName(AIStudio.Settings.Provider provider) { // For system models, return localized text: diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor index aff415b2..009d31bc 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor @@ -50,6 +50,9 @@ + + + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs index 243200a3..c4b76739 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs @@ -1,5 +1,6 @@ using AIStudio.Dialogs; using AIStudio.Settings; +using AIStudio.Tools.PluginSystem; using Microsoft.AspNetCore.Components; @@ -114,6 +115,18 @@ public partial class SettingsPanelTranscription : SettingsPanelBase await this.UpdateTranscriptionProviders(); await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); } + + private async Task ExportTranscriptionProvider(TranscriptionProvider provider) + { + if (provider == TranscriptionProvider.NONE) + return; + + var luaCode = ConfigurationExport.ExportTranscriptionProvider(provider); + if (string.IsNullOrWhiteSpace(luaCode)) + return; + + await this.RustService.CopyText2Clipboard(this.Snackbar, luaCode); + } private async Task UpdateTranscriptionProviders() { diff --git a/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationExport.cs b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationExport.cs new file mode 100644 index 00000000..fb0df8fe --- /dev/null +++ b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationExport.cs @@ -0,0 +1,95 @@ +using AIStudio.Provider.HuggingFace; + +namespace AIStudio.Tools.PluginSystem; + +public static class ConfigurationExport +{ + public static string ExportProvider(AIStudio.Settings.Provider provider) + { + if (provider == Settings.Provider.NONE) + return string.Empty; + + var hfInferenceProviderLine = provider.HFInferenceProvider is not HFInferenceProvider.NONE + ? $" [\"HFInferenceProvider\"] = \"{provider.HFInferenceProvider}\",\n" + : string.Empty; + + return $$""" + CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = { + ["Id"] = "{{EscapeLuaString(NormalizeId(provider.Id))}}", + ["InstanceName"] = "{{EscapeLuaString(provider.InstanceName)}}", + ["UsedLLMProvider"] = "{{provider.UsedLLMProvider}}", + + ["Host"] = "{{provider.Host}}", + ["Hostname"] = "{{EscapeLuaString(provider.Hostname)}}", + {{hfInferenceProviderLine}} + ["AdditionalJsonApiParameters"] = "{{EscapeLuaString(provider.AdditionalJsonApiParameters)}}", + ["Model"] = { + ["Id"] = "{{EscapeLuaString(provider.Model.Id)}}", + ["DisplayName"] = "{{EscapeLuaString(provider.Model.DisplayName ?? string.Empty)}}", + }, + } + """; + } + + public static string ExportEmbeddingProvider(Settings.EmbeddingProvider provider) + { + if (provider == Settings.EmbeddingProvider.NONE) + return string.Empty; + + return $$""" + CONFIG["EMBEDDING_PROVIDERS"][#CONFIG["EMBEDDING_PROVIDERS"]+1] = { + ["Id"] = "{{EscapeLuaString(NormalizeId(provider.Id))}}", + ["Name"] = "{{EscapeLuaString(provider.Name)}}", + ["UsedLLMProvider"] = "{{provider.UsedLLMProvider}}", + + ["Host"] = "{{provider.Host}}", + ["Hostname"] = "{{EscapeLuaString(provider.Hostname)}}", + ["Model"] = { + ["Id"] = "{{EscapeLuaString(provider.Model.Id)}}", + ["DisplayName"] = "{{EscapeLuaString(provider.Model.DisplayName ?? string.Empty)}}", + }, + } + """; + } + + public static string ExportTranscriptionProvider(Settings.TranscriptionProvider provider) + { + if (provider == Settings.TranscriptionProvider.NONE) + return string.Empty; + + return $$""" + CONFIG["TRANSCRIPTION_PROVIDERS"][#CONFIG["TRANSCRIPTION_PROVIDERS"]+1] = { + ["Id"] = "{{EscapeLuaString(NormalizeId(provider.Id))}}", + ["Name"] = "{{EscapeLuaString(provider.Name)}}", + ["UsedLLMProvider"] = "{{provider.UsedLLMProvider}}", + + ["Host"] = "{{provider.Host}}", + ["Hostname"] = "{{EscapeLuaString(provider.Hostname)}}", + ["Model"] = { + ["Id"] = "{{EscapeLuaString(provider.Model.Id)}}", + ["DisplayName"] = "{{EscapeLuaString(provider.Model.DisplayName ?? string.Empty)}}", + }, + } + """; + } + + private static string NormalizeId(string? id) + { + if (!string.IsNullOrWhiteSpace(id)) + return id; + + return Guid.NewGuid().ToString(); + } + + private static string EscapeLuaString(string? value) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + + return value + .Replace("\\", "\\\\") + .Replace("\"", "\\\"") + .Replace("\r", "\\r") + .Replace("\n", "\\n"); + } +} diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.2.2.md b/app/MindWork AI Studio/wwwroot/changelog/v26.2.2.md index 00d385a9..d9105bcb 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.2.2.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.2.2.md @@ -1,4 +1,5 @@ # v26.2.2, build 234 (2026-02-xx xx:xx UTC) - Added a vector database (Qdrant) as a building block for our local RAG (retrieval-augmented generation) solution. Thank you very much, Paul (`PaulKoudelka`), for this major contribution. Note that our local RAG implementation remained in preview and has not yet been released; other building blocks are not yet ready. - Added an app setting to enable administration options for IT staff to configure and maintain organization-wide settings. +- Added an option to export all provider types (LLMs, embeddings, transcriptions) for use in a configuration plugin. This feature appears only when administration options are enabled. - Improved the document analysis assistant (in beta) by hiding the export functionality by default. Enable the administration options in the app settings to show and use the export functionality. This streamlines the usage for regular users. \ No newline at end of file