mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-12 17:01:36 +00:00
Added embedding provider config (#622)
This commit is contained in:
parent
30197cf507
commit
7110fb866f
@ -38,16 +38,25 @@
|
|||||||
<MudTd>@GetEmbeddingProviderModelName(context)</MudTd>
|
<MudTd>@GetEmbeddingProviderModelName(context)</MudTd>
|
||||||
|
|
||||||
<MudTd>
|
<MudTd>
|
||||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||||
<MudTooltip Text="@T("Open Dashboard")">
|
@if (context.IsEnterpriseConfiguration)
|
||||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.OpenInBrowser" Href="@context.UsedLLMProvider.GetDashboardURL()" Target="_blank" Disabled="@(!context.UsedLLMProvider.HasDashboard())"/>
|
{
|
||||||
</MudTooltip>
|
<MudTooltip Text="@T("This embedding provider is managed by your organization.")">
|
||||||
<MudTooltip Text="@T("Edit")">
|
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditEmbeddingProvider(context))"/>
|
</MudTooltip>
|
||||||
</MudTooltip>
|
}
|
||||||
<MudTooltip Text="@T("Delete")">
|
else
|
||||||
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DeleteEmbeddingProvider(context))"/>
|
{
|
||||||
</MudTooltip>
|
<MudTooltip Text="@T("Open Dashboard")">
|
||||||
|
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.OpenInBrowser" Href="@context.UsedLLMProvider.GetDashboardURL()" Target="_blank" Disabled="@(!context.UsedLLMProvider.HasDashboard())"/>
|
||||||
|
</MudTooltip>
|
||||||
|
<MudTooltip Text="@T("Edit")">
|
||||||
|
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditEmbeddingProvider(context))"/>
|
||||||
|
</MudTooltip>
|
||||||
|
<MudTooltip Text="@T("Delete")">
|
||||||
|
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DeleteEmbeddingProvider(context))"/>
|
||||||
|
</MudTooltip>
|
||||||
|
}
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
|
|||||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId).IsSelfHosted;
|
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||||
|
|
||||||
private DataSourceLocalDirectory CreateDataSource() => new()
|
private DataSourceLocalDirectory CreateDataSource() => new()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase, IAsy
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
this.embeddingProvider = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.DataSource.EmbeddingId);
|
this.embeddingProvider = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.DataSource.EmbeddingId) ?? EmbeddingProvider.NONE;
|
||||||
this.directoryInfo = new DirectoryInfo(this.DataSource.Path);
|
this.directoryInfo = new DirectoryInfo(this.DataSource.Path);
|
||||||
|
|
||||||
if (this.directoryInfo.Exists)
|
if (this.directoryInfo.Exists)
|
||||||
@ -46,7 +46,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase, IAsy
|
|||||||
|
|
||||||
private readonly CancellationTokenSource cts = new();
|
private readonly CancellationTokenSource cts = new();
|
||||||
|
|
||||||
private EmbeddingProvider embeddingProvider;
|
private EmbeddingProvider embeddingProvider = EmbeddingProvider.NONE;
|
||||||
private DirectoryInfo directoryInfo = null!;
|
private DirectoryInfo directoryInfo = null!;
|
||||||
private long directorySizeBytes;
|
private long directorySizeBytes;
|
||||||
private long directorySizeNumFiles;
|
private long directorySizeNumFiles;
|
||||||
|
|||||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId).IsSelfHosted;
|
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||||
|
|
||||||
private DataSourceLocalFile CreateDataSource() => new()
|
private DataSourceLocalFile CreateDataSource() => new()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -18,14 +18,14 @@ public partial class DataSourceLocalFileInfoDialog : MSGComponentBase
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
this.embeddingProvider = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.DataSource.EmbeddingId);
|
this.embeddingProvider = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.DataSource.EmbeddingId) ?? EmbeddingProvider.NONE;
|
||||||
this.fileInfo = new FileInfo(this.DataSource.FilePath);
|
this.fileInfo = new FileInfo(this.DataSource.FilePath);
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private EmbeddingProvider embeddingProvider;
|
private EmbeddingProvider embeddingProvider = EmbeddingProvider.NONE;
|
||||||
private FileInfo fileInfo = null!;
|
private FileInfo fileInfo = null!;
|
||||||
|
|
||||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
||||||
|
|||||||
@ -129,6 +129,8 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
|||||||
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
|
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
|
||||||
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
|
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
|
||||||
Host = this.DataHost,
|
Host = this.DataHost,
|
||||||
|
IsEnterpriseConfiguration = false,
|
||||||
|
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,6 +70,24 @@ CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Embedding providers for local RAG (Retrieval-Augmented Generation) functionality:
|
||||||
|
CONFIG["EMBEDDING_PROVIDERS"] = {}
|
||||||
|
|
||||||
|
-- An example of an embedding provider configuration:
|
||||||
|
-- CONFIG["EMBEDDING_PROVIDERS"][#CONFIG["EMBEDDING_PROVIDERS"]+1] = {
|
||||||
|
-- ["Id"] = "00000000-0000-0000-0000-000000000000",
|
||||||
|
-- ["Name"] = "<user-friendly name for the embedding provider>",
|
||||||
|
-- ["UsedLLMProvider"] = "SELF_HOSTED",
|
||||||
|
--
|
||||||
|
-- -- Allowed values for Host are: LM_STUDIO, LLAMACPP, OLLAMA, and VLLM
|
||||||
|
-- ["Host"] = "OLLAMA",
|
||||||
|
-- ["Hostname"] = "<https address of the server>",
|
||||||
|
-- ["Model"] = {
|
||||||
|
-- ["Id"] = "<the model ID, e.g., nomic-embed-text>",
|
||||||
|
-- ["DisplayName"] = "<user-friendly name of the model>",
|
||||||
|
-- }
|
||||||
|
-- }
|
||||||
|
|
||||||
CONFIG["SETTINGS"] = {}
|
CONFIG["SETTINGS"] = {}
|
||||||
|
|
||||||
-- Configure the update check interval:
|
-- Configure the update check interval:
|
||||||
|
|||||||
@ -1,21 +1,42 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
|
using AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
|
using Lua;
|
||||||
|
|
||||||
using Host = AIStudio.Provider.SelfHosted.Host;
|
using Host = AIStudio.Provider.SelfHosted.Host;
|
||||||
|
|
||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
public readonly record struct EmbeddingProvider(
|
public sealed record EmbeddingProvider(
|
||||||
uint Num,
|
uint Num,
|
||||||
string Id,
|
string Id,
|
||||||
string Name,
|
string Name,
|
||||||
LLMProviders UsedLLMProvider,
|
LLMProviders UsedLLMProvider,
|
||||||
Model Model,
|
Model Model,
|
||||||
bool IsSelfHosted = false,
|
bool IsSelfHosted = false,
|
||||||
|
bool IsEnterpriseConfiguration = false,
|
||||||
|
Guid EnterpriseConfigurationPluginId = default,
|
||||||
string Hostname = "http://localhost:1234",
|
string Hostname = "http://localhost:1234",
|
||||||
Host Host = Host.NONE) : ISecretId
|
Host Host = Host.NONE) : ConfigurationBaseObject, ISecretId
|
||||||
{
|
{
|
||||||
|
private static readonly ILogger<EmbeddingProvider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<EmbeddingProvider>();
|
||||||
|
|
||||||
|
public static readonly EmbeddingProvider NONE = new();
|
||||||
|
|
||||||
|
public EmbeddingProvider() : this(
|
||||||
|
0,
|
||||||
|
Guid.Empty.ToString(),
|
||||||
|
string.Empty,
|
||||||
|
LLMProviders.NONE,
|
||||||
|
default,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Guid.Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => this.Name;
|
public override string ToString() => this.Name;
|
||||||
|
|
||||||
#region Implementation of ISecretId
|
#region Implementation of ISecretId
|
||||||
@ -29,4 +50,85 @@ public readonly record struct EmbeddingProvider(
|
|||||||
public string SecretName => this.Name;
|
public string SecretName => this.Name;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public static bool TryParseEmbeddingProviderTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject provider)
|
||||||
|
{
|
||||||
|
provider = NONE;
|
||||||
|
if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead<string>(out var idText) || !Guid.TryParse(idText, out var id))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid ID. The ID must be a valid GUID.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("Name", out var nameValue) || !nameValue.TryRead<string>(out var name))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid name.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("UsedLLMProvider", out var usedLLMProviderValue) || !usedLLMProviderValue.TryRead<string>(out var usedLLMProviderText) || !Enum.TryParse<LLMProviders>(usedLLMProviderText, true, out var usedLLMProvider))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid LLM provider enum value.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("Host", out var hostValue) || !hostValue.TryRead<string>(out var hostText) || !Enum.TryParse<Host>(hostText, true, out var host))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid host enum value.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("Hostname", out var hostnameValue) || !hostnameValue.TryRead<string>(out var hostname))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid hostname.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("Model", out var modelValue) || !modelValue.TryRead<LuaTable>(out var modelTable))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid model table.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryReadModelTable(idx, modelTable, out var model))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid model configuration.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
provider = new EmbeddingProvider
|
||||||
|
{
|
||||||
|
Num = 0,
|
||||||
|
Id = id.ToString(),
|
||||||
|
Name = name,
|
||||||
|
UsedLLMProvider = usedLLMProvider,
|
||||||
|
Model = model,
|
||||||
|
IsSelfHosted = usedLLMProvider is LLMProviders.SELF_HOSTED,
|
||||||
|
IsEnterpriseConfiguration = true,
|
||||||
|
EnterpriseConfigurationPluginId = configPluginId,
|
||||||
|
Hostname = hostname,
|
||||||
|
Host = host,
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReadModelTable(int idx, LuaTable table, out Model model)
|
||||||
|
{
|
||||||
|
model = default;
|
||||||
|
if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead<string>(out var id))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid model ID.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.TryGetValue("DisplayName", out var displayNameValue) || !displayNameValue.TryRead<string>(out var displayName))
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning($"The configured embedding provider {idx} does not contain a valid model display name.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
model = new(id, displayName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -70,6 +70,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
|||||||
// Handle configured LLM providers:
|
// Handle configured LLM providers:
|
||||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||||
|
|
||||||
|
// Handle configured embedding providers:
|
||||||
|
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.EMBEDDING_PROVIDER, x => x.EmbeddingProviders, x => x.NextEmbeddingNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||||
|
|
||||||
// Handle configured chat templates:
|
// Handle configured chat templates:
|
||||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, x => x.NextChatTemplateNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, x => x.NextChatTemplateNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||||
|
|
||||||
|
|||||||
@ -102,6 +102,7 @@ public sealed record PluginConfigurationObject
|
|||||||
PluginConfigurationObjectType.LLM_PROVIDER => (Settings.Provider.TryParseProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Settings.Provider.NONE, configurationObject),
|
PluginConfigurationObjectType.LLM_PROVIDER => (Settings.Provider.TryParseProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Settings.Provider.NONE, configurationObject),
|
||||||
PluginConfigurationObjectType.CHAT_TEMPLATE => (ChatTemplate.TryParseChatTemplateTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != ChatTemplate.NO_CHAT_TEMPLATE, configurationObject),
|
PluginConfigurationObjectType.CHAT_TEMPLATE => (ChatTemplate.TryParseChatTemplateTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != ChatTemplate.NO_CHAT_TEMPLATE, configurationObject),
|
||||||
PluginConfigurationObjectType.PROFILE => (Profile.TryParseProfileTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Profile.NO_PROFILE, configurationObject),
|
PluginConfigurationObjectType.PROFILE => (Profile.TryParseProfileTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Profile.NO_PROFILE, configurationObject),
|
||||||
|
PluginConfigurationObjectType.EMBEDDING_PROVIDER => (EmbeddingProvider.TryParseEmbeddingProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != EmbeddingProvider.NONE, configurationObject),
|
||||||
|
|
||||||
_ => (false, NoConfigurationObject.INSTANCE)
|
_ => (false, NoConfigurationObject.INSTANCE)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -133,6 +133,10 @@ public static partial class PluginFactory
|
|||||||
// Check LLM providers:
|
// Check LLM providers:
|
||||||
var wasConfigurationChanged = PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, AVAILABLE_PLUGINS, configObjectList);
|
var wasConfigurationChanged = PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, AVAILABLE_PLUGINS, configObjectList);
|
||||||
|
|
||||||
|
// Check embedding providers:
|
||||||
|
if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.EMBEDDING_PROVIDER, x => x.EmbeddingProviders, AVAILABLE_PLUGINS, configObjectList))
|
||||||
|
wasConfigurationChanged = true;
|
||||||
|
|
||||||
// Check chat templates:
|
// Check chat templates:
|
||||||
if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, AVAILABLE_PLUGINS, configObjectList))
|
if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, AVAILABLE_PLUGINS, configObjectList))
|
||||||
wasConfigurationChanged = true;
|
wasConfigurationChanged = true;
|
||||||
|
|||||||
@ -3,5 +3,6 @@
|
|||||||
- Added the option to use source code files in chats and document analysis. This supports software development workflows.
|
- Added the option to use source code files in chats and document analysis. This supports software development workflows.
|
||||||
- Added a preview feature that lets you record your own voice in preparation for the transcription feature. The feature remains in development and appears only when the preview feature is enabled.
|
- Added a preview feature that lets you record your own voice in preparation for the transcription feature. The feature remains in development and appears only when the preview feature is enabled.
|
||||||
- Added the option to configure transcription providers (for example, using Whisper models). As usual, there can be local as well as cloud models configured. This option is part of the transcription preview and remains hidden until the preview is activated or the feature gets released.
|
- Added the option to configure transcription providers (for example, using Whisper models). As usual, there can be local as well as cloud models configured. This option is part of the transcription preview and remains hidden until the preview is activated or the feature gets released.
|
||||||
|
- Added the option to configure embedding providers through a config plugin and distribute them within an organization.
|
||||||
- Improved the app versioning. Starting in 2026, each version number includes the year, followed by the month. The last digit shows the release number for that month. For example, version `26.1.1` is the first release in January 2026.
|
- Improved the app versioning. Starting in 2026, each version number includes the year, followed by the month. The last digit shows the release number for that month. For example, version `26.1.1` is the first release in January 2026.
|
||||||
- Fixed a bug in the profile selection where the "Use no profile" entry could not be localized, causing English text to appear in languages such as German. This behavior has now been fixed.
|
- Fixed a bug in the profile selection where the "Use no profile" entry could not be localized, causing English text to appear in languages such as German. This behavior has now been fixed.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user