mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-19 02:18:00 +00:00
Improved adding local data sources without an embedding provider (#1084)
This commit is contained in:
1 parent
bca9e7ea89
commit
92fa0d08ef
20 files changed
+590
-154
No files matched your search
@@ -4081,6 +4081,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1208397349"] = "Au
|
||||
-- Edit Local Directory Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1215599168"] = "Edit Local Directory Data Source"
|
||||
|
||||
-- Local File, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1317002733"] = "Local File, requires an embedding provider"
|
||||
|
||||
-- Refresh
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T135637716"] = "Refresh"
|
||||
|
||||
@@ -4117,6 +4120,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2146756020"] = "Lo
|
||||
-- Edit ERI v1 Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T221059217"] = "Edit ERI v1 Data Source"
|
||||
|
||||
-- Mailbox (IMAP), requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2363290424"] = "Mailbox (IMAP), requires an embedding provider"
|
||||
|
||||
-- Edit Local File Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2453292893"] = "Edit Local File Data Source"
|
||||
|
||||
@@ -4195,6 +4201,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3595669127"] = "Ex
|
||||
-- Local data sources refresh when files change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3687976654"] = "Local data sources refresh when files change."
|
||||
|
||||
-- Local Directory, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3698039736"] = "Local Directory, requires an embedding provider"
|
||||
|
||||
-- Not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3706935413"] = "Not available"
|
||||
|
||||
@@ -4243,6 +4252,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T87980240"] = "The
|
||||
-- Local Directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T926703547"] = "Local Directory"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1681763001"] = "Import Embedding"
|
||||
|
||||
-- Add Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1738753945"] = "Add Embedding"
|
||||
|
||||
-- No embedding provider is configured yet, but this data source needs one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1792425555"] = "No embedding provider is configured yet, but this data source needs one."
|
||||
|
||||
-- You can add one right here; everything you entered in this dialog stays as it is.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T2076959501"] = "You can add one right here; everything you entered in this dialog stays as it is."
|
||||
|
||||
-- Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T215225643"] = "Your organization manages the embedding providers and has not provided one yet. Please ask your IT department."
|
||||
|
||||
-- No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T863764937"] = "No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it."
|
||||
|
||||
-- Yes, let the AI decide which data sources are needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1031370894"] = "Yes, let the AI decide which data sources are needed."
|
||||
|
||||
@@ -5269,9 +5296,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T17607
|
||||
-- Are you sure you want to delete the embedding provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1825371968"] = "Are you sure you want to delete the embedding provider '{0}'?"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T190634634"] = "Add Embedding Provider"
|
||||
|
||||
-- This embedding provider is managed by your organization. You can set your own API key.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1931890418"] = "This embedding provider is managed by your organization. You can set your own API key."
|
||||
|
||||
@@ -12187,6 +12211,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T4175865785"] = "Repair Data
|
||||
-- The index of the data source '{0}' cannot be read anymore. Repairing it means building the index from scratch: everything indexed so far is thrown away, and every document of this data source is sent to your embedding provider once more. With a cloud provider, this costs money, and with a large data source it takes a while. Do you want to repair this data source now?
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T857336889"] = "The index of the data source '{0}' cannot be read anymore. Repairing it means building the index from scratch: everything indexed so far is thrown away, and every document of this data source is sent to your embedding provider once more. With a cloud provider, this costs money, and with a large data source it takes a while. Do you want to repair this data source now?"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T1681763001"] = "Import Embedding"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T190634634"] = "Add Embedding Provider"
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment."
|
||||
|
||||
@@ -14539,6 +14569,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4001510395"
|
||||
-- The name must not contain control characters.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4234589878"] = "The name must not contain control characters."
|
||||
|
||||
-- The embedding provider of this data source no longer exists. Please select another one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4288009003"] = "The embedding provider of this data source no longer exists. Please select another one."
|
||||
|
||||
-- Please enter the host of the IMAP server, e.g., imap.example.org.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T471173229"] = "Please enter the host of the IMAP server, e.g., imap.example.org."
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
}
|
||||
</MudJustifiedText>
|
||||
|
||||
<DataSourceMissingEmbeddingWarning/>
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="mb-3" Wrap="Wrap.Wrap">
|
||||
<MudTextSwitch Label="@T("Automatic local data source refresh")" Value="@this.SettingsManager.ConfigurationData.App.DataSourceIndexing.AutomaticRefresh" LabelOn="@(this.AreMailboxesEnabled ? T("Local data sources refresh when files change, mailboxes every 16 minutes.") : T("Local data sources refresh when files change."))" LabelOff="@T("Local data sources refresh only when triggered manually.")" ValueChanged="@this.AutomaticRefreshChanged"/>
|
||||
<MudTooltip Text="@T("Refresh all")">
|
||||
@@ -130,17 +132,21 @@
|
||||
<MudMenuItem OnClick="@(() => this.AddDataSource(DataSourceType.ERI_V1))">
|
||||
@T("External Data (ERI-Server v1)")
|
||||
</MudMenuItem>
|
||||
<MudMenuItem OnClick="@(() => this.AddDataSource(DataSourceType.LOCAL_DIRECTORY))">
|
||||
@T("Local Directory")
|
||||
@*
|
||||
Without an embedding provider, the dialogs of the local data sources could never be saved.
|
||||
They stay listed with the reason, so nobody concludes that AI Studio cannot read local files:
|
||||
*@
|
||||
<MudMenuItem OnClick="@(() => this.AddDataSource(DataSourceType.LOCAL_DIRECTORY))" Disabled="@(!this.HasEmbeddingProvider)">
|
||||
@(this.HasEmbeddingProvider ? T("Local Directory") : T("Local Directory, requires an embedding provider"))
|
||||
</MudMenuItem>
|
||||
<MudMenuItem OnClick="@(() => this.AddDataSource(DataSourceType.LOCAL_FILE))">
|
||||
@T("Local File")
|
||||
<MudMenuItem OnClick="@(() => this.AddDataSource(DataSourceType.LOCAL_FILE))" Disabled="@(!this.HasEmbeddingProvider)">
|
||||
@(this.HasEmbeddingProvider ? T("Local File") : T("Local File, requires an embedding provider"))
|
||||
</MudMenuItem>
|
||||
@if (PreviewFeatures.PRE_MAILBOXES_2026.IsEnabled(this.SettingsManager))
|
||||
{
|
||||
@* Shown with a lock rather than left out, like the locked buttons for adding providers: *@
|
||||
<MudMenuItem OnClick="@this.AddMailbox" Disabled="@(!this.MayAddMailbox)" Icon="@(this.MayAddMailbox ? null : Icons.Material.Filled.Lock)">
|
||||
@(this.MayAddMailbox ? T("Mailbox (IMAP)") : T("Mailbox (IMAP), not allowed by your organization"))
|
||||
<MudMenuItem OnClick="@this.AddMailbox" Disabled="@(!this.MayAddMailbox || !this.HasEmbeddingProvider)" Icon="@(this.MayAddMailbox ? null : Icons.Material.Filled.Lock)">
|
||||
@this.MailboxMenuText
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
|
||||
@@ -30,8 +30,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
[Inject]
|
||||
private DatabaseClientProvider DatabaseClientProvider { get; init; } = null!;
|
||||
|
||||
private readonly List<ConfigurationSelectData<string>> availableEmbeddingProviders = new();
|
||||
|
||||
/// <summary>
|
||||
/// The data sources and then the mailboxes, which the table shows together.
|
||||
/// </summary>
|
||||
@@ -42,13 +40,26 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
|
||||
private bool MayAddMailbox => this.SettingsManager.ConfigurationData.App.AllowUserToAddMailbox;
|
||||
|
||||
/// <summary>
|
||||
/// Whether an embedding provider exists, which every local data source needs.
|
||||
/// </summary>
|
||||
private bool HasEmbeddingProvider => !EmbeddingProviderSetup.IsMissing(this.SettingsManager);
|
||||
|
||||
/// <remarks>
|
||||
/// The rule of the organization comes first: an embedding provider would not make the mailbox possible.
|
||||
/// </remarks>
|
||||
private string MailboxMenuText => !this.MayAddMailbox
|
||||
? T("Mailbox (IMAP), not allowed by your organization")
|
||||
: this.HasEmbeddingProvider
|
||||
? T("Mailbox (IMAP)")
|
||||
: T("Mailbox (IMAP), requires an embedding provider");
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED, Event.RAG_EMBEDDING_STATUS_CHANGED ]);
|
||||
this.UpdateEmbeddingProviders();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -61,10 +72,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
case Event.PLUGINS_RELOADED:
|
||||
this.UpdateEmbeddingProviders();
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
case Event.RAG_EMBEDDING_STATUS_CHANGED:
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
@@ -75,13 +82,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private void UpdateEmbeddingProviders()
|
||||
{
|
||||
this.availableEmbeddingProviders.Clear();
|
||||
foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders())
|
||||
this.availableEmbeddingProviders.Add(new (provider.Name, provider.Id));
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Files which were skipped for good are none of the failed ones, so an otherwise usable data
|
||||
/// source stays green. The shared health policy warns when none of the selected documents could
|
||||
@@ -222,6 +222,10 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
|
||||
private async Task AddDataSource(DataSourceType type)
|
||||
{
|
||||
// The menu offers no local data source without an embedding provider, but the last one may have gone since it was drawn:
|
||||
if (type is DataSourceType.LOCAL_FILE or DataSourceType.LOCAL_DIRECTORY && !this.HasEmbeddingProvider)
|
||||
return;
|
||||
|
||||
IDataSource? addedDataSource = null;
|
||||
switch (type)
|
||||
{
|
||||
@@ -229,7 +233,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
var localFileDialogParameters = new DialogParameters<DataSourceLocalFileDialog>
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
{ x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
|
||||
};
|
||||
|
||||
var localFileDialogReference = await this.DialogService.ShowAsync<DataSourceLocalFileDialog>(T("Add Local File as Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -246,7 +249,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
var localDirectoryDialogParameters = new DialogParameters<DataSourceLocalDirectoryDialog>
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
{ x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
|
||||
};
|
||||
|
||||
var localDirectoryDialogReference = await this.DialogService.ShowAsync<DataSourceLocalDirectoryDialog>(T("Add Local Directory as Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -400,7 +402,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.DataSource, localFile },
|
||||
{ x => x.LockSource, lockDataSourceOrigin },
|
||||
{ x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
|
||||
};
|
||||
|
||||
var localFileDialogReference = await this.DialogService.ShowAsync<DataSourceLocalFileDialog>(T("Edit Local File Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -417,7 +418,6 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.DataSource, localDirectory },
|
||||
{ x => x.LockSource, lockDataSourceOrigin },
|
||||
{ x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
|
||||
};
|
||||
|
||||
var localDirectoryDialogReference = await this.DialogService.ShowAsync<DataSourceLocalDirectoryDialog>(T("Edit Local Directory Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -539,13 +539,12 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
|
||||
private async Task AddMailbox()
|
||||
{
|
||||
if (!this.MayAddMailbox)
|
||||
if (!this.MayAddMailbox || !this.HasEmbeddingProvider)
|
||||
return;
|
||||
|
||||
var dialogParameters = new DialogParameters<DataSourceMailboxDialog>
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
{ x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<DataSourceMailboxDialog>(T("Add Mailbox"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
@inherits MSGComponentBase
|
||||
|
||||
@*
|
||||
The condition lives here rather than with the parents: the component stays in place while the
|
||||
alert comes and goes, so it can still report the provider it just added.
|
||||
*@
|
||||
@if (this.IsMissing)
|
||||
{
|
||||
<MudAlert Severity="@(this.MayAdd ? Severity.Warning : Severity.Info)" Variant="Variant.Outlined" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body1">
|
||||
@this.Text
|
||||
</MudJustifiedText>
|
||||
@if (this.MayAdd)
|
||||
{
|
||||
<MudStack Row="true" Wrap="Wrap.Wrap" Class="mt-3">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Warning" StartIcon="@Icons.Material.Filled.AddRoad" Disabled="@this.isAdding" OnClick="@this.AddEmbeddingProvider">
|
||||
@T("Add Embedding")
|
||||
</MudButton>
|
||||
@if (this.MayImport)
|
||||
{
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Warning" StartIcon="@Icons.Material.Filled.FileDownload" Disabled="@this.isAdding" OnClick="@this.ImportEmbeddingProvider">
|
||||
@T("Import Embedding")
|
||||
</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</MudAlert>
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Tells that no embedding provider exists, which every local data source needs, and offers to add
|
||||
/// one right there.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Shown where a local data source is set up: above the data source table, and in the dialogs for
|
||||
/// adding or editing one. Without it, the missing provider only came up when the user saved the
|
||||
/// dialog, after filling in everything else, and leaving the dialog to add one lost all of it.
|
||||
/// </remarks>
|
||||
public partial class DataSourceMissingEmbeddingWarning : MSGComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the warning sits in the dialog of a data source rather than above the data source table.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsInDataSourceDialog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Receives the embedding provider the user just added, so that a dialog can select it.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<EmbeddingProvider> EmbeddingProviderAdded { get; set; }
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private DataSourceEmbeddingService DataSourceEmbeddingService { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the dialog for adding a provider is open, so that a second click does not open another one.
|
||||
/// </summary>
|
||||
private bool isAdding;
|
||||
|
||||
private bool IsMissing => EmbeddingProviderSetup.IsMissing(this.SettingsManager);
|
||||
|
||||
private bool MayAdd => EmbeddingProviderSetup.MayAdd(this.SettingsManager);
|
||||
|
||||
private bool MayImport => EmbeddingProviderSetup.MayImport(this.SettingsManager);
|
||||
|
||||
private string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
var problem = this.IsInDataSourceDialog
|
||||
? T("No embedding provider is configured yet, but this data source needs one.")
|
||||
: T("No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.");
|
||||
|
||||
if (!this.MayAdd)
|
||||
return $"{problem} {T("Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.")}";
|
||||
|
||||
// Above the table, the buttons speak for themselves. In a dialog, the worry is about what was entered so far:
|
||||
return this.IsInDataSourceDialog
|
||||
? $"{problem} {T("You can add one right here; everything you entered in this dialog stays as it is.")}"
|
||||
: problem;
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
// The warning goes away as soon as a provider exists, also one which a configuration plugin brings along:
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED)
|
||||
this.StateHasChanged();
|
||||
|
||||
return base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Task AddEmbeddingProvider() => this.AddOnceAsync(() => EmbeddingProviderSetup.AddAsync(this.DialogService, this.SettingsManager, this.DataSourceEmbeddingService));
|
||||
|
||||
private Task ImportEmbeddingProvider() => this.AddOnceAsync(() => EmbeddingProviderSetup.ImportAsync(this.DialogService, this.SettingsManager, this.DataSourceEmbeddingService));
|
||||
|
||||
private async Task AddOnceAsync(Func<Task<EmbeddingProvider?>> addProvider)
|
||||
{
|
||||
if (this.isAdding)
|
||||
return;
|
||||
|
||||
this.isAdding = true;
|
||||
try
|
||||
{
|
||||
var addedProvider = await addProvider();
|
||||
if (addedProvider is null)
|
||||
return;
|
||||
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
await this.EmbeddingProviderAdded.InvokeAsync(addedProvider);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isAdding = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
@using AIStudio.Provider
|
||||
@using AIStudio.Settings
|
||||
@using AIStudio.Settings.DataModel
|
||||
@using AIStudio.Tools.PluginSystem
|
||||
@inherits SettingsPanelProviderBase
|
||||
|
||||
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
|
||||
@@ -95,8 +94,8 @@
|
||||
}
|
||||
|
||||
<MudStack Row="true" Wrap="Wrap.Wrap" Class="mt-3 mb-6">
|
||||
<LockableButton Text="@T("Add Embedding")" IsLocked="@(() => !this.SettingsManager.ConfigurationData.App.AllowUserToAddProvider || !this.SettingsManager.ConfigurationData.App.AllowUserToAddEmbeddingProvider)" Icon="@Icons.Material.Filled.AddRoad" OnClickAsync="@this.AddEmbeddingProvider" Class="flex-grow-0" NoMargin="true" />
|
||||
<LockableButton Text="@T("Import Embedding")" IsLocked="@(() => !this.SettingsManager.ConfigurationData.App.CanImportConfigurationSnippet(PluginConfigurationObjectType.EMBEDDING_PROVIDER))" Icon="@Icons.Material.Filled.FileDownload" OnClickAsync="@this.ImportEmbeddingProvider" ButtonVariant="Variant.Outlined" Class="flex-grow-0" NoMargin="true" />
|
||||
<LockableButton Text="@T("Add Embedding")" IsLocked="@(() => !EmbeddingProviderSetup.MayAdd(this.SettingsManager))" Icon="@Icons.Material.Filled.AddRoad" OnClickAsync="@this.AddEmbeddingProvider" Class="flex-grow-0" NoMargin="true" />
|
||||
<LockableButton Text="@T("Import Embedding")" IsLocked="@(() => !EmbeddingProviderSetup.MayImport(this.SettingsManager))" Icon="@Icons.Material.Filled.FileDownload" OnClickAsync="@this.ImportEmbeddingProvider" ButtonVariant="Variant.Outlined" Class="flex-grow-0" NoMargin="true" />
|
||||
</MudStack>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System.Globalization;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -56,57 +55,28 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
|
||||
|
||||
private async Task AddEmbeddingProvider()
|
||||
{
|
||||
var dialogParameters = new DialogParameters<EmbeddingProviderDialog>
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
};
|
||||
if (await EmbeddingProviderSetup.AddAsync(this.DialogService, this.SettingsManager, this.DataSourceEmbeddingService) is null)
|
||||
return;
|
||||
|
||||
await this.AddEmbeddingProvider(dialogParameters, isImport: false);
|
||||
await this.UpdateEmbeddingProviders();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
private async Task ImportEmbeddingProvider()
|
||||
{
|
||||
var import = await ConfigurationSnippetImportDialog.ShowAsync(this.DialogService, PluginConfigurationObjectType.EMBEDDING_PROVIDER, T("Import Embedding"));
|
||||
if (import?.ConfigurationObject is not EmbeddingProvider embeddingProvider)
|
||||
if (await EmbeddingProviderSetup.ImportAsync(this.DialogService, this.SettingsManager, this.DataSourceEmbeddingService) is null)
|
||||
return;
|
||||
|
||||
var dialogParameters = CreateDialogParameters(embeddingProvider, isEditing: false);
|
||||
dialogParameters.Add(x => x.ImportedAPIKey, import.Secret);
|
||||
await this.AddEmbeddingProvider(dialogParameters, isImport: true);
|
||||
}
|
||||
|
||||
private async Task AddEmbeddingProvider(DialogParameters<EmbeddingProviderDialog> dialogParameters, bool isImport)
|
||||
{
|
||||
var dialogReference = await this.DialogService.ShowAsync<EmbeddingProviderDialog>(T("Add Embedding Provider"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
//
|
||||
// An organization can lock the import while the user is still filling in the form, e.g.,
|
||||
// with a new version of its configuration plugin. Hence, the permission is checked once
|
||||
// more before the imported embedding provider is stored:
|
||||
//
|
||||
if (isImport && !this.SettingsManager.ConfigurationData.App.CanImportConfigurationSnippet(PluginConfigurationObjectType.EMBEDDING_PROVIDER))
|
||||
return;
|
||||
|
||||
var addedEmbedding = (EmbeddingProvider)dialogResult.Data!;
|
||||
addedEmbedding = addedEmbedding with { Num = this.SettingsManager.ConfigurationData.NextEmbeddingNum++ };
|
||||
|
||||
this.SettingsManager.ConfigurationData.EmbeddingProviders.Add(addedEmbedding);
|
||||
await this.UpdateEmbeddingProviders();
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.DataSourceEmbeddingService.QueueAllInternalDataSourcesAsync();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
private async Task EditEmbeddingProvider(EmbeddingProvider embeddingProvider)
|
||||
{
|
||||
if (embeddingProvider.IsEnterpriseConfiguration && !embeddingProvider.AllowUserProvidedAPIKey)
|
||||
return;
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<EmbeddingProviderDialog>(T("Edit Embedding Provider"), CreateDialogParameters(embeddingProvider, isEditing: true), DialogOptions.FULLSCREEN);
|
||||
var dialogReference = await this.DialogService.ShowAsync<EmbeddingProviderDialog>(T("Edit Embedding Provider"), EmbeddingProviderSetup.CreateDialogParameters(embeddingProvider, isEditing: true), DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
@@ -136,26 +106,6 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
private static DialogParameters<EmbeddingProviderDialog> CreateDialogParameters(EmbeddingProvider embeddingProvider, bool isEditing) => new()
|
||||
{
|
||||
{ x => x.DataNum, embeddingProvider.Num },
|
||||
{ x => x.DataId, embeddingProvider.Id },
|
||||
{ x => x.DataName, embeddingProvider.Name },
|
||||
{ x => x.DataLLMProvider, embeddingProvider.UsedLLMProvider },
|
||||
{ x => x.DataCustomIconDataUrl, embeddingProvider.CustomIconDataUrl },
|
||||
{ x => x.DataModel, embeddingProvider.Model },
|
||||
{ x => x.DataHostname, embeddingProvider.Hostname },
|
||||
{ x => x.IsSelfHosted, embeddingProvider.IsSelfHosted },
|
||||
{ x => x.IsEditing, isEditing },
|
||||
{ x => x.DataHost, embeddingProvider.Host },
|
||||
{ x => x.DataTokenizerPath, embeddingProvider.TokenizerPath },
|
||||
{ x => x.DataTokenizerFingerprint, embeddingProvider.TokenizerFingerprint },
|
||||
{ x => x.DataTokenLimit, embeddingProvider.EffectiveTokenLimit },
|
||||
{ x => x.DataEmbeddingBatchSize, embeddingProvider.EffectiveEmbeddingBatchSize },
|
||||
{ x => x.HFInferenceProviderId, embeddingProvider.HFInferenceProvider },
|
||||
{ x => x.IsEnterpriseConfiguration, embeddingProvider.IsEnterpriseConfiguration },
|
||||
};
|
||||
|
||||
private async Task DeleteEmbeddingProvider(EmbeddingProvider provider)
|
||||
{
|
||||
var question = string.Format(T("Are you sure you want to delete the embedding provider '{0}'?"), provider.Name);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
@* A drop anywhere in this dialog belongs to the dialog, not to the page behind it: *@
|
||||
<PathDropZone IsArea="@true">
|
||||
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues" FieldChanged="@this.RevalidateAfterFieldChange">
|
||||
<DataSourceMissingEmbeddingWarning IsInDataSourceDialog="@true" EmbeddingProviderAdded="@this.SelectAddedEmbeddingProvider"/>
|
||||
|
||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||
<MudTextField
|
||||
T="string"
|
||||
@@ -102,17 +104,10 @@
|
||||
@T("In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.")
|
||||
</MudJustifiedText>
|
||||
<MudSelect @ref="@this.embeddingSelect" @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingProviderAccess">
|
||||
@foreach (var embedding in this.AvailableEmbeddings)
|
||||
@foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders())
|
||||
{
|
||||
<MudSelectItem Value="@embedding.Value">
|
||||
@if (this.GetEmbeddingProvider(embedding.Value) is { } provider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@embedding.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@embedding.Name
|
||||
}
|
||||
<MudSelectItem Value="@provider.Id">
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@provider.Name" />
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
@@ -33,9 +33,6 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public bool LockSource { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public IReadOnlyList<ConfigurationSelectData<string>> AvailableEmbeddings { get; set; } = [];
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
@@ -134,6 +131,9 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
}
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
// The embedding providers may change while the dialog is open, e.g., through a configuration plugin:
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
@@ -155,12 +155,25 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private EmbeddingProvider? GetEmbeddingProvider(string providerId)
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
var provider = this.SettingsManager.GetEmbeddingProviderById(providerId);
|
||||
return provider == EmbeddingProvider.NONE ? null : provider;
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
case Event.PLUGINS_RELOADED:
|
||||
// The embedding providers are listed anew, and the fields checked so far get a fresh verdict once they hold the new values:
|
||||
this.revalidateAfterRender = true;
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
return base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private EmbeddingProvider? SelectedEmbedding => this.SettingsManager.ConfigurationData.EmbeddingProviders
|
||||
.FirstOrDefault(x => x.Id == this.dataEmbeddingId);
|
||||
|
||||
@@ -328,5 +341,22 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the embedding provider the user just added from within this dialog, so that what they
|
||||
/// entered so far can be saved right away.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only when no existing provider is selected, which includes the provider of a data source that
|
||||
/// was deleted since. Like the token limit in ToggleExpertSettings, the field learns its new value
|
||||
/// only with the next render, so it is checked after that.
|
||||
/// </remarks>
|
||||
private void SelectAddedEmbeddingProvider(EmbeddingProvider provider)
|
||||
{
|
||||
if (this.SelectedEmbedding is null)
|
||||
this.dataEmbeddingId = provider.Id;
|
||||
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
@* A drop anywhere in this dialog belongs to the dialog, not to the page behind it: *@
|
||||
<PathDropZone IsArea="@true">
|
||||
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues" FieldChanged="@this.RevalidateAfterFieldChange">
|
||||
<DataSourceMissingEmbeddingWarning IsInDataSourceDialog="@true" EmbeddingProviderAdded="@this.SelectAddedEmbeddingProvider"/>
|
||||
|
||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||
<MudTextField
|
||||
T="string"
|
||||
@@ -75,17 +77,10 @@
|
||||
@T("In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.")
|
||||
</MudJustifiedText>
|
||||
<MudSelect @ref="@this.embeddingSelect" @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingProviderAccess">
|
||||
@foreach (var embedding in this.AvailableEmbeddings)
|
||||
@foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders())
|
||||
{
|
||||
<MudSelectItem Value="@embedding.Value">
|
||||
@if (this.GetEmbeddingProvider(embedding.Value) is { } provider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@embedding.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@embedding.Name
|
||||
}
|
||||
<MudSelectItem Value="@provider.Id">
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@provider.Name" />
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
@@ -33,9 +33,6 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
/// </remarks>
|
||||
[Parameter]
|
||||
public bool LockSource { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public IReadOnlyList<ConfigurationSelectData<string>> AvailableEmbeddings { get; set; } = [];
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
@@ -125,6 +122,9 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
}
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
// The embedding providers may change while the dialog is open, e.g., through a configuration plugin:
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
@@ -146,12 +146,25 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private EmbeddingProvider? GetEmbeddingProvider(string providerId)
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
var provider = this.SettingsManager.GetEmbeddingProviderById(providerId);
|
||||
return provider == EmbeddingProvider.NONE ? null : provider;
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
case Event.PLUGINS_RELOADED:
|
||||
// The embedding providers are listed anew, and the fields checked so far get a fresh verdict once they hold the new values:
|
||||
this.revalidateAfterRender = true;
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
return base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private EmbeddingProvider? SelectedEmbedding => this.SettingsManager.ConfigurationData.EmbeddingProviders
|
||||
.FirstOrDefault(x => x.Id == this.dataEmbeddingId);
|
||||
|
||||
@@ -308,5 +321,22 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the embedding provider the user just added from within this dialog, so that what they
|
||||
/// entered so far can be saved right away.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only when no existing provider is selected, which includes the provider of a data source that
|
||||
/// was deleted since. Like the token limit in ToggleExpertSettings, the field learns its new value
|
||||
/// only with the next render, so it is checked after that.
|
||||
/// </remarks>
|
||||
private void SelectAddedEmbeddingProvider(EmbeddingProvider provider)
|
||||
{
|
||||
if (this.SelectedEmbedding is null)
|
||||
this.dataEmbeddingId = provider.Id;
|
||||
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
||||
}
|
||||
@@ -41,6 +41,12 @@
|
||||
</MudAlert>
|
||||
}
|
||||
|
||||
@* A way out which leads nowhere is worse than none: the mailbox could not be added anyway. *@
|
||||
@if (!this.IsAddingNotAllowed)
|
||||
{
|
||||
<DataSourceMissingEmbeddingWarning IsInDataSourceDialog="@true" EmbeddingProviderAdded="@this.SelectAddedEmbeddingProvider"/>
|
||||
}
|
||||
|
||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||
<MudTextField
|
||||
T="string"
|
||||
@@ -325,17 +331,10 @@
|
||||
@T("In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.")
|
||||
</MudJustifiedText>
|
||||
<MudSelect @ref="@this.embeddingSelect" @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingProviderAccess">
|
||||
@foreach (var embedding in this.AvailableEmbeddings)
|
||||
@foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders())
|
||||
{
|
||||
<MudSelectItem Value="@embedding.Value">
|
||||
@if (this.GetEmbeddingProvider(embedding.Value) is { } provider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@embedding.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@embedding.Name
|
||||
}
|
||||
<MudSelectItem Value="@provider.Id">
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@provider.Name" />
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
@@ -46,9 +46,6 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public bool LockSource { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public IReadOnlyList<ConfigurationSelectData<string>> AvailableEmbeddings { get; set; } = [];
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
@@ -370,12 +367,6 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
|
||||
? Icons.Material.Outlined.HourglassEmpty
|
||||
: this.testFailure is null ? Icons.Material.Outlined.CheckCircle : Icons.Material.Outlined.Error;
|
||||
|
||||
private EmbeddingProvider? GetEmbeddingProvider(string providerId)
|
||||
{
|
||||
var provider = this.SettingsManager.GetEmbeddingProviderById(providerId);
|
||||
return provider == EmbeddingProvider.NONE ? null : provider;
|
||||
}
|
||||
|
||||
private EmbeddingProvider? SelectedEmbedding => this.SettingsManager.ConfigurationData.EmbeddingProviders
|
||||
.FirstOrDefault(x => x.Id == this.dataEmbeddingId);
|
||||
|
||||
@@ -745,5 +736,22 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the embedding provider the user just added from within this dialog, so that what they
|
||||
/// entered so far, the password and the tested connection included, can be saved right away.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only when no existing provider is selected, which includes the provider of a mailbox that was
|
||||
/// deleted since. Like the token limit in ToggleExpertSettings, the field learns its new value only
|
||||
/// with the next render, so it is checked after that.
|
||||
/// </remarks>
|
||||
private void SelectAddedEmbeddingProvider(EmbeddingProvider provider)
|
||||
{
|
||||
if (this.SelectedEmbedding is null)
|
||||
this.dataEmbeddingId = provider.Id;
|
||||
|
||||
this.revalidateAfterRender = true;
|
||||
}
|
||||
|
||||
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
||||
}
|
||||
+36
-3
@@ -4083,6 +4083,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1208397349"] = "Au
|
||||
-- Edit Local Directory Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1215599168"] = "Datenquelle bearbeiten: Lokaler Ordner"
|
||||
|
||||
-- Local File, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1317002733"] = "Lokale Datei, erfordert einen Einbettungsanbieter"
|
||||
|
||||
-- Refresh
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T135637716"] = "Aktualisieren"
|
||||
|
||||
@@ -4119,6 +4122,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2146756020"] = "In
|
||||
-- Edit ERI v1 Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T221059217"] = "ERI v1 Datenquelle bearbeiten"
|
||||
|
||||
-- Mailbox (IMAP), requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2363290424"] = "Postfach (IMAP), erfordert einen Einbettungsanbieter"
|
||||
|
||||
-- Edit Local File Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2453292893"] = "Datenquelle bearbeiten: Lokale Datei"
|
||||
|
||||
@@ -4197,6 +4203,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3595669127"] = "Zu
|
||||
-- Local data sources refresh when files change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3687976654"] = "Lokale Datenquellen werden aktualisiert, wenn sich Dateien ändern."
|
||||
|
||||
-- Local Directory, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3698039736"] = "Lokaler Ordner, erfordert einen Einbettungsanbieter"
|
||||
|
||||
-- Not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3706935413"] = "Nicht verfügbar"
|
||||
|
||||
@@ -4245,6 +4254,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T87980240"] = "Das
|
||||
-- Local Directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T926703547"] = "Lokaler Ordner"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1681763001"] = "Einbettung importieren"
|
||||
|
||||
-- Add Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1738753945"] = "Einbettung hinzufügen"
|
||||
|
||||
-- No embedding provider is configured yet, but this data source needs one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1792425555"] = "Es ist noch kein Einbettungsanbieter konfiguriert, doch diese Datenquelle benötigt einen."
|
||||
|
||||
-- You can add one right here; everything you entered in this dialog stays as it is.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T2076959501"] = "Sie können hier direkt einen hinzufügen. Ihre Eingaben in diesem Dialog bleiben erhalten."
|
||||
|
||||
-- Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T215225643"] = "Ihre Organisation verwaltet die Einbettungsanbieter und hat noch keinen bereitgestellt. Bitte wenden Sie sich an Ihre IT-Abteilung."
|
||||
|
||||
-- No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T863764937"] = "Es ist noch kein Einbettungsanbieter konfiguriert. Lokale Datenquellen wie Ihre Dateien und Ordner benötigen einen: Er bereitet Ihre Daten so auf, dass die KI sie durchsuchen kann."
|
||||
|
||||
-- Yes, let the AI decide which data sources are needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1031370894"] = "Ja, die KI soll entscheiden, welche Datenquellen benötigt werden."
|
||||
|
||||
@@ -5271,9 +5298,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T17607
|
||||
-- Are you sure you want to delete the embedding provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1825371968"] = "Sind Sie sicher, dass Sie den Einbettungsanbieter '{0}' löschen möchten?"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T190634634"] = "Einbettungsanbieter hinzufügen"
|
||||
|
||||
-- This embedding provider is managed by your organization. You can set your own API key.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1931890418"] = "Dieser Anbieter für Einbettungen wird von Ihrer Organisation verwaltet. Sie können Ihren eigenen API-Schlüssel festlegen."
|
||||
|
||||
@@ -12189,6 +12213,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T4175865785"] = "Datenquelle
|
||||
-- The index of the data source '{0}' cannot be read anymore. Repairing it means building the index from scratch: everything indexed so far is thrown away, and every document of this data source is sent to your embedding provider once more. With a cloud provider, this costs money, and with a large data source it takes a while. Do you want to repair this data source now?
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T857336889"] = "Der Index der Datenquelle „{0}“ kann nicht mehr gelesen werden. Bei einer Reparatur wird der Index vollständig neu erstellt: Alle bisher indexierten Daten werden verworfen und jedes Dokument dieser Datenquelle erneut an Ihren Einbettungsanbieter gesendet. Bei einem Cloud-Anbieter entstehen dadurch Kosten, und bei einer großen Datenquelle kann dies einige Zeit dauern. Möchten Sie diese Datenquelle jetzt reparieren?"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T1681763001"] = "Einbettung importieren"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T190634634"] = "Einbettungsanbieter hinzufügen"
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "Die zugehörigen Daten dürfen an keinen LLM-Anbieter gesendet werden. Das bedeutet, dass diese Datenquelle momentan nicht verwendet werden kann."
|
||||
|
||||
@@ -14541,6 +14571,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4001510395"
|
||||
-- The name must not contain control characters.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4234589878"] = "Der Name darf keine Steuerzeichen enthalten."
|
||||
|
||||
-- The embedding provider of this data source no longer exists. Please select another one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4288009003"] = "Der Einbettungsanbieter dieser Datenquelle existiert nicht mehr. Bitte wählen Sie einen anderen aus."
|
||||
|
||||
-- Please enter the host of the IMAP server, e.g., imap.example.org.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T471173229"] = "Bitte geben Sie den Hostnamen des IMAP-Servers ein, z. B. imap.example.org."
|
||||
|
||||
|
||||
+36
-3
@@ -4083,6 +4083,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1208397349"] = "Au
|
||||
-- Edit Local Directory Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1215599168"] = "Edit Local Directory Data Source"
|
||||
|
||||
-- Local File, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1317002733"] = "Local File, requires an embedding provider"
|
||||
|
||||
-- Refresh
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T135637716"] = "Refresh"
|
||||
|
||||
@@ -4119,6 +4122,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2146756020"] = "Lo
|
||||
-- Edit ERI v1 Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T221059217"] = "Edit ERI v1 Data Source"
|
||||
|
||||
-- Mailbox (IMAP), requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2363290424"] = "Mailbox (IMAP), requires an embedding provider"
|
||||
|
||||
-- Edit Local File Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2453292893"] = "Edit Local File Data Source"
|
||||
|
||||
@@ -4197,6 +4203,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3595669127"] = "Ex
|
||||
-- Local data sources refresh when files change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3687976654"] = "Local data sources refresh when files change."
|
||||
|
||||
-- Local Directory, requires an embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3698039736"] = "Local Directory, requires an embedding provider"
|
||||
|
||||
-- Not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3706935413"] = "Not available"
|
||||
|
||||
@@ -4245,6 +4254,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T87980240"] = "The
|
||||
-- Local Directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T926703547"] = "Local Directory"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1681763001"] = "Import Embedding"
|
||||
|
||||
-- Add Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1738753945"] = "Add Embedding"
|
||||
|
||||
-- No embedding provider is configured yet, but this data source needs one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T1792425555"] = "No embedding provider is configured yet, but this data source needs one."
|
||||
|
||||
-- You can add one right here; everything you entered in this dialog stays as it is.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T2076959501"] = "You can add one right here; everything you entered in this dialog stays as it is."
|
||||
|
||||
-- Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T215225643"] = "Your organization manages the embedding providers and has not provided one yet. Please ask your IT department."
|
||||
|
||||
-- No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMISSINGEMBEDDINGWARNING::T863764937"] = "No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it."
|
||||
|
||||
-- Yes, let the AI decide which data sources are needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1031370894"] = "Yes, let the AI decide which data sources are needed."
|
||||
|
||||
@@ -5271,9 +5298,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T17607
|
||||
-- Are you sure you want to delete the embedding provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1825371968"] = "Are you sure you want to delete the embedding provider '{0}'?"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T190634634"] = "Add Embedding Provider"
|
||||
|
||||
-- This embedding provider is managed by your organization. You can set your own API key.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1931890418"] = "This embedding provider is managed by your organization. You can set your own API key."
|
||||
|
||||
@@ -12189,6 +12213,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T4175865785"] = "Repair Data
|
||||
-- The index of the data source '{0}' cannot be read anymore. Repairing it means building the index from scratch: everything indexed so far is thrown away, and every document of this data source is sent to your embedding provider once more. With a cloud provider, this costs money, and with a large data source it takes a while. Do you want to repair this data source now?
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATASOURCEREPAIR::T857336889"] = "The index of the data source '{0}' cannot be read anymore. Repairing it means building the index from scratch: everything indexed so far is thrown away, and every document of this data source is sent to your embedding provider once more. With a cloud provider, this costs money, and with a large data source it takes a while. Do you want to repair this data source now?"
|
||||
|
||||
-- Import Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T1681763001"] = "Import Embedding"
|
||||
|
||||
-- Add Embedding Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EMBEDDINGPROVIDERSETUP::T190634634"] = "Add Embedding Provider"
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment."
|
||||
|
||||
@@ -14541,6 +14571,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4001510395"
|
||||
-- The name must not contain control characters.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4234589878"] = "The name must not contain control characters."
|
||||
|
||||
-- The embedding provider of this data source no longer exists. Please select another one.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T4288009003"] = "The embedding provider of this data source no longer exists. Please select another one."
|
||||
|
||||
-- Please enter the host of the IMAP server, e.g., imap.example.org.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T471173229"] = "Please enter the host of the IMAP server, e.g., imap.example.org."
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using DialogOptions = AIStudio.Dialogs.DialogOptions;
|
||||
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Adds an embedding provider, either from scratch or from an imported configuration, and tells
|
||||
/// whether the user may do so.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Kept here rather than in the places which offer it -- the embedding provider panel and the data
|
||||
/// source settings, which offer it while no embedding provider exists -- so that adding one works the
|
||||
/// same way everywhere: the organization's permission is checked, the provider is stored, and the
|
||||
/// data sources are checked against it.
|
||||
/// </remarks>
|
||||
public static class EmbeddingProviderSetup
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(EmbeddingProviderSetup).Namespace, nameof(EmbeddingProviderSetup));
|
||||
|
||||
/// <summary>
|
||||
/// Whether the organization lets the user add an embedding provider.
|
||||
/// </summary>
|
||||
public static bool MayAdd(SettingsManager settingsManager) => settingsManager.ConfigurationData.App.AllowUserToAddProvider && settingsManager.ConfigurationData.App.AllowUserToAddEmbeddingProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the organization lets the user import an embedding provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An import adds a provider, so this holds only when MayAdd holds as well.
|
||||
/// </remarks>
|
||||
public static bool MayImport(SettingsManager settingsManager) => settingsManager.ConfigurationData.App.CanImportConfigurationSnippet(PluginConfigurationObjectType.EMBEDDING_PROVIDER);
|
||||
|
||||
/// <summary>
|
||||
/// Whether no embedding provider exists, so that no local data source can be prepared for the AI.
|
||||
/// </summary>
|
||||
public static bool IsMissing(SettingsManager settingsManager) => settingsManager.ConfigurationData.EmbeddingProviders.Count == 0;
|
||||
|
||||
/// <summary>
|
||||
/// The parameters which open the embedding provider dialog with the given provider filled in.
|
||||
/// </summary>
|
||||
/// <param name="embeddingProvider">The provider to fill in.</param>
|
||||
/// <param name="isEditing">True to edit this provider, false to add it as a new one, as an import does.</param>
|
||||
public static DialogParameters<EmbeddingProviderDialog> CreateDialogParameters(EmbeddingProvider embeddingProvider, bool isEditing) => new()
|
||||
{
|
||||
{ x => x.DataNum, embeddingProvider.Num },
|
||||
{ x => x.DataId, embeddingProvider.Id },
|
||||
{ x => x.DataName, embeddingProvider.Name },
|
||||
{ x => x.DataLLMProvider, embeddingProvider.UsedLLMProvider },
|
||||
{ x => x.DataCustomIconDataUrl, embeddingProvider.CustomIconDataUrl },
|
||||
{ x => x.DataModel, embeddingProvider.Model },
|
||||
{ x => x.DataHostname, embeddingProvider.Hostname },
|
||||
{ x => x.IsSelfHosted, embeddingProvider.IsSelfHosted },
|
||||
{ x => x.IsEditing, isEditing },
|
||||
{ x => x.DataHost, embeddingProvider.Host },
|
||||
{ x => x.DataTokenizerPath, embeddingProvider.TokenizerPath },
|
||||
{ x => x.DataTokenizerFingerprint, embeddingProvider.TokenizerFingerprint },
|
||||
{ x => x.DataTokenLimit, embeddingProvider.EffectiveTokenLimit },
|
||||
{ x => x.DataEmbeddingBatchSize, embeddingProvider.EffectiveEmbeddingBatchSize },
|
||||
{ x => x.HFInferenceProviderId, embeddingProvider.HFInferenceProvider },
|
||||
{ x => x.IsEnterpriseConfiguration, embeddingProvider.IsEnterpriseConfiguration },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Lets the user add an embedding provider from scratch, and stores it when they save.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The caller tells the rest of the app that the configuration changed, as the sender of that message.
|
||||
/// </remarks>
|
||||
/// <param name="dialogService">The dialog service to show the provider settings with.</param>
|
||||
/// <param name="settingsManager">The settings, which receive the provider.</param>
|
||||
/// <param name="embeddingService">The service which checks the data sources against the new provider.</param>
|
||||
/// <returns>The added provider, or null when the user cancelled or the organization does not allow adding one.</returns>
|
||||
public static async Task<EmbeddingProvider?> AddAsync(IDialogService dialogService, SettingsManager settingsManager, DataSourceEmbeddingService embeddingService)
|
||||
{
|
||||
if (!MayAdd(settingsManager))
|
||||
return null;
|
||||
|
||||
var dialogParameters = new DialogParameters<EmbeddingProviderDialog>
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
};
|
||||
|
||||
return await AddFromDialogAsync(dialogService, settingsManager, embeddingService, dialogParameters, isImport: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lets the user import an embedding provider from a configuration snippet, and stores it when they save.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The caller tells the rest of the app that the configuration changed, as the sender of that message.
|
||||
/// </remarks>
|
||||
/// <param name="dialogService">The dialog service to show the import and the provider settings with.</param>
|
||||
/// <param name="settingsManager">The settings, which receive the provider.</param>
|
||||
/// <param name="embeddingService">The service which checks the data sources against the new provider.</param>
|
||||
/// <returns>The imported provider, or null when the user cancelled or the organization does not allow importing one.</returns>
|
||||
public static async Task<EmbeddingProvider?> ImportAsync(IDialogService dialogService, SettingsManager settingsManager, DataSourceEmbeddingService embeddingService)
|
||||
{
|
||||
if (!MayImport(settingsManager))
|
||||
return null;
|
||||
|
||||
var import = await ConfigurationSnippetImportDialog.ShowAsync(dialogService, PluginConfigurationObjectType.EMBEDDING_PROVIDER, TB("Import Embedding"));
|
||||
if (import?.ConfigurationObject is not EmbeddingProvider embeddingProvider)
|
||||
return null;
|
||||
|
||||
var dialogParameters = CreateDialogParameters(embeddingProvider, isEditing: false);
|
||||
dialogParameters.Add(x => x.ImportedAPIKey, import.Secret);
|
||||
return await AddFromDialogAsync(dialogService, settingsManager, embeddingService, dialogParameters, isImport: true);
|
||||
}
|
||||
|
||||
private static async Task<EmbeddingProvider?> AddFromDialogAsync(IDialogService dialogService, SettingsManager settingsManager, DataSourceEmbeddingService embeddingService, DialogParameters<EmbeddingProviderDialog> dialogParameters, bool isImport)
|
||||
{
|
||||
var dialogReference = await dialogService.ShowAsync<EmbeddingProviderDialog>(TB("Add Embedding Provider"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return null;
|
||||
|
||||
//
|
||||
// An organization can lock the import while the user is still filling in the form, e.g.,
|
||||
// with a new version of its configuration plugin. Hence, the permission is checked once
|
||||
// more before the imported embedding provider is stored:
|
||||
//
|
||||
if (isImport && !MayImport(settingsManager))
|
||||
return null;
|
||||
|
||||
var addedEmbedding = (EmbeddingProvider)dialogResult.Data!;
|
||||
addedEmbedding = addedEmbedding with { Num = settingsManager.ConfigurationData.NextEmbeddingNum++ };
|
||||
|
||||
settingsManager.ConfigurationData.EmbeddingProviders.Add(addedEmbedding);
|
||||
await settingsManager.StoreSettings();
|
||||
await embeddingService.QueueAllInternalDataSourcesAsync();
|
||||
return addedEmbedding;
|
||||
}
|
||||
}
|
||||
@@ -39,16 +39,11 @@ public static class MailboxEditing
|
||||
return false;
|
||||
|
||||
var storedMailbox = mailboxes[position];
|
||||
var availableEmbeddings = settingsManager.GetAllEmbeddingProviders()
|
||||
.Select(provider => new ConfigurationSelectData<string>(provider.Name, provider.Id))
|
||||
.ToList();
|
||||
|
||||
var dialogParameters = new DialogParameters<DataSourceMailboxDialog>
|
||||
{
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.DataSource, storedMailbox },
|
||||
{ x => x.LockSource, await embeddingService.ShouldLockDataSourceOriginAsync(storedMailbox.Id) },
|
||||
{ x => x.AvailableEmbeddings, availableEmbeddings }
|
||||
};
|
||||
|
||||
var dialogReference = await dialogService.ShowAsync<DataSourceMailboxDialog>(TB("Edit Mailbox"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
|
||||
@@ -181,7 +181,17 @@ public sealed class DataSourceValidation
|
||||
public string? ValidateEmbeddingProviderAccess(string embeddingId)
|
||||
{
|
||||
var embeddingIssue = this.ValidateEmbeddingId(embeddingId);
|
||||
return embeddingIssue ?? this.ValidateSelectedEmbeddingProviderAccess();
|
||||
if(embeddingIssue is not null)
|
||||
return embeddingIssue;
|
||||
|
||||
//
|
||||
// An id which matches no provider belongs to one which was deleted since. Saved like this, the
|
||||
// data source keeps pointing at a provider nobody can reach, and nothing of it is embedded:
|
||||
//
|
||||
if(this.GetSelectedEmbeddingProvider() is null)
|
||||
return TB("The embedding provider of this data source no longer exists. Please select another one.");
|
||||
|
||||
return this.ValidateSelectedEmbeddingProviderAccess();
|
||||
}
|
||||
|
||||
public string? ValidateDataSourceConfidenceLevel(ConfidenceLevel confidenceLevel)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
- Improved the organization-wide management of the Batch Processing assistant. IT departments can now preset whether it includes hidden files and folders, which files and folders it leaves out, and how large a file may be, either fixed or as a default which users may change.
|
||||
- Improved the organization-wide management of the app settings. IT departments can now also set whether AI Studio saves energy while the AI writes its answers, which helps on virtual desktops, for example.
|
||||
- Improved attaching files to a chat. You can now attach any file that contains readable text, for example, program code or configuration files of a kind AI Studio did not know before.
|
||||
- Improved adding a local data source when you have not configured an embedding provider yet. Until now, you only found out when saving the dialog, after filling in everything else. The data source settings now tell you right away and let you add an embedding provider right there, without losing what you entered.
|
||||
- Changed the banner on the start page to a fresh design that shows what AI Studio can do today.
|
||||
- Fixed a warning about the confidence level that stayed in the dialog for adding a local data source, even after you chose an embedding provider that meets it. The dialog now checks again whenever you change either of them, so a warning also appears when you switch to a provider that falls short.
|
||||
- Fixed the list of data sources squeezing their names into a very narrow column when you opened it from a chat or from the background embeddings page, so the names were hard to read.
|
||||
@@ -60,6 +61,7 @@
|
||||
- Fixed data sources staying unavailable after the configuration of your organization changed their embedding provider, until one of their documents changed, or you restarted AI Studio. When AI Studio updates your data sources automatically, it now rebuilds their index right away.
|
||||
- Fixed AI Studio deleting the index of a local data source when it could not reach its folder or file, for example, because the drive was not connected. Once the folder was back, AI Studio indexed everything again, which could take hours. AI Studio now keeps the index and tells you that it cannot reach the folder. The same applies to subfolders you are not allowed to open.
|
||||
- Fixed AI Studio rebuilding the index of a data source from scratch without asking you when part of the index was missing on your computer. Since this sends every document to your embedding provider once more, AI Studio now tells you about the missing index and offers to repair the data source.
|
||||
- Fixed saving a local data source whose embedding provider had been deleted, without choosing a new one. The dialog now asks you to select an embedding provider, so that AI Studio can prepare the data source again.
|
||||
- Fixed justified texts being hyphenated by the rules of English even when AI Studio shows another language, such as German. Screen readers now also know which language AI Studio uses.
|
||||
- Fixed the log file of AI Studio showing the wrong time for some entries when AI Studio was busy. Each entry now shows when it actually happened.
|
||||
- Fixed AI Studio pausing for a moment while it opened the local index of a data source, such as a mailbox. Other work, for example applying the configuration of your organization, had to wait until then.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Validation;
|
||||
|
||||
namespace AIStudio.Tests.Tools.Validation;
|
||||
|
||||
/// <summary>
|
||||
/// Checks the choice of the embedding provider in the dialogs of the local data sources.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public sealed class DataSourceEmbeddingValidationTests
|
||||
{
|
||||
private const string EMBEDDING_ID = "4b7c7f0e-5d1a-4c55-9a43-0f9b6f2c1d2e";
|
||||
|
||||
[Test]
|
||||
public void AnEmptyChoiceIsRejected()
|
||||
{
|
||||
var validation = new DataSourceValidation { GetSelectedEmbeddingProvider = () => null };
|
||||
|
||||
Assert.That(validation.ValidateEmbeddingProviderAccess(string.Empty), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AProviderWhichNoLongerExistsIsRejected()
|
||||
{
|
||||
// The dialogs resolve the id against the configured providers, so a deleted one resolves to nothing:
|
||||
var validation = new DataSourceValidation { GetSelectedEmbeddingProvider = () => null };
|
||||
|
||||
Assert.That(validation.ValidateEmbeddingProviderAccess(EMBEDDING_ID), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnExistingProviderIsAccepted()
|
||||
{
|
||||
var embeddingProvider = new EmbeddingProvider(1, EMBEDDING_ID, "Test embeddings", LLMProviders.OPEN_AI, new("text-embedding-3-small", "text-embedding-3-small"));
|
||||
var validation = new DataSourceValidation { GetSelectedEmbeddingProvider = () => embeddingProvider };
|
||||
|
||||
Assert.That(validation.ValidateEmbeddingProviderAccess(EMBEDDING_ID), Is.Null);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user