2024-12-03 14:24:40 +00:00
using System.Text.Json.Serialization ;
2024-04-19 19:25:44 +00:00
using AIStudio.Provider ;
2025-04-11 12:31:10 +00:00
using AIStudio.Provider.HuggingFace ;
2025-08-26 08:59:56 +00:00
using AIStudio.Tools.PluginSystem ;
using Lua ;
2024-07-16 08:28:13 +00:00
using Host = AIStudio . Provider . SelfHosted . Host ;
2024-04-19 19:25:44 +00:00
namespace AIStudio.Settings ;
2024-05-04 08:55:00 +00:00
/// <summary>
/// Data model for configured providers.
/// </summary>
2024-05-19 18:28:25 +00:00
/// <param name="Num">The provider's number.</param>
2024-05-04 08:55:00 +00:00
/// <param name="Id">The provider's ID.</param>
/// <param name="InstanceName">The provider's instance name. Useful for multiple instances of the same provider, e.g., to distinguish between different OpenAI API keys.</param>
2024-09-13 19:50:00 +00:00
/// <param name="UsedLLMProvider">The provider used.</param>
2024-07-03 18:31:04 +00:00
/// <param name="IsSelfHosted">Whether the provider is self-hosted.</param>
/// <param name="Hostname">The hostname of the provider. Useful for self-hosted providers.</param>
2024-05-19 14:10:37 +00:00
/// <param name="Model">The LLM model to use for chat.</param>
2025-08-26 08:59:56 +00:00
public sealed record Provider (
2024-07-16 08:28:13 +00:00
uint Num ,
string Id ,
string InstanceName ,
2024-09-13 19:50:00 +00:00
LLMProviders UsedLLMProvider ,
2024-07-16 08:28:13 +00:00
Model Model ,
bool IsSelfHosted = false ,
2025-06-01 19:14:21 +00:00
bool IsEnterpriseConfiguration = false ,
Guid EnterpriseConfigurationPluginId = default ,
2024-07-16 08:28:13 +00:00
string Hostname = "http://localhost:1234" ,
2025-04-11 12:31:10 +00:00
Host Host = Host . NONE ,
2025-11-13 17:13:16 +00:00
HFInferenceProvider HFInferenceProvider = HFInferenceProvider . NONE ,
string AdditionalJsonApiParameters = "" ) : ConfigurationBaseObject , ISecretId
2024-05-04 08:55:00 +00:00
{
2025-08-26 08:59:56 +00:00
private static readonly ILogger < Provider > LOGGER = Program . LOGGER_FACTORY . CreateLogger < Provider > ( ) ;
public static readonly Provider NONE = new ( ) ;
public Provider ( ) : this (
0 ,
Guid . Empty . ToString ( ) ,
string . Empty ,
LLMProviders . NONE ,
default ,
false ,
false ,
Guid . Empty )
{
}
2024-05-04 08:55:00 +00:00
#region Overrides of ValueType
/// <summary>
/// Returns a string that represents the current provider in a human-readable format.
/// We use this to display the provider in the chat UI.
/// </summary>
/// <returns>A string that represents the current provider in a human-readable format.</returns>
public override string ToString ( )
{
2024-07-03 18:31:04 +00:00
if ( this . IsSelfHosted )
2024-09-13 19:50:00 +00:00
return $"{this.InstanceName} ({this.UsedLLMProvider.ToName()}, {this.Host}, {this.Hostname}, {this.Model})" ;
2024-07-03 18:31:04 +00:00
2024-09-13 19:50:00 +00:00
return $"{this.InstanceName} ({this.UsedLLMProvider.ToName()}, {this.Model})" ;
2024-05-04 08:55:00 +00:00
}
#endregion
2024-12-03 14:24:40 +00:00
#region Implementation of ISecretId
/// <inheritdoc />
[JsonIgnore]
public string SecretId = > this . Id ;
/// <inheritdoc />
[JsonIgnore]
public string SecretName = > this . InstanceName ;
#endregion
2025-08-26 08:59:56 +00:00
#region Implementation of IConfigurationObject
public override string Name
{
get = > this . InstanceName ;
init = > this . InstanceName = value ;
}
#endregion
public static bool TryParseProviderTable ( int idx , LuaTable table , Guid configPluginId , out ConfigurationBaseObject provider )
{
provider = NONE ;
if ( ! table . TryGetValue ( "Id" , out var idValue ) | | ! idValue . TryRead < string > ( out var idText ) | | ! Guid . TryParse ( idText , out var id ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid ID. The ID must be a valid GUID." ) ;
return false ;
}
if ( ! table . TryGetValue ( "InstanceName" , out var instanceNameValue ) | | ! instanceNameValue . TryRead < string > ( out var instanceName ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid instance name." ) ;
return false ;
}
if ( ! table . TryGetValue ( "UsedLLMProvider" , out var usedLLMProviderValue ) | | ! usedLLMProviderValue . TryRead < string > ( out var usedLLMProviderText ) | | ! Enum . TryParse < LLMProviders > ( usedLLMProviderText , true , out var usedLLMProvider ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid LLM provider enum value." ) ;
return false ;
}
if ( ! table . TryGetValue ( "Host" , out var hostValue ) | | ! hostValue . TryRead < string > ( out var hostText ) | | ! Enum . TryParse < Host > ( hostText , true , out var host ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid host enum value." ) ;
return false ;
}
if ( ! table . TryGetValue ( "Hostname" , out var hostnameValue ) | | ! hostnameValue . TryRead < string > ( out var hostname ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid hostname." ) ;
return false ;
}
2026-02-05 08:05:23 +00:00
var hfInferenceProvider = HFInferenceProvider . NONE ;
if ( table . TryGetValue ( "HFInferenceProvider" , out var hfInferenceProviderValue ) & & hfInferenceProviderValue . TryRead < string > ( out var hfInferenceProviderText ) )
{
if ( ! Enum . TryParse < HFInferenceProvider > ( hfInferenceProviderText , true , out hfInferenceProvider ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid Hugging Face inference provider enum value." ) ;
hfInferenceProvider = HFInferenceProvider . NONE ;
}
}
2025-08-26 08:59:56 +00:00
if ( ! table . TryGetValue ( "Model" , out var modelValue ) | | ! modelValue . TryRead < LuaTable > ( out var modelTable ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid model table." ) ;
return false ;
}
if ( ! TryReadModelTable ( idx , modelTable , out var model ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid model configuration." ) ;
return false ;
}
2025-11-13 17:13:16 +00:00
if ( ! table . TryGetValue ( "AdditionalJsonApiParameters" , out var additionalJsonApiParametersValue ) | | ! additionalJsonApiParametersValue . TryRead < string > ( out var additionalJsonApiParameters ) )
{
2025-11-17 12:13:19 +00:00
// In this case, no reason exists to reject this provider, though.
2025-11-13 17:13:16 +00:00
LOGGER . LogWarning ( $"The configured provider {idx} does not contain valid additional JSON API parameters." ) ;
2025-11-17 12:13:19 +00:00
additionalJsonApiParameters = string . Empty ;
2025-11-13 17:13:16 +00:00
}
2025-08-26 08:59:56 +00:00
provider = new Provider
{
2026-02-01 13:50:19 +00:00
Num = 0 , // will be set later by the PluginConfigurationObject
2025-08-26 08:59:56 +00:00
Id = id . ToString ( ) ,
InstanceName = instanceName ,
UsedLLMProvider = usedLLMProvider ,
Model = model ,
IsSelfHosted = usedLLMProvider is LLMProviders . SELF_HOSTED ,
IsEnterpriseConfiguration = true ,
EnterpriseConfigurationPluginId = configPluginId ,
Hostname = hostname ,
2025-11-13 17:13:16 +00:00
Host = host ,
2026-02-05 08:05:23 +00:00
HFInferenceProvider = hfInferenceProvider ,
2025-11-13 17:13:16 +00:00
AdditionalJsonApiParameters = additionalJsonApiParameters ,
2025-08-26 08:59:56 +00:00
} ;
return true ;
}
private static bool TryReadModelTable ( int idx , LuaTable table , out Model model )
{
model = default ;
if ( ! table . TryGetValue ( "Id" , out var idValue ) | | ! idValue . TryRead < string > ( out var id ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid model ID." ) ;
return false ;
}
if ( ! table . TryGetValue ( "DisplayName" , out var displayNameValue ) | | ! displayNameValue . TryRead < string > ( out var displayName ) )
{
LOGGER . LogWarning ( $"The configured provider {idx} does not contain a valid model display name." ) ;
return false ;
}
model = new ( id , displayName ) ;
return true ;
}
2026-02-05 09:59:59 +00:00
public string ExportAsConfigurationSection ( )
{
var hfInferenceProviderLine = string . Empty ;
if ( this . HFInferenceProvider is not HFInferenceProvider . NONE )
{
hfInferenceProviderLine = $"" "
["HFInferenceProvider"] = "{this.HFInferenceProvider}" ,
"" ";
}
return $ $"" "
CONFIG [ "LLM_PROVIDERS" ] [ # CONFIG [ "LLM_PROVIDERS" ] + 1 ] = {
2026-02-05 10:10:34 +00:00
["Id"] = "{{LuaTools.EscapeLuaString(NormalizeId(this.Id))}}" ,
["InstanceName"] = "{{LuaTools.EscapeLuaString(this.InstanceName)}}" ,
["UsedLLMProvider"] = "{{this.UsedLLMProvider}}" ,
["Host"] = "{{this.Host}}" ,
["Hostname"] = "{{LuaTools.EscapeLuaString(this.Hostname)}}" ,
{ { hfInferenceProviderLine } }
["AdditionalJsonApiParameters"] = "{{LuaTools.EscapeLuaString(this.AdditionalJsonApiParameters)}}" ,
["Model"] = {
["Id"] = "{{LuaTools.EscapeLuaString(this.Model.Id)}}" ,
["DisplayName"] = "{{LuaTools.EscapeLuaString(this.Model.DisplayName ?? string.Empty)}}" ,
} ,
}
"" ";
2026-02-05 09:59:59 +00:00
}
private static string NormalizeId ( string? id )
{
if ( ! string . IsNullOrWhiteSpace ( id ) )
return id ;
return Guid . NewGuid ( ) . ToString ( ) ;
}
2026-02-05 08:05:23 +00:00
}