Offer the embedding models of every self-hosted engine

This commit is contained in:
Thorsten Sommer 2026-09-19 12:34:55 +02:00
parent c6e36a11d3
commit d79f3c2100
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
3 changed files with 19 additions and 69 deletions

View File

@ -85,46 +85,28 @@
<MudField FullWidth="true" Label="@T("Model selection")" Variant="Variant.Outlined" Class="mb-3"> <MudField FullWidth="true" Label="@T("Model selection")" Variant="Variant.Outlined" Class="mb-3">
<MudStack Row="@true" AlignItems="AlignItems.Center" StretchItems="StretchItems.End"> <MudStack Row="@true" AlignItems="AlignItems.Center" StretchItems="StretchItems.End">
@if (this.DataLLMProvider.IsEmbeddingModelProvidedManually(this.DataHost)) <MudButton Disabled="@(this.IsEnterpriseConfiguration || !this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="@this.ReloadModels">
@T("Load")
</MudButton>
@if (this.availableModels.Count is 0)
{ {
<MudTextField <MudText Typo="Typo.body1">
T="string" @T("No models loaded or available.")
@bind-Text="@this.dataManuallyModel" </MudText>
Label="@T("Model")"
Class="mb-3"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Dns"
AdornmentColor="Color.Info"
Disabled="@this.IsEnterpriseConfiguration"
Validation="@this.ValidateManuallyModel"
UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="@T("Currently, we cannot query the embedding models for the selected provider and/or host. Therefore, please enter the model name manually.")"/>
} }
else else
{ {
<MudButton Disabled="@(this.IsEnterpriseConfiguration || !this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="@this.ReloadModels"> <MudSelect Disabled="@(this.IsEnterpriseConfiguration || this.IsNoneProvider)" @bind-Value="@this.DataModel" Label="@T("Model")"
@T("Load") OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural"
</MudButton> AdornmentColor="Color.Info" Adornment="Adornment.Start"
@if (this.availableModels.Count is 0) Validation="@this.providerValidation.ValidatingModel">
{ @foreach (var model in this.availableModels)
<MudText Typo="Typo.body1"> {
@T("No models loaded or available.") <MudSelectItem Value="@model">
</MudText> @model
} </MudSelectItem>
else }
{ </MudSelect>
<MudSelect Disabled="@(this.IsEnterpriseConfiguration || this.IsNoneProvider)" @bind-Value="@this.DataModel" Label="@T("Model")"
OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural"
AdornmentColor="Color.Info" Adornment="Adornment.Start"
Validation="@this.providerValidation.ValidatingModel">
@foreach (var model in this.availableModels)
{
<MudSelectItem Value="@model">
@model
</MudSelectItem>
}
</MudSelect>
}
} }
</MudStack> </MudStack>
@if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue)) @if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue))

View File

@ -133,7 +133,6 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
private string[] dataIssues = []; private string[] dataIssues = [];
private string dataAPIKey = string.Empty; private string dataAPIKey = string.Empty;
private bool dataHadStoredAPIKeyOnLoad; private bool dataHadStoredAPIKeyOnLoad;
private string dataManuallyModel = string.Empty;
private string dataAPIKeyStorageIssue = string.Empty; private string dataAPIKeyStorageIssue = string.Empty;
private string dataEditingPreviousInstanceName = string.Empty; private string dataEditingPreviousInstanceName = string.Empty;
private string dataLoadingModelsIssue = string.Empty; private string dataLoadingModelsIssue = string.Empty;
@ -162,7 +161,6 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName,
GetUsedInstanceNames = () => this.UsedInstanceNames, GetUsedInstanceNames = () => this.UsedInstanceNames,
GetHost = () => this.DataHost, GetHost = () => this.DataHost,
IsModelProvidedManually = () => this.DataLLMProvider.IsEmbeddingModelProvidedManually(this.DataHost),
GetCustomTokenizerValidationIssue = () => this.dataCustomTokenizerValidationIssue, GetCustomTokenizerValidationIssue = () => this.dataCustomTokenizerValidationIssue,
}; };
} }
@ -170,24 +168,13 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
private EmbeddingProvider CreateEmbeddingProviderSettings() private EmbeddingProvider CreateEmbeddingProviderSettings()
{ {
var cleanedHostname = this.DataHostname.Trim(); var cleanedHostname = this.DataHostname.Trim();
Model model = default;
if(this.DataLLMProvider is LLMProviders.SELF_HOSTED)
{
if (this.DataLLMProvider.IsEmbeddingModelProvidedManually(this.DataHost))
model = new Model(this.dataManuallyModel, null);
else if (this.DataHost is Host.LM_STUDIO)
model = this.DataModel;
}
else
model = this.DataModel;
return new() return new()
{ {
Num = this.DataNum, Num = this.DataNum,
Id = this.DataId, Id = this.DataId,
Name = this.DataName, Name = this.DataName,
UsedLLMProvider = this.DataLLMProvider, UsedLLMProvider = this.DataLLMProvider,
Model = model, Model = this.DataModel,
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED, IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname, Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
Host = this.DataHost, Host = this.DataHost,
@ -225,10 +212,6 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|| this.DataTokenLimit != EmbeddingProvider.DEFAULT_TOKEN_LIMIT || this.DataTokenLimit != EmbeddingProvider.DEFAULT_TOKEN_LIMIT
|| this.DataEmbeddingBatchSize != EmbeddingProvider.DEFAULT_EMBEDDING_BATCH_SIZE; || this.DataEmbeddingBatchSize != EmbeddingProvider.DEFAULT_EMBEDDING_BATCH_SIZE;
// When using self-hosted embedding, we must copy the model name:
if (this.DataLLMProvider is LLMProviders.SELF_HOSTED)
this.dataManuallyModel = this.DataModel.Id;
// Load the API key. A self-hosted server may well need one: LM Studio can ask for a // Load the API key. A self-hosted server may well need one: LM Studio can ask for a
// token of its own, and any of these servers can sit behind an authenticating proxy. // token of its own, and any of these servers can sit behind an authenticating proxy.
// So we try for every host and treat a missing key as the normal case (isTrying). // So we try for every host and treat a missing key as the normal case (isTrying).
@ -358,14 +341,6 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
this.MudDialog.Close(DialogResult.Ok(addedProviderSettings)); this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
} }
private string? ValidateManuallyModel(string manuallyModel)
{
if (this.DataLLMProvider is LLMProviders.SELF_HOSTED && string.IsNullOrWhiteSpace(manuallyModel))
return T("Please enter an embedding model name.");
return null;
}
private string? ValidateTokenLimit(int tokenLimit) private string? ValidateTokenLimit(int tokenLimit)
{ {
if (tokenLimit < 1) if (tokenLimit < 1)
@ -516,7 +491,6 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
// When the host changes, reset the model selection state: // When the host changes, reset the model selection state:
this.DataHost = selectedHost; this.DataHost = selectedHost;
this.DataModel = default; this.DataModel = default;
this.dataManuallyModel = string.Empty;
this.availableModels.Clear(); this.availableModels.Clear();
this.dataLoadingModelsIssue = string.Empty; this.dataLoadingModelsIssue = string.Empty;
} }

View File

@ -421,12 +421,6 @@ public static class LLMProvidersExtensions
_ => false, _ => false,
}; };
public static bool IsEmbeddingModelProvidedManually(this LLMProviders provider, Host host) => provider switch
{
LLMProviders.SELF_HOSTED => host is not Host.LM_STUDIO,
_ => false,
};
public static bool IsTranscriptionModelProvidedManually(this LLMProviders provider, Host host) => provider switch public static bool IsTranscriptionModelProvidedManually(this LLMProviders provider, Host host) => provider switch
{ {
_ => false, _ => false,