mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 04:20:20 +00:00 
			
		
		
		
	Refactored provider validation
This commit is contained in:
		
							parent
							
								
									d65e9c5786
								
							
						
					
					
						commit
						e0b69ee655
					
				@ -6,7 +6,7 @@
 | 
				
			|||||||
        <MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
 | 
					        <MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
 | 
				
			||||||
            <MudStack Row="@true" AlignItems="AlignItems.Center">
 | 
					            <MudStack Row="@true" AlignItems="AlignItems.Center">
 | 
				
			||||||
                @* ReSharper disable once CSharpWarnings::CS8974 *@
 | 
					                @* ReSharper disable once CSharpWarnings::CS8974 *@
 | 
				
			||||||
                <MudSelect @bind-Value="@this.DataLLMProvider" Label="Provider" Class="mb-3" OpenIcon="@Icons.Material.Filled.AccountBalance" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingProvider">
 | 
					                <MudSelect @bind-Value="@this.DataLLMProvider" Label="Provider" Class="mb-3" OpenIcon="@Icons.Material.Filled.AccountBalance" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingProvider">
 | 
				
			||||||
                    @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders)))
 | 
					                    @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders)))
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        <MudSelectItem Value="@provider">@provider</MudSelectItem>
 | 
					                        <MudSelectItem Value="@provider">@provider</MudSelectItem>
 | 
				
			||||||
@ -26,7 +26,7 @@
 | 
				
			|||||||
                AdornmentIcon="@Icons.Material.Filled.VpnKey"
 | 
					                AdornmentIcon="@Icons.Material.Filled.VpnKey"
 | 
				
			||||||
                AdornmentColor="Color.Info"
 | 
					                AdornmentColor="Color.Info"
 | 
				
			||||||
                InputType="InputType.Password"
 | 
					                InputType="InputType.Password"
 | 
				
			||||||
                Validation="@this.ValidatingAPIKey"
 | 
					                Validation="@this.providerValidation.ValidatingAPIKey"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            <MudTextField
 | 
					            <MudTextField
 | 
				
			||||||
@ -38,11 +38,11 @@
 | 
				
			|||||||
                Adornment="Adornment.Start"
 | 
					                Adornment="Adornment.Start"
 | 
				
			||||||
                AdornmentIcon="@Icons.Material.Filled.Dns"
 | 
					                AdornmentIcon="@Icons.Material.Filled.Dns"
 | 
				
			||||||
                AdornmentColor="Color.Info"
 | 
					                AdornmentColor="Color.Info"
 | 
				
			||||||
                Validation="@this.ValidatingHostname"
 | 
					                Validation="@this.providerValidation.ValidatingHostname"
 | 
				
			||||||
                UserAttributes="@SPELLCHECK_ATTRIBUTES"
 | 
					                UserAttributes="@SPELLCHECK_ATTRIBUTES"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <MudSelect Disabled="@(!this.DataLLMProvider.IsHostNeeded())" @bind-Value="@this.DataHost" Label="Host" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingHost">
 | 
					            <MudSelect Disabled="@(!this.DataLLMProvider.IsHostNeeded())" @bind-Value="@this.DataHost" Label="Host" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingHost">
 | 
				
			||||||
                @foreach (Host host in Enum.GetValues(typeof(Host)))
 | 
					                @foreach (Host host in Enum.GetValues(typeof(Host)))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    <MudSelectItem Value="@host">@host.Name()</MudSelectItem>
 | 
					                    <MudSelectItem Value="@host">@host.Name()</MudSelectItem>
 | 
				
			||||||
@ -68,7 +68,7 @@
 | 
				
			|||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    <MudButton Disabled="@(!this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
 | 
					                    <MudButton Disabled="@(!this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
 | 
				
			||||||
                    <MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="Model" Class="mb-3" OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingModel">
 | 
					                    <MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="Model" Class="mb-3" OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingModel">
 | 
				
			||||||
                        @foreach (var model in this.availableModels)
 | 
					                        @foreach (var model in this.availableModels)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            <MudSelectItem Value="@model">@model</MudSelectItem>
 | 
					                            <MudSelectItem Value="@model">@model</MudSelectItem>
 | 
				
			||||||
@ -89,7 +89,7 @@
 | 
				
			|||||||
                Adornment="Adornment.Start"
 | 
					                Adornment="Adornment.Start"
 | 
				
			||||||
                AdornmentIcon="@Icons.Material.Filled.Lightbulb"
 | 
					                AdornmentIcon="@Icons.Material.Filled.Lightbulb"
 | 
				
			||||||
                AdornmentColor="Color.Info"
 | 
					                AdornmentColor="Color.Info"
 | 
				
			||||||
                Validation="@this.ValidatingInstanceName"
 | 
					                Validation="@this.providerValidation.ValidatingInstanceName"
 | 
				
			||||||
                UserAttributes="@SPELLCHECK_ATTRIBUTES"
 | 
					                UserAttributes="@SPELLCHECK_ATTRIBUTES"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
using AIStudio.Provider;
 | 
					using AIStudio.Provider;
 | 
				
			||||||
using AIStudio.Settings;
 | 
					using AIStudio.Settings;
 | 
				
			||||||
 | 
					using AIStudio.Tools.Validation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -98,6 +99,19 @@ public partial class ProviderDialog : ComponentBase, ISecretId
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    private readonly List<Model> availableModels = new();
 | 
					    private readonly List<Model> availableModels = new();
 | 
				
			||||||
    private readonly Encryption encryption = Program.ENCRYPTION;
 | 
					    private readonly Encryption encryption = Program.ENCRYPTION;
 | 
				
			||||||
 | 
					    private readonly ProviderValidation providerValidation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ProviderDialog()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.providerValidation = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GetProvider = () => this.DataLLMProvider,
 | 
				
			||||||
 | 
					            GetAPIKeyStorageIssue = () => this.dataAPIKeyStorageIssue,
 | 
				
			||||||
 | 
					            GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName,
 | 
				
			||||||
 | 
					            GetUsedInstanceNames = () => this.UsedInstanceNames,
 | 
				
			||||||
 | 
					            GetHost = () => this.DataHost,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Settings.Provider CreateProviderSettings()
 | 
					    private Settings.Provider CreateProviderSettings()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -212,25 +226,6 @@ public partial class ProviderDialog : ComponentBase, ISecretId
 | 
				
			|||||||
        this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
 | 
					        this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private string? ValidatingProvider(LLMProviders llmProvider)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (llmProvider == LLMProviders.NONE)
 | 
					 | 
				
			||||||
            return "Please select a provider.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private string? ValidatingHost(Host host)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(this.DataLLMProvider is not LLMProviders.SELF_HOSTED)
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (host == Host.NONE)
 | 
					 | 
				
			||||||
            return "Please select a host.";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private string? ValidateManuallyModel(string manuallyModel)
 | 
					    private string? ValidateManuallyModel(string manuallyModel)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (this.DataLLMProvider is LLMProviders.FIREWORKS && string.IsNullOrWhiteSpace(manuallyModel))
 | 
					        if (this.DataLLMProvider is LLMProviders.FIREWORKS && string.IsNullOrWhiteSpace(manuallyModel))
 | 
				
			||||||
@ -239,64 +234,6 @@ public partial class ProviderDialog : ComponentBase, ISecretId
 | 
				
			|||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private string? ValidatingModel(Model model)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(this.DataLLMProvider is LLMProviders.SELF_HOSTED && this.DataHost == Host.LLAMACPP)
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if (model == default)
 | 
					 | 
				
			||||||
            return "Please select a model.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private string? ValidatingInstanceName(string instanceName)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (string.IsNullOrWhiteSpace(instanceName))
 | 
					 | 
				
			||||||
            return "Please enter an instance name.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if (instanceName.Length > 40)
 | 
					 | 
				
			||||||
            return "The instance name must not exceed 40 characters.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        // The instance name must be unique:
 | 
					 | 
				
			||||||
        var lowerInstanceName = instanceName.ToLowerInvariant();
 | 
					 | 
				
			||||||
        if (lowerInstanceName != this.dataEditingPreviousInstanceName && this.UsedInstanceNames.Contains(lowerInstanceName))
 | 
					 | 
				
			||||||
            return "The instance name must be unique; the chosen name is already in use.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private string? ValidatingAPIKey(string apiKey)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(this.DataLLMProvider is LLMProviders.SELF_HOSTED)
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if(!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue))
 | 
					 | 
				
			||||||
            return this.dataAPIKeyStorageIssue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(string.IsNullOrWhiteSpace(apiKey))
 | 
					 | 
				
			||||||
            return "Please enter an API key.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private string? ValidatingHostname(string hostname)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(this.DataLLMProvider != LLMProviders.SELF_HOSTED)
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if(string.IsNullOrWhiteSpace(hostname))
 | 
					 | 
				
			||||||
            return "Please enter a hostname, e.g., http://localhost:1234";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if(!hostname.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) && !hostname.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
 | 
					 | 
				
			||||||
            return "The hostname must start with either http:// or https://";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!Uri.TryCreate(hostname, UriKind.Absolute, out _))
 | 
					 | 
				
			||||||
            return "The hostname is not a valid HTTP(S) URL.";
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void Cancel() => this.MudDialog.Cancel();
 | 
					    private void Cancel() => this.MudDialog.Cancel();
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private async Task ReloadModels()
 | 
					    private async Task ReloadModels()
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					using AIStudio.Provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Host = AIStudio.Provider.SelfHosted.Host;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace AIStudio.Tools.Validation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public sealed class ProviderValidation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public Func<LLMProviders> GetProvider { get; init; } = () => LLMProviders.NONE;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public Func<string> GetAPIKeyStorageIssue { get; init; } = () => string.Empty;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public Func<string> GetPreviousInstanceName { get; init; } = () => string.Empty;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public Func<IEnumerable<string>> GetUsedInstanceNames { get; init; } = () => [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Func<Host> GetHost { get; init; } = () => Host.NONE;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public string? ValidatingHostname(string hostname)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(this.GetProvider() != LLMProviders.SELF_HOSTED)
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if(string.IsNullOrWhiteSpace(hostname))
 | 
				
			||||||
 | 
					            return "Please enter a hostname, e.g., http://localhost:1234";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if(!hostname.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) && !hostname.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
 | 
				
			||||||
 | 
					            return "The hostname must start with either http:// or https://";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!Uri.TryCreate(hostname, UriKind.Absolute, out _))
 | 
				
			||||||
 | 
					            return "The hostname is not a valid HTTP(S) URL.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string? ValidatingAPIKey(string apiKey)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(this.GetProvider() is LLMProviders.SELF_HOSTED)
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var apiKeyStorageIssue = this.GetAPIKeyStorageIssue();
 | 
				
			||||||
 | 
					        if(!string.IsNullOrWhiteSpace(apiKeyStorageIssue))
 | 
				
			||||||
 | 
					            return apiKeyStorageIssue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(string.IsNullOrWhiteSpace(apiKey))
 | 
				
			||||||
 | 
					            return "Please enter an API key.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string? ValidatingInstanceName(string instanceName)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (string.IsNullOrWhiteSpace(instanceName))
 | 
				
			||||||
 | 
					            return "Please enter an instance name.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (instanceName.Length > 40)
 | 
				
			||||||
 | 
					            return "The instance name must not exceed 40 characters.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // The instance name must be unique:
 | 
				
			||||||
 | 
					        var lowerInstanceName = instanceName.ToLowerInvariant();
 | 
				
			||||||
 | 
					        if (lowerInstanceName != this.GetPreviousInstanceName() && this.GetUsedInstanceNames().Contains(lowerInstanceName))
 | 
				
			||||||
 | 
					            return "The instance name must be unique; the chosen name is already in use.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string? ValidatingModel(Model model)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(this.GetProvider() is LLMProviders.SELF_HOSTED && this.GetHost() == Host.LLAMACPP)
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (model == default)
 | 
				
			||||||
 | 
					            return "Please select a model.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string? ValidatingProvider(LLMProviders llmProvider)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (llmProvider == LLMProviders.NONE)
 | 
				
			||||||
 | 
					            return "Please select a provider.";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string? ValidatingHost(Host host)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(this.GetProvider() is not LLMProviders.SELF_HOSTED)
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (host == Host.NONE)
 | 
				
			||||||
 | 
					            return "Please select a host.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user