diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor index aaf2cec7..db396281 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor @@ -101,6 +101,12 @@ } } + @if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue)) + { + + @this.dataLoadingModelsIssue + + } @* ReSharper disable once CSharpWarnings::CS8974 *@ diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs index 0e5df9b9..6ecf9910 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs @@ -71,7 +71,10 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId [Inject] private RustService RustService { get; init; } = null!; - + + [Inject] + private ILogger Logger { get; init; } = null!; + private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new(); /// @@ -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 diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor index b424202d..58ff5e5b 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor @@ -116,6 +116,12 @@ } } + @if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue)) + { + + @this.dataLoadingModelsIssue + + } @* ReSharper disable once CSharpWarnings::CS8974 *@ diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs index e4f1f27a..fdea809b 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs @@ -84,6 +84,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId [Inject] private RustService RustService { get; init; } = null!; + [Inject] + private ILogger Logger { get; init; } = null!; + private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new(); /// @@ -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 diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor index 0a2aa3bb..e8461b87 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor @@ -101,6 +101,12 @@ } } + @if (!string.IsNullOrWhiteSpace(this.dataLoadingModelsIssue)) + { + + @this.dataLoadingModelsIssue + + } @* ReSharper disable once CSharpWarnings::CS8974 *@ diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs index 83477dec..9664b305 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs @@ -71,7 +71,10 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId [Inject] private RustService RustService { get; init; } = null!; - + + [Inject] + private ILogger Logger { get; init; } = null!; + private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new(); /// @@ -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 diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md b/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md index cf7f7b7c..d6c034ea 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md @@ -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. \ No newline at end of file