Improved error handling for model loading across dialogs

This commit is contained in:
Thorsten Sommer 2026-01-18 12:45:57 +01:00
parent 8107c97a6e
commit cb5e4e063f
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
7 changed files with 89 additions and 31 deletions

View File

@ -101,6 +101,12 @@
}
}
</MudStack>
@if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue))
{
<MudAlert Severity="Severity.Error" Class="mt-3">
@this.dataLoadingModelsIssue
</MudAlert>
}
</MudField>
@* ReSharper disable once CSharpWarnings::CS8974 *@

View File

@ -71,7 +71,10 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
private ILogger<EmbeddingProviderDialog> Logger { get; init; } = null!;
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
/// <summary>
@ -85,7 +88,8 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
private string dataManuallyModel = string.Empty;
private string dataAPIKeyStorageIssue = string.Empty;
private string dataEditingPreviousInstanceName = string.Empty;
private string dataLoadingModelsIssue = string.Empty;
// We get the form reference from Blazor code to validate it manually:
private MudForm form = null!;
@ -263,18 +267,27 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
private async Task ReloadModels()
{
this.dataLoadingModelsIssue = string.Empty;
var currentEmbeddingProviderSettings = this.CreateEmbeddingProviderSettings();
var provider = currentEmbeddingProviderSettings.CreateProvider();
if(provider is NoProvider)
if (provider is NoProvider)
return;
var models = await provider.GetEmbeddingModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
try
{
var models = await provider.GetEmbeddingModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
}
catch (Exception e)
{
this.Logger.LogError($"Failed to load models from provider '{this.DataLLMProvider}' (host={this.DataHost}, hostname='{this.DataHostname}'): {e.Message}");
this.dataLoadingModelsIssue = T("We are currently unable to communicate with the provider to load models. Please try again later.");
}
}
private string APIKeyText => this.DataLLMProvider switch

View File

@ -116,6 +116,12 @@
}
}
</MudStack>
@if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue))
{
<MudAlert Severity="Severity.Error" Class="mt-3">
@this.dataLoadingModelsIssue
</MudAlert>
}
</MudField>
@* ReSharper disable once CSharpWarnings::CS8974 *@

View File

@ -84,6 +84,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
private ILogger<ProviderDialog> Logger { get; init; } = null!;
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
/// <summary>
@ -97,6 +100,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
private string dataManuallyModel = string.Empty;
private string dataAPIKeyStorageIssue = string.Empty;
private string dataEditingPreviousInstanceName = string.Empty;
private string dataLoadingModelsIssue = string.Empty;
private bool showExpertSettings;
// We get the form reference from Blazor code to validate it manually:
@ -277,18 +281,27 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
private async Task ReloadModels()
{
this.dataLoadingModelsIssue = string.Empty;
var currentProviderSettings = this.CreateProviderSettings();
var provider = currentProviderSettings.CreateProvider();
if(provider is NoProvider)
if (provider is NoProvider)
return;
var models = await provider.GetTextModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
try
{
var models = await provider.GetTextModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
}
catch (Exception e)
{
this.Logger.LogError($"Failed to load models from provider '{this.DataLLMProvider}' (host={this.DataHost}, hostname='{this.DataHostname}'): {e.Message}");
this.dataLoadingModelsIssue = T("We are currently unable to communicate with the provider to load models. Please try again later.");
}
}
private string APIKeyText => this.DataLLMProvider switch

View File

@ -101,6 +101,12 @@
}
}
</MudStack>
@if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue))
{
<MudAlert Severity="Severity.Error" Class="mt-3">
@this.dataLoadingModelsIssue
</MudAlert>
}
</MudField>
@* ReSharper disable once CSharpWarnings::CS8974 *@

View File

@ -71,7 +71,10 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
private ILogger<TranscriptionProviderDialog> Logger { get; init; } = null!;
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
/// <summary>
@ -85,7 +88,8 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
private string dataManuallyModel = string.Empty;
private string dataAPIKeyStorageIssue = string.Empty;
private string dataEditingPreviousInstanceName = string.Empty;
private string dataLoadingModelsIssue = string.Empty;
// We get the form reference from Blazor code to validate it manually:
private MudForm form = null!;
@ -271,18 +275,27 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
private async Task ReloadModels()
{
this.dataLoadingModelsIssue = string.Empty;
var currentTranscriptionProviderSettings = this.CreateTranscriptionProviderSettings();
var provider = currentTranscriptionProviderSettings.CreateProvider();
if(provider is NoProvider)
if (provider is NoProvider)
return;
var models = await provider.GetTranscriptionModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
try
{
var models = await provider.GetTranscriptionModels(this.dataAPIKey);
// Order descending by ID means that the newest models probably come first:
var orderedModels = models.OrderByDescending(n => n.Id);
this.availableModels.Clear();
this.availableModels.AddRange(orderedModels);
}
catch (Exception e)
{
this.Logger.LogError($"Failed to load models from provider '{this.DataLLMProvider}' (host={this.DataHost}, hostname='{this.DataHostname}'): {e.Message}");;
this.dataLoadingModelsIssue = T("We are currently unable to communicate with the provider to load models. Please try again later.");
}
}
private string APIKeyText => this.DataLLMProvider switch

View File

@ -1,5 +1,6 @@
# v26.1.2, build 232 (2026-01-xx xx:xx UTC)
- Added the option to hide specific assistants by configuration plugins. This is useful for enterprise environments in organizations.
- Improved error handling for model loading in provider dialogs (LLMs, embeddings, transcriptions).
- Fixed a logging bug that prevented log events from being recorded in some cases.
- Fixed a bug that allowed adding a provider without selecting a model.
- Fixed a bug with local transcription providers by handling errors correctly when the local provider is unavailable.