mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-08 02:49:39 +00:00
Added provider icons (#934)
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
1 parent
afdcc0455d
commit
e78a0e61b9
74 files changed
+1018
-74
No files matched your search
@@ -1,2 +1,13 @@
|
||||
@inherits MSGComponentBase
|
||||
<ConfigurationSelect IsLocked="@this.IsLocked" OptionDescription="@T("Preselected provider")" Disabled="@(() => this.Disabled())" OptionHelp="@this.HelpText()" Data="@this.FilteredData()" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
|
||||
<ConfigurationSelect IsLocked="@this.IsLocked" OptionDescription="@T("Preselected provider")" Disabled="@(() => this.Disabled())" OptionHelp="@this.HelpText()" Data="@this.FilteredData()" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate">
|
||||
<ItemTemplate Context="providerData">
|
||||
@if (this.GetProvider(providerData.Value) is { } provider)
|
||||
{
|
||||
<ProviderLabel ProviderSettings="@provider" Text="@providerData.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@providerData.Name
|
||||
}
|
||||
</ItemTemplate>
|
||||
</ConfigurationSelect>
|
||||
@@ -32,7 +32,7 @@ public partial class ConfigurationProviderSelection : MSGComponentBase
|
||||
|
||||
[Parameter]
|
||||
public Func<bool> IsLocked { get; set; } = () => false;
|
||||
|
||||
|
||||
private IEnumerable<ConfigurationSelectData<string>> FilteredData()
|
||||
{
|
||||
if(this.Component is not Tools.Components.NONE and not Tools.Components.APP_SETTINGS)
|
||||
@@ -51,6 +51,15 @@ public partial class ConfigurationProviderSelection : MSGComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
private AIStudio.Settings.Provider? GetProvider(string providerId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(providerId))
|
||||
return null;
|
||||
|
||||
var provider = this.SettingsManager.GetProviderById(providerId);
|
||||
return provider == AIStudio.Settings.Provider.NONE ? null : provider;
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
|
||||
@@ -5,7 +5,14 @@
|
||||
@foreach (var data in this.Data)
|
||||
{
|
||||
<MudSelectItem Value="@data.Value">
|
||||
@data.Name
|
||||
@if (this.ItemTemplate is null)
|
||||
{
|
||||
@data.Name
|
||||
}
|
||||
else
|
||||
{
|
||||
@this.ItemTemplate(data)
|
||||
}
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudSelect>
|
||||
@@ -33,7 +33,13 @@ public partial class ConfigurationSelect<TConfig> : ConfigurationBaseCore
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TConfig, Task> SelectionUpdateAsync { get; set; } = _ => Task.CompletedTask;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Optional template used to render an item in the list.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<ConfigurationSelectData<TConfig>>? ItemTemplate { get; set; }
|
||||
|
||||
#region Overrides of ConfigurationBase
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -54,4 +60,4 @@ public partial class ConfigurationSelect<TConfig> : ConfigurationBaseCore
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<img src="@this.IconUrl" alt="" aria-hidden="true" draggable="false" class="@this.CssClass" style="@this.Style" />
|
||||
@@ -0,0 +1,59 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Shows the icon of a provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The icon is rendered as an image instead of inline SVG. That way the browser treats the icon as
|
||||
/// a standalone, script-less document, which matters for the custom icons a configuration plugin
|
||||
/// may supply.
|
||||
/// </remarks>
|
||||
public partial class ProviderIcon : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The configured provider whose icon should be shown. Takes precedence over ProviderType.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public AIStudio.Settings.Provider? ProviderSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The LLM provider whose icon should be shown when no ProviderSettings was given.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public LLMProviders ProviderType { get; set; } = LLMProviders.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// The validated custom icon supplied by a configuration plugin.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string CustomIconDataUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Additional CSS class for the icon.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Class { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Additional inline style for the icon.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Style { get; set; } = string.Empty;
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The provider-icon class carries the sizing from app.css. Callers add to it instead of
|
||||
/// replacing it, so an icon cannot lose its size by setting a class of its own.
|
||||
/// </summary>
|
||||
private string CssClass => $"provider-icon {this.Class}".TrimEnd();
|
||||
|
||||
private string IconUrl => this.ProviderSettings?.GetIconUrl(this.SettingsManager.IsDarkMode)
|
||||
?? this.ProviderType.GetIconUrl(this.SettingsManager.IsDarkMode, this.CustomIconDataUrl);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Wrap="Wrap.NoWrap">
|
||||
<ProviderIcon ProviderSettings="@this.ProviderSettings" ProviderType="@this.ProviderType" CustomIconDataUrl="@this.CustomIconDataUrl" />
|
||||
<MudText Class="@this.TextClass">@this.Text</MudText>
|
||||
</MudStack>
|
||||
@@ -0,0 +1,46 @@
|
||||
using AIStudio.Provider;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Shows a provider icon next to its name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Providers appear in select items, in table cells, and in group headers. All of them need the
|
||||
/// same icon and text pairing, so this component owns that layout once instead of repeating it at
|
||||
/// every call site.
|
||||
/// </remarks>
|
||||
public partial class ProviderLabel : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The configured provider whose icon should be shown. Takes precedence over ProviderType.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public AIStudio.Settings.Provider? ProviderSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The LLM provider whose icon should be shown when no ProviderSettings was given.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public LLMProviders ProviderType { get; set; } = LLMProviders.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// The validated custom icon supplied by a configuration plugin.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string CustomIconDataUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The text shown next to the icon.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Additional CSS class for the text.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string TextClass { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
@using AIStudio.Settings
|
||||
@inherits MSGComponentBase
|
||||
<MudSelect T="Provider" Value="@this.ProviderSettings" ValueChanged="@this.SelectionChanged" Validation="@this.ValidateProvider" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Apps" Margin="Margin.Dense" Label="@T("Provider")" Class="mb-3 rounded-lg" OuterClass="flex-grow-0" Variant="Variant.Outlined" Disabled="@this.Disabled">
|
||||
<MudSelect T="Provider" Value="@this.ProviderSettings" ValueChanged="@this.SelectionChanged" Validation="@this.ValidateProvider" Margin="Margin.Dense" Label="@T("Provider")" Class="mb-3 rounded-lg" OuterClass="flex-grow-0" Variant="Variant.Outlined" Disabled="@this.Disabled">
|
||||
@foreach (var providerItem in this.GetAvailableProviderSelectionItems())
|
||||
{
|
||||
<MudSelectItem Value="@providerItem.Provider">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="w-100" Wrap="Wrap.NoWrap">
|
||||
<MudText Class="me-2">@providerItem.Provider</MudText>
|
||||
<ProviderLabel ProviderSettings="@providerItem.Provider" Text="@providerItem.Provider.ToString()" TextClass="me-2" />
|
||||
@if (providerItem.CapabilityIcons.Count > 0)
|
||||
{
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Wrap="Wrap.NoWrap" Class="flex-grow-0">
|
||||
|
||||
@@ -105,12 +105,24 @@ public partial class ProviderSelection : MSGComponentBase
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
||||
this.StateHasChanged();
|
||||
{
|
||||
//
|
||||
// We hold a copy of the provider record, which is a snapshot taken when it was selected.
|
||||
// Once the user edits that provider, our copy is stale and would keep showing the old
|
||||
// name and the old icon, so we resolve it again and hand the fresh one to our parent:
|
||||
//
|
||||
var updatedProvider = this.SettingsManager.GetProviderById(this.ProviderSettings.Id);
|
||||
if (updatedProvider != AIStudio.Settings.Provider.NONE && updatedProvider != this.ProviderSettings)
|
||||
{
|
||||
this.ProviderSettings = updatedProvider;
|
||||
await this.ProviderSettingsChanged.InvokeAsync(updatedProvider);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
this.StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -118,4 +130,4 @@ public partial class ProviderSelection : MSGComponentBase
|
||||
private readonly record struct CapabilityIcon(string Icon, string Tooltip);
|
||||
|
||||
private readonly record struct ProviderSelectionItem(AIStudio.Settings.Provider Provider, IReadOnlyList<CapabilityIcon> CapabilityIcons);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,18 @@
|
||||
|
||||
@if (PreviewFeatures.PRE_SPEECH_TO_TEXT_2026.IsEnabled(this.SettingsManager))
|
||||
{
|
||||
<ConfigurationSelect OptionDescription="@T("Select a transcription provider")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider)" Data="@this.GetFilteredTranscriptionProviders()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider = selectedValue)" OptionHelp="@T("Select a transcription provider for transcribing your voice. Without a selected provider, dictation and transcription features will be disabled.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UseTranscriptionProvider, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Select a transcription provider")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider)" Data="@this.GetFilteredTranscriptionProviders()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider = selectedValue)" OptionHelp="@T("Select a transcription provider for transcribing your voice. Without a selected provider, dictation and transcription features will be disabled.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UseTranscriptionProvider, out var meta) && meta.IsLocked">
|
||||
<ItemTemplate Context="providerData">
|
||||
@if (this.GetTranscriptionProvider(providerData.Value) is { } provider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@provider.UsedLLMProvider" CustomIconDataUrl="@provider.CustomIconDataUrl" Text="@providerData.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@providerData.Name
|
||||
}
|
||||
</ItemTemplate>
|
||||
</ConfigurationSelect>
|
||||
<ConfigurationShortcut Data="@this.VoiceRecordingShortcut" OptionDescription="@T("Voice recording shortcut")" OptionHelp="@T("The global keyboard shortcut for toggling voice recording. This shortcut works system-wide, even when the app is not focused.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShortcutVoiceRecording, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,12 @@ public partial class SettingsPanelApp : SettingsPanelBase
|
||||
}
|
||||
}
|
||||
|
||||
private TranscriptionProvider? GetTranscriptionProvider(string providerId)
|
||||
{
|
||||
var provider = this.SettingsManager.GetTranscriptionProviderById(providerId);
|
||||
return provider == TranscriptionProvider.NONE ? null : provider;
|
||||
}
|
||||
|
||||
private void UpdatePreviewFeatures(PreviewVisibility previewVisibility)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.App.PreviewVisibility = previewVisibility;
|
||||
|
||||
@@ -30,11 +30,16 @@
|
||||
</HeaderContent>
|
||||
<GroupHeaderTemplate>
|
||||
<MudTh Class="provider-group-header" colspan="4">
|
||||
@context.Key
|
||||
@if (context.Key is LLMProviders llmProvider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@llmProvider" Text="@llmProvider.ToName()" />
|
||||
}
|
||||
</MudTh>
|
||||
</GroupHeaderTemplate>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>
|
||||
<ProviderLabel ProviderType="@context.UsedLLMProvider" CustomIconDataUrl="@context.CustomIconDataUrl" Text="@context.Name" />
|
||||
</MudTd>
|
||||
<MudTd>@this.GetEmbeddingProviderModelName(context)</MudTd>
|
||||
|
||||
<MudTd>
|
||||
|
||||
@@ -19,7 +19,7 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
|
||||
{
|
||||
Expandable = true,
|
||||
IsInitiallyExpanded = false,
|
||||
Selector = provider => provider.UsedLLMProvider.ToName(),
|
||||
Selector = provider => provider.UsedLLMProvider,
|
||||
};
|
||||
|
||||
[Parameter]
|
||||
@@ -82,6 +82,7 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
|
||||
{ x => x.DataId, embeddingProvider.Id },
|
||||
{ x => x.DataName, embeddingProvider.Name },
|
||||
{ x => x.DataLLMProvider, embeddingProvider.UsedLLMProvider },
|
||||
{ x => x.DataCustomIconDataUrl, embeddingProvider.CustomIconDataUrl },
|
||||
{ x => x.DataModel, embeddingProvider.Model },
|
||||
{ x => x.DataHostname, embeddingProvider.Hostname },
|
||||
{ x => x.IsSelfHosted, embeddingProvider.IsSelfHosted },
|
||||
|
||||
@@ -22,11 +22,16 @@
|
||||
</HeaderContent>
|
||||
<GroupHeaderTemplate>
|
||||
<MudTh Class="provider-group-header" colspan="4">
|
||||
@context.Key
|
||||
@if (context.Key is LLMProviders llmProvider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@llmProvider" Text="@llmProvider.ToName()" />
|
||||
}
|
||||
</MudTh>
|
||||
</GroupHeaderTemplate>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.InstanceName</MudTd>
|
||||
<MudTd>
|
||||
<ProviderLabel ProviderSettings="@context" Text="@context.InstanceName" />
|
||||
</MudTd>
|
||||
<MudTd>@this.GetLLMProviderModelName(context)</MudTd>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -20,7 +19,7 @@ public partial class SettingsPanelProviders : SettingsPanelProviderBase
|
||||
{
|
||||
Expandable = true,
|
||||
IsInitiallyExpanded = false,
|
||||
Selector = provider => provider.UsedLLMProvider.ToName(),
|
||||
Selector = provider => provider.UsedLLMProvider,
|
||||
};
|
||||
|
||||
[Parameter]
|
||||
@@ -77,6 +76,7 @@ public partial class SettingsPanelProviders : SettingsPanelProviderBase
|
||||
{ x => x.DataId, provider.Id },
|
||||
{ x => x.DataInstanceName, provider.InstanceName },
|
||||
{ x => x.DataLLMProvider, provider.UsedLLMProvider },
|
||||
{ x => x.DataCustomIconDataUrl, provider.CustomIconDataUrl },
|
||||
{ x => x.DataModel, provider.Model },
|
||||
{ x => x.DataHostname, provider.Hostname },
|
||||
{ x => x.IsSelfHosted, provider.IsSelfHosted },
|
||||
|
||||
@@ -26,11 +26,16 @@
|
||||
</HeaderContent>
|
||||
<GroupHeaderTemplate>
|
||||
<MudTh Class="provider-group-header" colspan="4">
|
||||
@context.Key
|
||||
@if (context.Key is LLMProviders llmProvider)
|
||||
{
|
||||
<ProviderLabel ProviderType="@llmProvider" Text="@llmProvider.ToName()" />
|
||||
}
|
||||
</MudTh>
|
||||
</GroupHeaderTemplate>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>
|
||||
<ProviderLabel ProviderType="@context.UsedLLMProvider" CustomIconDataUrl="@context.CustomIconDataUrl" Text="@context.Name" />
|
||||
</MudTd>
|
||||
<MudTd>@this.GetTranscriptionProviderModelName(context)</MudTd>
|
||||
|
||||
<MudTd>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -18,7 +17,7 @@ public partial class SettingsPanelTranscription : SettingsPanelProviderBase
|
||||
{
|
||||
Expandable = true,
|
||||
IsInitiallyExpanded = false,
|
||||
Selector = provider => provider.UsedLLMProvider.ToName(),
|
||||
Selector = provider => provider.UsedLLMProvider,
|
||||
};
|
||||
|
||||
[Parameter]
|
||||
@@ -81,6 +80,7 @@ public partial class SettingsPanelTranscription : SettingsPanelProviderBase
|
||||
{ x => x.DataId, transcriptionProvider.Id },
|
||||
{ x => x.DataName, transcriptionProvider.Name },
|
||||
{ x => x.DataLLMProvider, transcriptionProvider.UsedLLMProvider },
|
||||
{ x => x.DataCustomIconDataUrl, transcriptionProvider.CustomIconDataUrl },
|
||||
{ x => x.DataModel, transcriptionProvider.Model },
|
||||
{ x => x.DataHostname, transcriptionProvider.Hostname },
|
||||
{ x => x.IsSelfHosted, transcriptionProvider.IsSelfHosted },
|
||||
|
||||
Reference in new issue
Block a user