2025-01-05 14:11:15 +00:00
using AIStudio.Dialogs ;
using AIStudio.Settings ;
2026-02-05 20:03:12 +00:00
using AIStudio.Tools.PluginSystem ;
2025-01-05 14:11:15 +00:00
using Microsoft.AspNetCore.Components ;
using DialogOptions = AIStudio . Dialogs . DialogOptions ;
namespace AIStudio.Components.Settings ;
public partial class SettingsPanelEmbeddings : SettingsPanelBase
{
[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 } ,
} ;
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 ) ;
2025-01-05 14:11:15 +00:00
if ( deleteSecretResponse . Success )
{
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-05 09:35:20 +00:00
private async Task ExportEmbeddingProvider ( EmbeddingProvider provider )
{
if ( provider = = EmbeddingProvider . NONE )
return ;
2026-02-05 20:03:12 +00:00
string? encryptedApiKey = null ;
// Check if the provider has an API key stored:
var apiKeyResponse = await this . RustService . GetAPIKey ( provider , SecretStoreType . EMBEDDING_PROVIDER , isTrying : true ) ;
if ( apiKeyResponse . Success )
{
// Ask the user if they want to export the API key:
var dialogParameters = new DialogParameters < ConfirmDialog >
{
{ x = > x . Message , T ( "This provider has an API key configured. Do you want to include the encrypted API key in the export? Note: The recipient will need the same encryption secret to use the API key." ) } ,
} ;
var dialogReference = await this . DialogService . ShowAsync < ConfirmDialog > ( T ( "Export API Key?" ) , dialogParameters , DialogOptions . FULLSCREEN ) ;
var dialogResult = await dialogReference . Result ;
if ( dialogResult is { Canceled : false } )
{
// User wants to export the API key - encrypt it:
var encryption = PluginFactory . EnterpriseEncryption ;
if ( encryption ? . IsAvailable = = true )
{
var decryptedApiKey = await apiKeyResponse . Secret . Decrypt ( Program . ENCRYPTION ) ;
if ( encryption . TryEncrypt ( decryptedApiKey , out var encrypted ) )
encryptedApiKey = encrypted ;
}
else
{
// No encryption secret available - inform the user:
2026-02-07 11:21:06 +00:00
this . Snackbar . Add ( T ( "Cannot export the encrypted API key: No enterprise encryption secret is configured." ) , Severity . Warning ) ;
2026-02-05 20:03:12 +00:00
}
}
}
var luaCode = provider . ExportAsConfigurationSection ( encryptedApiKey ) ;
2026-02-05 09:35:20 +00:00
if ( string . IsNullOrWhiteSpace ( luaCode ) )
return ;
await this . RustService . CopyText2Clipboard ( this . Snackbar , luaCode ) ;
}
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-05 09:59:59 +00:00
}