diff --git a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor
index 9b8fc5b9..0a75e399 100644
--- a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor
+++ b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor
@@ -146,6 +146,57 @@
}
+
+ Embedding settings
+
+
+
+ You will likely use one or more embedding methods to encode the meaning of your data into a typically high-dimensional vector
+ space. In this case, you will use a vector database to store and search these vectors (called embeddings). However, you don't
+ have to use embedding methods. When your retrieval method works without any embedding, you can ignore this section. An example: You
+ store files on a file server, and your retrieval method works exclusively with file names in the file system, so you don't
+ need embeddings.
+
+
+
+ You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries
+ or data types. For example, one embedding for texts, another for images, and a third for videos, etc.
+
+
+
+
+
+
+
+
+
+ Name
+ Type
+ Actions
+
+
+ @context.EmbeddingName
+ @context.EmbeddingType
+
+
+ Edit
+
+
+ Delete
+
+
+
+
+
+@if(this.embeddings.Count == 0)
+{
+ No embeddings configured yet.
+}
+
+
+ Add Embedding
+
+
Data retrieval settings
diff --git a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs
index 1b1107a2..f50459ef 100644
--- a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs
+++ b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs
@@ -1,7 +1,10 @@
using AIStudio.Chat;
+using AIStudio.Dialogs;
using Microsoft.AspNetCore.Components;
+using DialogOptions = AIStudio.Dialogs.DialogOptions;
+
namespace AIStudio.Assistants.ERI;
public partial class AssistantERI : AssistantBaseCore
@@ -9,6 +12,9 @@ public partial class AssistantERI : AssistantBaseCore
[Inject]
private HttpClient HttpClient { get; set; } = null!;
+ [Inject]
+ private IDialogService DialogService { get; init; } = null!;
+
public override Tools.Components Component => Tools.Components.ERI_ASSISTANT;
protected override string Title => "ERI Server";
@@ -56,6 +62,7 @@ public partial class AssistantERI : AssistantBaseCore
this.authDescription = string.Empty;
this.selectedOperatingSystem = OperatingSystem.NONE;
this.allowedLLMProviders = AllowedLLMProviders.NONE;
+ this.embeddings = new();
this.retrievalDescription = string.Empty;
this.additionalLibraries = string.Empty;
}
@@ -83,6 +90,7 @@ public partial class AssistantERI : AssistantBaseCore
this.authDescription = this.SettingsManager.ConfigurationData.ERI.PreselectedAuthDescription;
this.selectedOperatingSystem = this.SettingsManager.ConfigurationData.ERI.PreselectedOperatingSystem;
this.allowedLLMProviders = this.SettingsManager.ConfigurationData.ERI.PreselectedAllowedLLMProviders;
+ this.embeddings = this.SettingsManager.ConfigurationData.ERI.EmbeddingInfos;
this.retrievalDescription = this.SettingsManager.ConfigurationData.ERI.PreselectedRetrievalDescription;
this.additionalLibraries = this.SettingsManager.ConfigurationData.ERI.PreselectedAdditionalLibraries;
return true;
@@ -115,6 +123,7 @@ public partial class AssistantERI : AssistantBaseCore
this.SettingsManager.ConfigurationData.ERI.PreselectedAuthDescription = this.authDescription;
this.SettingsManager.ConfigurationData.ERI.PreselectedOperatingSystem = this.selectedOperatingSystem;
this.SettingsManager.ConfigurationData.ERI.PreselectedAllowedLLMProviders = this.allowedLLMProviders;
+ this.SettingsManager.ConfigurationData.ERI.EmbeddingInfos = this.embeddings;
this.SettingsManager.ConfigurationData.ERI.PreselectedRetrievalDescription = this.retrievalDescription;
this.SettingsManager.ConfigurationData.ERI.PreselectedAdditionalLibraries = this.additionalLibraries;
await this.SettingsManager.StoreSettings();
@@ -135,6 +144,7 @@ public partial class AssistantERI : AssistantBaseCore
private string authDescription = string.Empty;
private OperatingSystem selectedOperatingSystem = OperatingSystem.NONE;
private AllowedLLMProviders allowedLLMProviders = AllowedLLMProviders.NONE;
+ private List embeddings = new();
private string retrievalDescription = string.Empty;
private string additionalLibraries = string.Empty;
@@ -389,6 +399,62 @@ public partial class AssistantERI : AssistantBaseCore
return true;
}
}
+
+ private async Task AddEmbedding()
+ {
+ var dialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, false },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync("Add Embedding", dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled)
+ return;
+
+ var addedEmbedding = (EmbeddingInfo)dialogResult.Data!;
+ this.embeddings.Add(addedEmbedding);
+ await this.AutoSave();
+ }
+
+ private async Task EditEmbedding(EmbeddingInfo embeddingInfo)
+ {
+ var dialogParameters = new DialogParameters
+ {
+ { x => x.DataEmbeddingName, embeddingInfo.EmbeddingName },
+ { x => x.DataEmbeddingType, embeddingInfo.EmbeddingType },
+ { x => x.DataDescription, embeddingInfo.Description },
+ { x => x.DataUsedWhen, embeddingInfo.UsedWhen },
+ { x => x.DataLink, embeddingInfo.Link },
+ { x => x.IsEditing, true },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync("Edit Embedding", dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled)
+ return;
+
+ var editedEmbedding = (EmbeddingInfo)dialogResult.Data!;
+
+ this.embeddings[this.embeddings.IndexOf(embeddingInfo)] = editedEmbedding;
+ await this.AutoSave();
+ }
+
+ private async Task DeleteEmbedding(EmbeddingInfo embeddingInfo)
+ {
+ var dialogParameters = new DialogParameters
+ {
+ { "Message", $"Are you sure you want to delete the embedding '{embeddingInfo.EmbeddingName}'?" },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync("Delete Embedding", dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled)
+ return;
+
+ this.embeddings.Remove(embeddingInfo);
+ await this.AutoSave();
+ }
private async Task GenerateServer()
{
diff --git a/app/MindWork AI Studio/Assistants/ERI/EmbeddingInfo.cs b/app/MindWork AI Studio/Assistants/ERI/EmbeddingInfo.cs
new file mode 100644
index 00000000..938ac20e
--- /dev/null
+++ b/app/MindWork AI Studio/Assistants/ERI/EmbeddingInfo.cs
@@ -0,0 +1,19 @@
+namespace AIStudio.Assistants.ERI;
+
+///
+/// Represents information about the used embedding for a data source.
+///
+/// What kind of embedding is used. For example, "Transformer Embedding," "Contextual Word
+/// Embedding," "Graph Embedding," etc.
+/// Name the embedding used. This can be a library, a framework, or the name of the used
+/// algorithm.
+/// A short description of the embedding. Describe what the embedding is doing.
+/// Describe when the embedding is used. For example, when the user prompt contains certain
+/// keywords, or anytime?
+/// A link to the embedding's documentation or the source code. Might be null.
+public readonly record struct EmbeddingInfo(
+ string EmbeddingType,
+ string EmbeddingName,
+ string Description,
+ string UsedWhen,
+ string? Link);
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor b/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor
new file mode 100644
index 00000000..0fe1b64b
--- /dev/null
+++ b/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor
@@ -0,0 +1,103 @@
+
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+
+
+
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+
+
+
+
+ Cancel
+
+ @if(this.IsEditing)
+ {
+ @:Update
+ }
+ else
+ {
+ @:Add
+ }
+
+
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor.cs
new file mode 100644
index 00000000..2b394f5f
--- /dev/null
+++ b/app/MindWork AI Studio/Dialogs/EmbeddingMethodDialog.razor.cs
@@ -0,0 +1,129 @@
+using AIStudio.Assistants.ERI;
+using AIStudio.Settings;
+
+using Microsoft.AspNetCore.Components;
+
+namespace AIStudio.Dialogs;
+
+public partial class EmbeddingMethodDialog : ComponentBase
+{
+ [CascadingParameter]
+ private MudDialogInstance MudDialog { get; set; } = null!;
+
+ ///
+ /// The user chosen embedding name.
+ ///
+ [Parameter]
+ public string DataEmbeddingName { get; set; } = string.Empty;
+
+ ///
+ /// The user chosen embedding type.
+ ///
+ [Parameter]
+ public string DataEmbeddingType { get; set; } = string.Empty;
+
+ ///
+ /// The embedding description.
+ ///
+ [Parameter]
+ public string DataDescription { get; set; } = string.Empty;
+
+ ///
+ /// When is the embedding used?
+ ///
+ [Parameter]
+ public string DataUsedWhen { get; set; } = string.Empty;
+
+ ///
+ /// A link to the embedding documentation or the source code. Might be null, which means no link is provided.
+ ///
+ [Parameter]
+ public string? DataLink { get; set; }
+
+ ///
+ /// Should the dialog be in editing mode?
+ ///
+ [Parameter]
+ public bool IsEditing { get; init; }
+
+ [Inject]
+ private SettingsManager SettingsManager { get; init; } = null!;
+
+ private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new();
+
+ private bool dataIsValid;
+ private string[] dataIssues = [];
+
+ // We get the form reference from Blazor code to validate it manually:
+ private MudForm form = null!;
+
+ private EmbeddingInfo CreateEmbeddingInfo() => new(this.DataEmbeddingType, this.DataEmbeddingName, this.DataDescription, this.DataUsedWhen, this.DataLink);
+
+ #region Overrides of ComponentBase
+
+ protected override async Task OnInitializedAsync()
+ {
+ // Configure the spellchecking for the instance name input:
+ this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
+
+ await base.OnInitializedAsync();
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ // Reset the validation when not editing and on the first render.
+ // We don't want to show validation errors when the user opens the dialog.
+ if(!this.IsEditing && firstRender)
+ this.form.ResetValidation();
+
+ await base.OnAfterRenderAsync(firstRender);
+ }
+
+ #endregion
+
+ private string? ValidateName(string name)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ return "The embedding name must not be empty. Please name the embedding.";
+
+ return null;
+ }
+
+ private string? ValidateType(string type)
+ {
+ if (string.IsNullOrWhiteSpace(type))
+ return "The embedding type must not be empty. Please specify the embedding type.";
+
+ return null;
+ }
+
+ private string? ValidateDescription(string description)
+ {
+ if (string.IsNullOrWhiteSpace(description))
+ return "The description must not be empty. Please describe the embedding method.";
+
+ return null;
+ }
+
+ private string? ValidateUsedWhen(string usedWhen)
+ {
+ if (string.IsNullOrWhiteSpace(usedWhen))
+ return "Please describe when the embedding is used. Might be anytime or when certain keywords are present, etc.";
+
+ return null;
+ }
+
+ private async Task Store()
+ {
+ await this.form.Validate();
+
+ // When the data is not valid, we don't store it:
+ if (!this.dataIsValid)
+ return;
+
+ var embeddingInfo = this.CreateEmbeddingInfo();
+ this.MudDialog.Close(DialogResult.Ok(embeddingInfo));
+ }
+
+ private void Cancel() => this.MudDialog.Cancel();
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Settings/DataModel/DataERI.cs b/app/MindWork AI Studio/Settings/DataModel/DataERI.cs
index 9e389f4b..bbdc779a 100644
--- a/app/MindWork AI Studio/Settings/DataModel/DataERI.cs
+++ b/app/MindWork AI Studio/Settings/DataModel/DataERI.cs
@@ -87,6 +87,11 @@ public sealed class DataERI
///
public AllowedLLMProviders PreselectedAllowedLLMProviders { get; set; } = AllowedLLMProviders.NONE;
+ ///
+ /// Do you want to predefine any embedding information?
+ ///
+ public List EmbeddingInfos { get; set; } = new();
+
///
/// Do you want to preselect a retrieval description?
///