mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-04-28 11:39:48 +00:00
Allow selection of self-hosted models
This commit is contained in:
parent
8af8426f5d
commit
52caf96cf4
@ -1,5 +1,6 @@
|
|||||||
@page "/settings"
|
@page "/settings"
|
||||||
@using AIStudio.Provider
|
@using AIStudio.Provider
|
||||||
|
@using Host = AIStudio.Provider.SelfHosted.Host
|
||||||
|
|
||||||
<MudText Typo="Typo.h3" Class="mb-12">Settings</MudText>
|
<MudText Typo="Typo.h3" Class="mb-12">Settings</MudText>
|
||||||
|
|
||||||
@ -26,10 +27,18 @@
|
|||||||
<MudTd>@context.InstanceName</MudTd>
|
<MudTd>@context.InstanceName</MudTd>
|
||||||
<MudTd>@context.UsedProvider</MudTd>
|
<MudTd>@context.UsedProvider</MudTd>
|
||||||
<MudTd>
|
<MudTd>
|
||||||
@if(context.UsedProvider is not Providers.SELF_HOSTED)
|
@if (context.UsedProvider is not Providers.SELF_HOSTED)
|
||||||
|
{
|
||||||
@context.Model
|
@context.Model
|
||||||
|
}
|
||||||
|
else if (context.UsedProvider is Providers.SELF_HOSTED && context.Host is not Host.LLAMACPP)
|
||||||
|
{
|
||||||
|
@context.Model
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
@("as selected by provider")
|
@("as selected by provider")
|
||||||
|
}
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd Style="text-align: left;">
|
<MudTd Style="text-align: left;">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.OpenInBrowser" Class="ma-2" Href="@this.GetProviderDashboardURL(context.UsedProvider)" Target="_blank" Disabled="@(context.UsedProvider is Providers.NONE or Providers.SELF_HOSTED)">
|
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.OpenInBrowser" Class="ma-2" Href="@this.GetProviderDashboardURL(context.UsedProvider)" Target="_blank" Disabled="@(context.UsedProvider is Providers.NONE or Providers.SELF_HOSTED)">
|
||||||
|
@ -33,7 +33,7 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide
|
|||||||
// Prepare the OpenAI HTTP chat request:
|
// Prepare the OpenAI HTTP chat request:
|
||||||
var providerChatRequest = JsonSerializer.Serialize(new ChatRequest
|
var providerChatRequest = JsonSerializer.Serialize(new ChatRequest
|
||||||
{
|
{
|
||||||
Model = (await this.GetTextModels(jsRuntime, settings, token: token)).First().Id,
|
Model = chatModel.Id,
|
||||||
|
|
||||||
// Build the messages:
|
// Build the messages:
|
||||||
// - First of all the system prompt
|
// - First of all the system prompt
|
||||||
@ -137,17 +137,33 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide
|
|||||||
|
|
||||||
public async Task<IEnumerable<Provider.Model>> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, string? apiKeyProvisional = null, CancellationToken token = default)
|
public async Task<IEnumerable<Provider.Model>> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, string? apiKeyProvisional = null, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, "models");
|
try
|
||||||
var response = await this.httpClient.SendAsync(request, token);
|
{
|
||||||
if(!response.IsSuccessStatusCode)
|
switch (provider.Host)
|
||||||
return [];
|
{
|
||||||
|
case Host.LLAMACPP:
|
||||||
|
// Right now, llama.cpp only supports one model.
|
||||||
|
// There is no API to list the model(s).
|
||||||
|
return [ new Provider.Model("as configured by llama.cpp") ];
|
||||||
|
|
||||||
|
case Host.LM_STUDIO:
|
||||||
|
case Host.OLLAMA:
|
||||||
|
var lmStudioRequest = new HttpRequestMessage(HttpMethod.Get, "models");
|
||||||
|
var lmStudioResponse = await this.httpClient.SendAsync(lmStudioRequest, token);
|
||||||
|
if(!lmStudioResponse.IsSuccessStatusCode)
|
||||||
|
return [];
|
||||||
|
|
||||||
var modelResponse = await response.Content.ReadFromJsonAsync<ModelsResponse>(token);
|
var lmStudioModelResponse = await lmStudioResponse.Content.ReadFromJsonAsync<ModelsResponse>(token);
|
||||||
if (modelResponse.Data.Length > 1)
|
return lmStudioModelResponse.Data.Select(n => new Provider.Model(n.Id));
|
||||||
Console.WriteLine("Warning: multiple models found; using the first one.");
|
}
|
||||||
|
|
||||||
var firstModel = modelResponse.Data.First();
|
return [];
|
||||||
return [ new Provider.Model(firstModel.Id) ];
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to load text models from self-hosted provider: {e.Message}");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
@ -51,8 +51,8 @@
|
|||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
|
||||||
<MudStack Row="@true" AlignItems="AlignItems.Center">
|
<MudStack Row="@true" AlignItems="AlignItems.Center">
|
||||||
<MudButton Disabled="@(!this.CanLoadModels)" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
|
<MudButton Disabled="@(!this.CanLoadModels())" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
|
||||||
<MudSelect Disabled="@this.IsSelfHostedOrNone" @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.ValidatingModel">
|
||||||
@foreach (var model in this.availableModels)
|
@foreach (var model in this.availableModels)
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@model">@model</MudSelectItem>
|
<MudSelectItem Value="@model">@model</MudSelectItem>
|
||||||
|
@ -122,10 +122,11 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
this.dataEditingPreviousInstanceName = this.DataInstanceName.ToLowerInvariant();
|
this.dataEditingPreviousInstanceName = this.DataInstanceName.ToLowerInvariant();
|
||||||
|
|
||||||
//
|
//
|
||||||
// We cannot load the API key nor models for self-hosted providers:
|
// We cannot load the API key for self-hosted providers:
|
||||||
//
|
//
|
||||||
if (this.DataProvider is Providers.SELF_HOSTED)
|
if (this.DataProvider is Providers.SELF_HOSTED)
|
||||||
{
|
{
|
||||||
|
await this.ReloadModels();
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -182,19 +183,21 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
// Use the data model to store the provider.
|
// Use the data model to store the provider.
|
||||||
// We just return this data to the parent component:
|
// We just return this data to the parent component:
|
||||||
var addedProviderSettings = this.CreateProviderSettings();
|
var addedProviderSettings = this.CreateProviderSettings();
|
||||||
|
if (addedProviderSettings.UsedProvider != Providers.SELF_HOSTED)
|
||||||
// We need to instantiate the provider to store the API key:
|
|
||||||
var provider = addedProviderSettings.CreateProvider();
|
|
||||||
|
|
||||||
// Store the API key in the OS secure storage:
|
|
||||||
var storeResponse = await this.SettingsManager.SetAPIKey(this.JsRuntime, provider, this.dataAPIKey);
|
|
||||||
if (!storeResponse.Success)
|
|
||||||
{
|
{
|
||||||
this.dataAPIKeyStorageIssue = $"Failed to store the API key in the operating system. The message was: {storeResponse.Issue}. Please try again.";
|
// We need to instantiate the provider to store the API key:
|
||||||
await this.form.Validate();
|
var provider = addedProviderSettings.CreateProvider();
|
||||||
return;
|
|
||||||
|
// Store the API key in the OS secure storage:
|
||||||
|
var storeResponse = await this.SettingsManager.SetAPIKey(this.JsRuntime, provider, this.dataAPIKey);
|
||||||
|
if (!storeResponse.Success)
|
||||||
|
{
|
||||||
|
this.dataAPIKeyStorageIssue = $"Failed to store the API key in the operating system. The message was: {storeResponse.Issue}. Please try again.";
|
||||||
|
await this.form.Validate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
|
this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +222,7 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
|
|
||||||
private string? ValidatingModel(Model model)
|
private string? ValidatingModel(Model model)
|
||||||
{
|
{
|
||||||
if(this.DataProvider is Providers.SELF_HOSTED)
|
if(this.DataProvider is Providers.SELF_HOSTED && this.DataHost == Host.LLAMACPP)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (model == default)
|
if (model == default)
|
||||||
@ -319,11 +322,43 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
this.availableModels.AddRange(orderedModels);
|
this.availableModels.AddRange(orderedModels);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanLoadModels => !string.IsNullOrWhiteSpace(this.dataAPIKey) && this.DataProvider != Providers.NONE && this.DataProvider != Providers.SELF_HOSTED;
|
private bool CanLoadModels()
|
||||||
|
{
|
||||||
|
if (this.DataProvider is Providers.SELF_HOSTED)
|
||||||
|
{
|
||||||
|
switch (this.DataHost)
|
||||||
|
{
|
||||||
|
case Host.NONE:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Host.LLAMACPP:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Host.LM_STUDIO:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Host.OLLAMA:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.DataProvider is Providers.NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(this.dataAPIKey))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsCloudProvider => this.DataProvider is not Providers.SELF_HOSTED;
|
private bool IsCloudProvider => this.DataProvider is not Providers.SELF_HOSTED;
|
||||||
|
|
||||||
private bool IsSelfHostedOrNone => this.DataProvider is Providers.SELF_HOSTED or Providers.NONE;
|
private bool IsSelfHostedOrNone => this.DataProvider is Providers.SELF_HOSTED or Providers.NONE;
|
||||||
|
|
||||||
|
private bool IsNoneProvider => this.DataProvider is Providers.NONE;
|
||||||
|
|
||||||
private string GetProviderCreationURL() => this.DataProvider switch
|
private string GetProviderCreationURL() => this.DataProvider switch
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user