diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor
index c8b827be..2becc03b 100644
--- a/app/MindWork AI Studio/Components/Pages/Settings.razor
+++ b/app/MindWork AI Studio/Components/Pages/Settings.razor
@@ -1,5 +1,6 @@
@page "/settings"
@using AIStudio.Provider
+@using Host = AIStudio.Provider.SelfHosted.Host
Settings
@@ -26,10 +27,18 @@
@context.InstanceName
@context.UsedProvider
- @if(context.UsedProvider is not Providers.SELF_HOSTED)
+ @if (context.UsedProvider is not Providers.SELF_HOSTED)
+ {
@context.Model
+ }
+ else if (context.UsedProvider is Providers.SELF_HOSTED && context.Host is not Host.LLAMACPP)
+ {
+ @context.Model
+ }
else
+ {
@("as selected by provider")
+ }
diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
index 63fb1051..7790d2e8 100644
--- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
+++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
@@ -33,7 +33,7 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide
// Prepare the OpenAI HTTP chat request:
var providerChatRequest = JsonSerializer.Serialize(new ChatRequest
{
- Model = (await this.GetTextModels(jsRuntime, settings, token: token)).First().Id,
+ Model = chatModel.Id,
// Build the messages:
// - First of all the system prompt
@@ -137,17 +137,33 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide
public async Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, string? apiKeyProvisional = null, CancellationToken token = default)
{
- var request = new HttpRequestMessage(HttpMethod.Get, "models");
- var response = await this.httpClient.SendAsync(request, token);
- if(!response.IsSuccessStatusCode)
- return [];
+ try
+ {
+ switch (provider.Host)
+ {
+ 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(token);
- if (modelResponse.Data.Length > 1)
- Console.WriteLine("Warning: multiple models found; using the first one.");
-
- var firstModel = modelResponse.Data.First();
- return [ new Provider.Model(firstModel.Id) ];
+ var lmStudioModelResponse = await lmStudioResponse.Content.ReadFromJsonAsync(token);
+ return lmStudioModelResponse.Data.Select(n => new Provider.Model(n.Id));
+ }
+
+ return [];
+ }
+ 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
diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor b/app/MindWork AI Studio/Settings/ProviderDialog.razor
index 3646764d..e83740e6 100644
--- a/app/MindWork AI Studio/Settings/ProviderDialog.razor
+++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor
@@ -51,8 +51,8 @@
- Load
-
+ Load
+
@foreach (var model in this.availableModels)
{
@model
diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs
index efcff584..edd00e91 100644
--- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs
+++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs
@@ -122,10 +122,11 @@ public partial class ProviderDialog : ComponentBase
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)
{
+ await this.ReloadModels();
await base.OnInitializedAsync();
return;
}
@@ -182,19 +183,21 @@ public partial class ProviderDialog : ComponentBase
// Use the data model to store the provider.
// We just return this data to the parent component:
var addedProviderSettings = this.CreateProviderSettings();
-
- // 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)
+ if (addedProviderSettings.UsedProvider != Providers.SELF_HOSTED)
{
- 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;
+ // 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.";
+ await this.form.Validate();
+ return;
+ }
}
-
+
this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
}
@@ -219,7 +222,7 @@ public partial class ProviderDialog : ComponentBase
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;
if (model == default)
@@ -319,11 +322,43 @@ public partial class ProviderDialog : ComponentBase
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 IsSelfHostedOrNone => this.DataProvider is Providers.SELF_HOSTED or Providers.NONE;
+
+ private bool IsNoneProvider => this.DataProvider is Providers.NONE;
private string GetProviderCreationURL() => this.DataProvider switch
{