2026-02-20 14:32:54 +00:00
using System.Globalization ;
2025-01-05 14:11:15 +00:00
using AIStudio.Dialogs ;
2026-02-20 14:32:54 +00:00
using AIStudio.Provider ;
2025-01-05 14:11:15 +00:00
using AIStudio.Settings ;
2026-04-23 14:29:30 +00:00
using AIStudio.Tools.Services ;
using AIStudio.Tools.Rust ;
2025-01-05 14:11:15 +00:00
using Microsoft.AspNetCore.Components ;
using DialogOptions = AIStudio . Dialogs . DialogOptions ;
namespace AIStudio.Components.Settings ;
2026-02-07 21:59:41 +00:00
public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
2025-01-05 14:11:15 +00:00
{
[Parameter]
public List < ConfigurationSelectData < string > > AvailableEmbeddingProviders { get ; set ; } = new ( ) ;
[Parameter]
public EventCallback < List < ConfigurationSelectData < string > > > AvailableEmbeddingProvidersChanged { get ; set ; }
2026-01-18 16:15:18 +00:00
private string GetEmbeddingProviderModelName ( EmbeddingProvider provider )
2025-01-05 14:11:15 +00:00
{
2026-01-18 16:15:18 +00:00
// For system models, return localized text:
if ( provider . Model . IsSystemModel )
return T ( "Uses the provider-configured model" ) ;
2025-01-05 14:11:15 +00:00
const int MAX_LENGTH = 36 ;
var modelName = provider . Model . ToString ( ) ;
return modelName . Length > MAX_LENGTH ? "[...] " + modelName [ ^ Math . Min ( MAX_LENGTH , modelName . Length ) . . ] : modelName ;
}
2025-01-13 18:51:26 +00:00
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync ( )
{
await this . UpdateEmbeddingProviders ( ) ;
await base . OnInitializedAsync ( ) ;
}
#endregion
2025-01-05 14:11:15 +00:00
private async Task AddEmbeddingProvider ( )
{
var dialogParameters = new DialogParameters < EmbeddingProviderDialog >
{
{ x = > x . IsEditing , false } ,
} ;
2025-05-11 14:57:52 +00:00
var dialogReference = await this . DialogService . ShowAsync < EmbeddingProviderDialog > ( T ( "Add Embedding Provider" ) , dialogParameters , DialogOptions . FULLSCREEN ) ;
2025-01-05 14:11:15 +00:00
var dialogResult = await dialogReference . Result ;
if ( dialogResult is null | | dialogResult . Canceled )
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 . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
private async Task EditEmbeddingProvider ( EmbeddingProvider embeddingProvider )
{
var dialogParameters = new DialogParameters < EmbeddingProviderDialog >
{
{ x = > x . DataNum , embeddingProvider . Num } ,
{ x = > x . DataId , embeddingProvider . Id } ,
{ x = > x . DataName , embeddingProvider . Name } ,
{ x = > x . DataLLMProvider , embeddingProvider . UsedLLMProvider } ,
{ x = > x . DataModel , embeddingProvider . Model } ,
{ x = > x . DataHostname , embeddingProvider . Hostname } ,
{ x = > x . IsSelfHosted , embeddingProvider . IsSelfHosted } ,
{ x = > x . IsEditing , true } ,
{ x = > x . DataHost , embeddingProvider . Host } ,
2026-04-10 16:34:10 +00:00
{ x = > x . DataTokenizerPath , embeddingProvider . TokenizerPath } ,
2025-01-05 14:11:15 +00:00
} ;
2025-05-11 14:57:52 +00:00
var dialogReference = await this . DialogService . ShowAsync < EmbeddingProviderDialog > ( T ( "Edit Embedding Provider" ) , dialogParameters , DialogOptions . FULLSCREEN ) ;
2025-01-05 14:11:15 +00:00
var dialogResult = await dialogReference . Result ;
if ( dialogResult is null | | dialogResult . Canceled )
return ;
var editedEmbeddingProvider = ( EmbeddingProvider ) dialogResult . Data ! ;
// Set the provider number if it's not set. This is important for providers
// added before we started saving the provider number.
if ( editedEmbeddingProvider . Num = = 0 )
editedEmbeddingProvider = editedEmbeddingProvider with { Num = this . SettingsManager . ConfigurationData . NextEmbeddingNum + + } ;
this . SettingsManager . ConfigurationData . EmbeddingProviders [ this . SettingsManager . ConfigurationData . EmbeddingProviders . IndexOf ( embeddingProvider ) ] = editedEmbeddingProvider ;
await this . UpdateEmbeddingProviders ( ) ;
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
private async Task DeleteEmbeddingProvider ( EmbeddingProvider provider )
{
2025-08-28 16:51:44 +00:00
var dialogParameters = new DialogParameters < ConfirmDialog >
2025-01-05 14:11:15 +00:00
{
2025-08-28 16:51:44 +00:00
{ x = > x . Message , string . Format ( T ( "Are you sure you want to delete the embedding provider '{0}'?" ) , provider . Name ) } ,
2025-01-05 14:11:15 +00:00
} ;
2025-05-11 14:57:52 +00:00
var dialogReference = await this . DialogService . ShowAsync < ConfirmDialog > ( T ( "Delete Embedding Provider" ) , dialogParameters , DialogOptions . FULLSCREEN ) ;
2025-01-05 14:11:15 +00:00
var dialogResult = await dialogReference . Result ;
if ( dialogResult is null | | dialogResult . Canceled )
return ;
2026-01-11 15:02:28 +00:00
var deleteSecretResponse = await this . RustService . DeleteAPIKey ( provider , SecretStoreType . EMBEDDING_PROVIDER ) ;
2026-04-23 14:29:30 +00:00
var deleteTokenizerResponse = await this . RustService . DeleteTokenizer ( TokenizerModelId . ForEmbeddingProvider ( provider ) ) ;
if ( deleteSecretResponse . Success & & deleteTokenizerResponse . Success )
2025-01-05 14:11:15 +00:00
{
this . SettingsManager . ConfigurationData . EmbeddingProviders . Remove ( provider ) ;
await this . SettingsManager . StoreSettings ( ) ;
}
2026-04-23 14:29:30 +00:00
else
{
var issueDialogParameters = new DialogParameters < ConfirmDialog >
{
{ x = > x . Message , string . Format ( T ( "Couldn't delete the embedding provider '{0}'. The issue: {1}. We can ignore this issue and delete the embedding provider anyway. Do you want to ignore it and delete this embedding provider?" ) , provider . Name , BuildDeleteIssue ( deleteSecretResponse , deleteTokenizerResponse ) ) } ,
} ;
var issueDialogReference = await this . DialogService . ShowAsync < ConfirmDialog > ( T ( "Delete Embedding Provider" ) , issueDialogParameters , DialogOptions . FULLSCREEN ) ;
var issueDialogResult = await issueDialogReference . Result ;
if ( issueDialogResult is null | | issueDialogResult . Canceled )
return ;
this . SettingsManager . ConfigurationData . EmbeddingProviders . Remove ( provider ) ;
await this . SettingsManager . StoreSettings ( ) ;
}
2026-01-11 15:02:28 +00:00
2025-01-05 14:11:15 +00:00
await this . UpdateEmbeddingProviders ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
2026-02-07 21:59:41 +00:00
2026-04-23 14:29:30 +00:00
private static string BuildDeleteIssue ( DeleteSecretResponse deleteSecretResponse , TokenizerResponse deleteTokenizerResponse )
{
var issues = new List < string > ( ) ;
if ( ! deleteSecretResponse . Success )
issues . Add ( deleteSecretResponse . Issue ) ;
if ( ! deleteTokenizerResponse . Success )
issues . Add ( deleteTokenizerResponse . Message ) ;
return string . Join ( " | " , issues ) ;
}
2026-02-07 21:59:41 +00:00
private async Task ExportEmbeddingProvider ( EmbeddingProvider provider )
{
2026-02-19 20:31:59 +00:00
if ( ! this . SettingsManager . ConfigurationData . App . ShowAdminSettings )
return ;
2026-02-07 21:59:41 +00:00
if ( provider = = EmbeddingProvider . NONE )
return ;
await this . ExportProvider ( provider , SecretStoreType . EMBEDDING_PROVIDER , provider . ExportAsConfigurationSection ) ;
}
2025-01-05 14:11:15 +00:00
private async Task UpdateEmbeddingProviders ( )
{
this . AvailableEmbeddingProviders . Clear ( ) ;
foreach ( var provider in this . SettingsManager . ConfigurationData . EmbeddingProviders )
this . AvailableEmbeddingProviders . Add ( new ( provider . Name , provider . Id ) ) ;
await this . AvailableEmbeddingProvidersChanged . InvokeAsync ( this . AvailableEmbeddingProviders ) ;
}
2026-02-20 14:32:54 +00:00
private async Task TestEmbeddingProvider ( EmbeddingProvider provider )
{
var dialogParameters = new DialogParameters < SingleInputDialog >
{
{ x = > x . ConfirmText , T ( "Embed text" ) } ,
{ x = > x . InputHeaderText , T ( "Add text that should be embedded:" ) } ,
{ x = > x . UserInput , T ( "Example text to embed" ) } ,
} ;
var dialogReference = await this . DialogService . ShowAsync < SingleInputDialog > ( T ( "Test Embedding Provider" ) , dialogParameters , DialogOptions . FULLSCREEN ) ;
var dialogResult = await dialogReference . Result ;
if ( dialogResult is null | | dialogResult . Canceled )
return ;
var inputText = dialogResult . Data as string ;
if ( string . IsNullOrWhiteSpace ( inputText ) )
return ;
var embeddingProvider = provider . CreateProvider ( ) ;
2026-04-15 08:17:14 +00:00
var embeddings = await embeddingProvider . EmbedTextAsync ( provider . Model , this . SettingsManager , CancellationToken . None , inputText ) ;
2026-02-20 14:32:54 +00:00
if ( embeddings . Count = = 0 )
{
await this . DialogService . ShowMessageBox ( T ( "Embedding Result" ) , T ( "No embedding was returned." ) , T ( "Close" ) ) ;
return ;
}
var vector = embeddings . FirstOrDefault ( ) ;
if ( vector is null | | vector . Count = = 0 )
{
await this . DialogService . ShowMessageBox ( T ( "Embedding Result" ) , T ( "No embedding was returned." ) , T ( "Close" ) ) ;
return ;
}
var resultText = string . Join ( Environment . NewLine , vector . Select ( value = > value . ToString ( "G9" , CultureInfo . InvariantCulture ) ) ) ;
var resultParameters = new DialogParameters < EmbeddingResultDialog >
{
{ x = > x . ResultText , resultText } ,
{ x = > x . ResultLabel , T ( "Embedding Vector (one dimension per line)" ) } ,
} ;
await this . DialogService . ShowAsync < EmbeddingResultDialog > ( T ( "Embedding Result" ) , resultParameters , DialogOptions . FULLSCREEN ) ;
}
2026-02-07 21:59:41 +00:00
}