diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/BaseServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/BaseServiceConfig.cs deleted file mode 100644 index 04d31b3e5f65..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/BaseServiceConfig.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// Base service options definition. -/// -public abstract class BaseServiceConfig -{ - /// - /// Model name. - /// - public string? ModelId { get; init; } - - /// - /// Service Id. - /// - public string? ServiceId { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIAudioToTextServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIAudioToTextServiceConfig.cs deleted file mode 100644 index 453b146081c8..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIAudioToTextServiceConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized audio to text configuration -/// -public class OpenAIAudioToTextServiceConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIChatCompletionConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIChatCompletionConfig.cs deleted file mode 100644 index 58a59d1cef32..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIChatCompletionConfig.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized chat completion options. -/// -public class OpenAIChatCompletionConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; internal set; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientAudioToTextServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientAudioToTextServiceConfig.cs deleted file mode 100644 index b3672845a60d..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientAudioToTextServiceConfig.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized client audio to text configuration -/// -public class OpenAIClientAudioToTextServiceConfig : OpenAIAudioToTextServiceConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientChatCompletionConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientChatCompletionConfig.cs deleted file mode 100644 index c7ef22794393..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientChatCompletionConfig.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI client specialized chat completion options. -/// -/// Model name. -public class OpenAIClientChatCompletionConfig : OpenAIChatCompletionConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextEmbeddingGenerationConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextEmbeddingGenerationConfig.cs deleted file mode 100644 index 7bc1c092960e..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextEmbeddingGenerationConfig.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI client specialized chat completion options. -/// -public class OpenAIClientTextEmbeddingGenerationConfig : OpenAITextEmbeddingGenerationConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToAudioConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToAudioConfig.cs deleted file mode 100644 index 9b5e0303f4ec..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToAudioConfig.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized client audio to text configuration -/// -public class OpenAIClientTextToAudioConfig : OpenAITextToAudioServiceConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToImageServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToImageServiceConfig.cs deleted file mode 100644 index a11f195cd45f..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAIClientTextToImageServiceConfig.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized client audio to text configuration -/// -public class OpenAIClientTextToImageServiceConfig : OpenAITextToImageServiceConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextEmbeddingGenerationConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextEmbeddingGenerationConfig.cs deleted file mode 100644 index 0f3930c3aedd..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextEmbeddingGenerationConfig.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI client specialized chat completion options. -/// -public class OpenAITextEmbeddingGenerationConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; init; } - - /// - /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. - /// - public int? Dimensions { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToAudioServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToAudioServiceConfig.cs deleted file mode 100644 index 5b8f8f457db3..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToAudioServiceConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized audio to text configuration -/// -public class OpenAITextToAudioServiceConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToImageServiceConfig.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToImageServiceConfig.cs deleted file mode 100644 index 9a42280d65aa..000000000000 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Configuration/OpenAITextToImageServiceConfig.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Microsoft.Extensions.Logging; - -namespace Microsoft.SemanticKernel.Connectors.OpenAI; - -/// -/// OpenAI specialized client text to image configuration -/// -public class OpenAITextToImageServiceConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; init; } -} - -/// -/// OpenAI specialized client file service configuration -/// -public class OpenAIFileServiceConfig : BaseServiceConfig -{ - /// - /// The to use for logging. If null, no logging will be performed. - /// - public ILoggerFactory? LoggerFactory { get; init; } -} - -/// -/// OpenAI specializedd file service configuration -/// -public class OpenAIClientFileServiceConfig : OpenAIFileServiceConfig -{ - /// - /// OpenAI Organization Id (usually optional). - /// - public string? OrganizationId { get; init; } - - /// - /// OpenAI API Key. - /// - public string? ApiKey { get; init; } - - /// - /// A non-default OpenAI compatible API endpoint. - /// - public Uri? Endpoint { get; init; } - - /// - /// The API version to target. - /// - public string? Version { get; init; } -} diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Core/OpenAIClientCore.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Core/OpenAIClientCore.cs index 7afc6503492a..631afb3cdbe5 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Core/OpenAIClientCore.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Core/OpenAIClientCore.cs @@ -31,57 +31,29 @@ internal sealed class OpenAIClientCore : ClientCore /// /// Initializes a new instance of the class. /// - /// Client configuration + /// Model name. + /// OpenAI API Key. + /// OpenAI compatible API endpoint. + /// OpenAI Organization Id (usually optional). /// Custom for HTTP requests. - /// The to use for logging. If null, no logging will be performed. - internal OpenAIClientCore( - OpenAIClientAudioToTextServiceConfig config, - HttpClient? httpClient = null, - ILogger? logger = null) - : this(config.ModelId, config.OrganizationId, config.Endpoint, config.ApiKey, httpClient, logger) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Client configuration - /// Custom for HTTP requests. - /// The to use for logging. If null, no logging will be performed. - internal OpenAIClientCore( - OpenAIClientChatCompletionConfig config, - HttpClient? httpClient = null, - ILogger? logger = null) - : this(config.ModelId, config.OrganizationId, config.Endpoint, config.ApiKey, httpClient, logger) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Client configuration - /// Custom for HTTP requests. - /// The to use for logging. If null, no logging will be performed. + /// The to use for logging. If null, no logging will be performed. internal OpenAIClientCore( - OpenAIClientTextEmbeddingGenerationConfig config, + string modelId, + string? apiKey = null, + Uri? endpoint = null, + string? organization = null, HttpClient? httpClient = null, - ILogger? logger = null) - : this(config.ModelId, config.OrganizationId, config.Endpoint, config.ApiKey, httpClient, logger) - { - } - - private OpenAIClientCore(string? modelId, string? organizationId, Uri? endpoint, string? apiKey, HttpClient? httpClient, ILogger? logger = null) : base(logger) + ILogger? logger = null) : base(logger) { Verify.NotNullOrWhiteSpace(modelId); - Verify.NotNullOrWhiteSpace(apiKey); this.ModelName = modelId; var options = GetOpenAIClientOptions(httpClient); - if (!string.IsNullOrWhiteSpace(organizationId)) + if (!string.IsNullOrWhiteSpace(organization)) { - options.AddPolicy(new AddHeaderRequestPolicy("OpenAI-Organization", organizationId!), PipelinePosition.PerCall); + options.AddPolicy(new AddHeaderRequestPolicy("OpenAI-Organization", organization!), PipelinePosition.PerCall); } // Accepts the endpoint if provided, otherwise uses the default OpenAI endpoint. @@ -105,18 +77,18 @@ private OpenAIClientCore(string? modelId, string? organizationId, Uri? endpoint, /// Note: instances created this way might not have the default diagnostics settings, /// it's up to the caller to configure the client. /// - /// Client configuration + /// Azure OpenAI model ID or deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource /// Custom . /// The to use for logging. If null, no logging will be performed. internal OpenAIClientCore( - BaseServiceConfig config, + string modelId, OpenAIClient openAIClient, ILogger? logger = null) : base(logger) { - Verify.NotNullOrWhiteSpace(config.ModelId); + Verify.NotNullOrWhiteSpace(modelId); Verify.NotNull(openAIClient); - this.ModelName = config.ModelId; + this.ModelName = modelId; this.Client = openAIClient; } diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIKernelBuilderExtensions.cs index 1a527fa86494..6c2e7bd386f5 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIKernelBuilderExtensions.cs @@ -25,23 +25,36 @@ public static class OpenAIKernelBuilderExtensions /// /// Adds the OpenAI text embeddings service to the list. /// - /// The instance to augment. - /// Options for the OpenAI text embeddings service. - /// to use for the service. If null, one must be available in the service provider when this service is resolved. + /// The instance to augment. + /// OpenAI model name, see https://platform.openai.com/docs/models + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// A local identifier for the given AI service + /// The HttpClient to use with this service. + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. /// The same instance as . [Experimental("SKEXP0010")] public static IKernelBuilder AddOpenAITextEmbeddingGeneration( this IKernelBuilder builder, - OpenAITextEmbeddingGenerationConfig options, - OpenAIClient? openAIClient = null) + string modelId, + string apiKey, + string? orgId = null, + string? serviceId = null, + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(builder); - Verify.NotNullOrWhiteSpace(options.ModelId); + Verify.NotNullOrWhiteSpace(modelId); + Verify.NotNullOrWhiteSpace(apiKey); - builder.Services.AddKeyedSingleton(options.ServiceId, (serviceProvider, _) => + builder.Services.AddKeyedSingleton(serviceId, (serviceProvider, _) => new OpenAITextEmbeddingGenerationService( - options, - openAIClient ?? serviceProvider.GetRequiredService())); + modelId, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + serviceProvider.GetService(), + dimensions)); return builder; } @@ -49,24 +62,29 @@ public static IKernelBuilder AddOpenAITextEmbeddingGeneration( /// /// Adds the OpenAI text embeddings service to the list. /// - /// The instance to augment. - /// Options for the OpenAI text embeddings service. - /// The HttpClient to use with this service. + /// The instance to augment. + /// OpenAI model name, see https://platform.openai.com/docs/models + /// to use for the service. If null, one must be available in the service provider when this service is resolved. + /// A local identifier for the given AI service + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. /// The same instance as . [Experimental("SKEXP0010")] public static IKernelBuilder AddOpenAITextEmbeddingGeneration( this IKernelBuilder builder, - OpenAIClientTextEmbeddingGenerationConfig options, - HttpClient? httpClient = null) + string modelId, + OpenAIClient? openAIClient = null, + string? serviceId = null, + int? dimensions = null) { Verify.NotNull(builder); - Verify.NotNullOrWhiteSpace(options.ModelId); - Verify.NotNullOrWhiteSpace(options.ApiKey); + Verify.NotNullOrWhiteSpace(modelId); - builder.Services.AddKeyedSingleton(options.ServiceId, (serviceProvider, _) => + builder.Services.AddKeyedSingleton(serviceId, (serviceProvider, _) => new OpenAITextEmbeddingGenerationService( - options, - HttpClientProvider.GetHttpClient(httpClient, serviceProvider))); + modelId, + openAIClient ?? serviceProvider.GetRequiredService(), + serviceProvider.GetService(), + dimensions)); return builder; } @@ -78,24 +96,32 @@ public static IKernelBuilder AddOpenAITextEmbeddingGeneration( /// Adds the OpenAI chat completion service to the list. /// /// The instance to augment. - /// OpenAI chat completion configuration + /// OpenAI model name, see https://platform.openai.com/docs/models + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// A local identifier for the given AI service /// The HttpClient to use with this service. /// The same instance as . public static IKernelBuilder AddOpenAIChatCompletion( this IKernelBuilder builder, - OpenAIClientChatCompletionConfig config, + string modelId, + string apiKey, + string? orgId = null, + string? serviceId = null, HttpClient? httpClient = null) { Verify.NotNull(builder); - Verify.NotNullOrWhiteSpace(config.ModelId); - Verify.NotNullOrWhiteSpace(config.ApiKey); + Verify.NotNullOrWhiteSpace(modelId); + Verify.NotNullOrWhiteSpace(apiKey); + Func factory = (serviceProvider, _) => - { - config.LoggerFactory ??= serviceProvider.GetService(); - return new(config, HttpClientProvider.GetHttpClient(httpClient, serviceProvider)); - }; + new(modelId, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + serviceProvider.GetService()); - builder.Services.AddKeyedSingleton(config.ServiceId, factory); + builder.Services.AddKeyedSingleton(serviceId, factory); return builder; } @@ -104,21 +130,23 @@ public static IKernelBuilder AddOpenAIChatCompletion( /// Adds the OpenAI chat completion service to the list. /// /// The instance to augment. - /// OpenAI chat completion configuration + /// OpenAI model id /// to use for the service. If null, one must be available in the service provider when this service is resolved. + /// A local identifier for the given AI service /// The same instance as . public static IKernelBuilder AddOpenAIChatCompletion( this IKernelBuilder builder, - OpenAIChatCompletionConfig config, - OpenAIClient? openAIClient = null) + string modelId, + OpenAIClient? openAIClient = null, + string? serviceId = null) { Verify.NotNull(builder); - Verify.NotNullOrWhiteSpace(config.ModelId); + Verify.NotNullOrWhiteSpace(modelId); Func factory = (serviceProvider, _) => - new(config, openAIClient ?? serviceProvider.GetRequiredService()); + new(modelId, openAIClient ?? serviceProvider.GetRequiredService(), serviceProvider.GetService()); - builder.Services.AddKeyedSingleton(config.ServiceId, factory); + builder.Services.AddKeyedSingleton(serviceId, factory); return builder; } @@ -135,7 +163,6 @@ public static IKernelBuilder AddOpenAIChatCompletion( /// The HttpClient to use with this service. /// The same instance as . [Experimental("SKEXP0010")] - //[Obsolete("Use the configuration paramether overload of this method instead.")] public static IKernelBuilder AddOpenAIChatCompletion( this IKernelBuilder builder, string modelId, @@ -149,16 +176,12 @@ public static IKernelBuilder AddOpenAIChatCompletion( Verify.NotNullOrWhiteSpace(modelId); Func factory = (serviceProvider, _) => - new(new() - { - ModelId = modelId, - ServiceId = serviceId, - Endpoint = endpoint, - ApiKey = apiKey, - OrganizationId = orgId, - LoggerFactory = serviceProvider.GetService() - }, - httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider)); + new(modelId: modelId, + apiKey: apiKey, + endpoint: endpoint, + organization: orgId, + httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + loggerFactory: serviceProvider.GetService()); builder.Services.AddKeyedSingleton(serviceId, factory); @@ -167,23 +190,22 @@ public static IKernelBuilder AddOpenAIChatCompletion( #endregion #region Images - - /// /// Add the OpenAI Dall-E text to image service to the list /// /// The instance to augment. /// OpenAI API key, see https://platform.openai.com/account/api-keys /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// The model to use for image generation. /// A local identifier for the given AI service /// The HttpClient to use with this service. /// The same instance as . [Experimental("SKEXP0010")] - //[Obsolete("Use the configuration paramether overload of this method instead.")] public static IKernelBuilder AddOpenAITextToImage( this IKernelBuilder builder, string apiKey, string? orgId = null, + string? modelId = null, string? serviceId = null, HttpClient? httpClient = null) { @@ -191,17 +213,14 @@ public static IKernelBuilder AddOpenAITextToImage( Verify.NotNullOrWhiteSpace(apiKey); builder.Services.AddKeyedSingleton(serviceId, (serviceProvider, _) => - new OpenAITextToImageService(new() - { - ApiKey = apiKey, - OrganizationId = orgId, - ServiceId = serviceId, - LoggerFactory = serviceProvider.GetService() - }, - HttpClientProvider.GetHttpClient(httpClient, serviceProvider)); + new OpenAITextToImageService( + apiKey, + orgId, + modelId, + HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + serviceProvider.GetService())); return builder; } - #endregion } diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIServiceCollectionExtensions.cs index eae2a77aa79d..a30a6270d06d 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Extensions/OpenAIServiceCollectionExtensions.cs @@ -29,69 +29,92 @@ public static class OpenAIServiceCollectionExtensions /// Adds the OpenAI text embeddings service to the list. /// /// The instance to augment. - /// Options for the OpenAI text embeddings service. + /// OpenAI model name, see https://platform.openai.com/docs/models + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// A local identifier for the given AI service + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. /// The same instance as . [Experimental("SKEXP0010")] public static IServiceCollection AddOpenAITextEmbeddingGeneration( this IServiceCollection services, - OpenAIClientTextEmbeddingGenerationConfig options) + string modelId, + string apiKey, + string? orgId = null, + string? serviceId = null, + int? dimensions = null) { Verify.NotNull(services); - Verify.NotNullOrWhiteSpace(options.ModelId); - Verify.NotNullOrWhiteSpace(options.ApiKey); + Verify.NotNullOrWhiteSpace(modelId); + Verify.NotNullOrWhiteSpace(apiKey); - return services.AddKeyedSingleton(options.ServiceId, (serviceProvider, _) => + return services.AddKeyedSingleton(serviceId, (serviceProvider, _) => new OpenAITextEmbeddingGenerationService( - options, - HttpClientProvider.GetHttpClient(serviceProvider))); + modelId, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(serviceProvider), + serviceProvider.GetService(), + dimensions)); } /// /// Adds the OpenAI text embeddings service to the list. /// /// The instance to augment. - /// Options for the OpenAI text embeddings service. + /// The OpenAI model id. /// to use for the service. If null, one must be available in the service provider when this service is resolved. + /// A local identifier for the given AI service + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. /// The same instance as . [Experimental("SKEXP0010")] public static IServiceCollection AddOpenAITextEmbeddingGeneration(this IServiceCollection services, - OpenAITextEmbeddingGenerationConfig options, - OpenAIClient? openAIClient = null) + string modelId, + OpenAIClient? openAIClient = null, + string? serviceId = null, + int? dimensions = null) { Verify.NotNull(services); - Verify.NotNullOrWhiteSpace(options.ModelId); + Verify.NotNullOrWhiteSpace(modelId); - return services.AddKeyedSingleton(options.ServiceId, (serviceProvider, _) => + return services.AddKeyedSingleton(serviceId, (serviceProvider, _) => new OpenAITextEmbeddingGenerationService( - options, - openAIClient ?? serviceProvider.GetRequiredService())); + modelId, + openAIClient ?? serviceProvider.GetRequiredService(), + serviceProvider.GetService(), + dimensions)); } #endregion #region Chat Completion - - /// /// Adds the OpenAI chat completion service to the list. /// /// The instance to augment. - /// OpenAI chat completion configuration + /// OpenAI model name, see https://platform.openai.com/docs/models + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// A local identifier for the given AI service /// The same instance as . public static IServiceCollection AddOpenAIChatCompletion( this IServiceCollection services, - OpenAIClientChatCompletionConfig config) + string modelId, + string apiKey, + string? orgId = null, + string? serviceId = null) { Verify.NotNull(services); - Verify.NotNullOrWhiteSpace(config.ModelId); - Verify.NotNullOrWhiteSpace(config.ApiKey); + Verify.NotNullOrWhiteSpace(modelId); + Verify.NotNullOrWhiteSpace(apiKey); Func factory = (serviceProvider, _) => - { - config.LoggerFactory ??= serviceProvider.GetService(); - return new(config, HttpClientProvider.GetHttpClient(serviceProvider)); - }; + new(modelId, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(serviceProvider), + serviceProvider.GetService()); - services.AddKeyedSingleton(config.ServiceId, factory); + services.AddKeyedSingleton(serviceId, factory); return services; } @@ -100,20 +123,22 @@ public static IServiceCollection AddOpenAIChatCompletion( /// Adds the OpenAI chat completion service to the list. /// /// The instance to augment. - /// OpenAI chat completion configuration + /// OpenAI model id /// to use for the service. If null, one must be available in the service provider when this service is resolved. + /// A local identifier for the given AI service /// The same instance as . public static IServiceCollection AddOpenAIChatCompletion(this IServiceCollection services, - OpenAIChatCompletionConfig config, - OpenAIClient? openAIClient = null) + string modelId, + OpenAIClient? openAIClient = null, + string? serviceId = null) { Verify.NotNull(services); - Verify.NotNullOrWhiteSpace(config.ModelId); + Verify.NotNullOrWhiteSpace(modelId); Func factory = (serviceProvider, _) => - new(config, openAIClient ?? serviceProvider.GetRequiredService()); + new(modelId, openAIClient ?? serviceProvider.GetRequiredService(), serviceProvider.GetService()); - services.AddKeyedSingleton(config.ServiceId, factory); + services.AddKeyedSingleton(serviceId, factory); return services; } @@ -129,7 +154,6 @@ public static IServiceCollection AddOpenAIChatCompletion(this IServiceCollection /// A local identifier for the given AI service /// The same instance as . [Experimental("SKEXP0010")] - //[Obsolete("Use the configuration paramether overload of this method instead.")] public static IServiceCollection AddOpenAIChatCompletion( this IServiceCollection services, string modelId, @@ -142,15 +166,12 @@ public static IServiceCollection AddOpenAIChatCompletion( Verify.NotNullOrWhiteSpace(modelId); Func factory = (serviceProvider, _) => - new(new() - { - ModelId = modelId, - Endpoint = endpoint, - ApiKey = apiKey, - OrganizationId = orgId, - LoggerFactory = serviceProvider.GetService() - }, - HttpClientProvider.GetHttpClient(serviceProvider)); + new(modelId, + endpoint, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(serviceProvider), + serviceProvider.GetService()); services.AddKeyedSingleton(serviceId, factory); @@ -159,20 +180,20 @@ public static IServiceCollection AddOpenAIChatCompletion( #endregion #region Images - - /// /// Add the OpenAI Dall-E text to image service to the list /// /// The instance to augment. /// OpenAI API key, see https://platform.openai.com/account/api-keys /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// The model to use for image generation. /// A local identifier for the given AI service /// The same instance as . [Experimental("SKEXP0010")] public static IServiceCollection AddOpenAITextToImage(this IServiceCollection services, string apiKey, string? orgId = null, + string? modelId = null, string? serviceId = null) { Verify.NotNull(services); @@ -182,6 +203,7 @@ public static IServiceCollection AddOpenAITextToImage(this IServiceCollection se new OpenAITextToImageService( apiKey, orgId, + modelId, HttpClientProvider.GetHttpClient(serviceProvider), serviceProvider.GetService())); } diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/OpenAIMemoryBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/OpenAIMemoryBuilderExtensions.cs index 46141f124c81..2f6b94b8362d 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/OpenAIMemoryBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/OpenAIMemoryBuilderExtensions.cs @@ -17,18 +17,28 @@ public static class OpenAIMemoryBuilderExtensions /// See https://platform.openai.com/docs for service details. /// /// The instance - /// Options for the OpenAI text embeddings service. + /// OpenAI model name, see https://platform.openai.com/docs/models + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. /// Custom for HTTP requests. + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. /// Self instance [Experimental("SKEXP0010")] public static MemoryBuilder WithOpenAITextEmbeddingGeneration( this MemoryBuilder builder, - OpenAIClientTextEmbeddingGenerationConfig options, - HttpClient? httpClient = null) + string modelId, + string apiKey, + string? orgId = null, + HttpClient? httpClient = null, + int? dimensions = null) { return builder.WithTextEmbeddingGeneration((loggerFactory, builderHttpClient) => new OpenAITextEmbeddingGenerationService( - options, - HttpClientProvider.GetHttpClient(httpClient ?? builderHttpClient))); + modelId, + apiKey, + orgId, + HttpClientProvider.GetHttpClient(httpClient ?? builderHttpClient), + loggerFactory, + dimensions)); } } diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIAudioToTextService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIAudioToTextService.cs index 2fc8e3dd0316..71eb2ccc9a93 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIAudioToTextService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIAudioToTextService.cs @@ -27,30 +27,43 @@ public sealed class OpenAIAudioToTextService : IAudioToTextService /// /// Creates an instance of the with API key auth. /// - /// Service configuration + /// Model name + /// OpenAI API Key + /// OpenAI Organization Id (usually optional) /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAIAudioToTextService( - OpenAIClientAudioToTextServiceConfig config, - HttpClient? httpClient = null) + string modelId, + string apiKey, + string? organization = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null) { - this._core = new(config, httpClient: httpClient); + this._core = new( + modelId: modelId, + apiKey: apiKey, + organization: organization, + httpClient: httpClient, + logger: loggerFactory?.CreateLogger(typeof(OpenAIAudioToTextService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, config.ModelId); - this._core.AddAttribute(OpenAIClientCore.OrganizationKey, config.OrganizationId); + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); + this._core.AddAttribute(OpenAIClientCore.OrganizationKey, organization); } /// /// Creates an instance of the using the specified . /// - /// Service configuration + /// Model name /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAIAudioToTextService( - OpenAIAudioToTextServiceConfig config, - OpenAIClient openAIClient) + string modelId, + OpenAIClient openAIClient, + ILoggerFactory? loggerFactory = null) { - this._core = new(config, openAIClient); + this._core = new(modelId, openAIClient, loggerFactory?.CreateLogger(typeof(OpenAIAudioToTextService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, config.ModelId); + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); } /// diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIChatCompletionService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIChatCompletionService.cs index f53dd26be867..c22906e806f3 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIChatCompletionService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIChatCompletionService.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -21,34 +23,92 @@ public sealed class OpenAIChatCompletionService : IChatCompletionService /// /// Create an instance of the OpenAI chat completion connector /// - /// Service configuration + /// Model name + /// OpenAI API Key + /// OpenAI Organization Id (usually optional) /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAIChatCompletionService( - OpenAIClientChatCompletionConfig config, - HttpClient? httpClient = null) + string modelId, + string apiKey, + string? organization = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null +) { - this._core = new(config, httpClient); + this._core = new( + modelId, + apiKey, + endpoint: null, + organization, + httpClient, + loggerFactory?.CreateLogger(typeof(OpenAIChatCompletionService))); + + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); + this._core.AddAttribute(OpenAIClientCore.OrganizationKey, organization); + } + + /// + /// Create an instance of the Custom Message API OpenAI chat completion connector + /// + /// Model name + /// Custom Message API compatible endpoint + /// OpenAI API Key + /// OpenAI Organization Id (usually optional) + /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. + [Experimental("SKEXP0010")] + public OpenAIChatCompletionService( + string modelId, + Uri endpoint, + string? apiKey = null, + string? organization = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null) + { + Uri? internalClientEndpoint = null; + var providedEndpoint = endpoint ?? httpClient?.BaseAddress; + if (providedEndpoint is not null) + { + // If the provided endpoint does not have a path specified, updates it to the default Message API Chat Completions endpoint + internalClientEndpoint = providedEndpoint.PathAndQuery == "/" ? + new Uri(providedEndpoint, "v1/chat/completions") + : providedEndpoint; + } + + this._core = new( + modelId, + apiKey, + internalClientEndpoint, + organization, + httpClient, + loggerFactory?.CreateLogger(typeof(OpenAIChatCompletionService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, config.ModelId); - this._core.AddAttribute(OpenAIClientCore.OrganizationKey, config.OrganizationId); + if (providedEndpoint is not null) + { + this._core.AddAttribute(AIServiceExtensions.EndpointKey, providedEndpoint.ToString()); + } + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); + this._core.AddAttribute(OpenAIClientCore.OrganizationKey, organization); } /// /// Create an instance of the OpenAI chat completion connector /// - /// Service configuration + /// Model name /// Custom for HTTP requests. /// The to use for logging. If null, no logging will be performed. public OpenAIChatCompletionService( - OpenAIChatCompletionConfig config, - OpenAIClient openAIClient) + string modelId, + OpenAIClient openAIClient, + ILoggerFactory? loggerFactory = null) { this._core = new( - config, + modelId, openAIClient, - config.LoggerFactory?.CreateLogger(typeof(OpenAIChatCompletionService))); + loggerFactory?.CreateLogger(typeof(OpenAIChatCompletionService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, config.ModelId); + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); } /// diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIFileService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIFileService.cs index 7dded9af1238..09e85bf103aa 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIFileService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAIFileService.cs @@ -42,21 +42,28 @@ public sealed class OpenAIFileService /// /// Create an instance of the Azure OpenAI chat completion connector /// - /// Service configuration + /// Azure Endpoint URL + /// Azure OpenAI API Key + /// OpenAI Organization Id (usually optional) + /// The API version to target. /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAIFileService( - OpenAIClientFileServiceConfig config, - HttpClient? httpClient = null) + Uri endpoint, + string apiKey, + string? organization = null, + string? version = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null) { - Verify.NotNull(config.ApiKey, nameof(config.ApiKey)); - Verify.NotNull(config.Endpoint, nameof(config.Endpoint)); + Verify.NotNull(apiKey, nameof(apiKey)); - this._apiKey = config.ApiKey; - this._logger = config.LoggerFactory?.CreateLogger(typeof(OpenAIFileService)) ?? NullLogger.Instance; + this._apiKey = apiKey; + this._logger = loggerFactory?.CreateLogger(typeof(OpenAIFileService)) ?? NullLogger.Instance; this._httpClient = HttpClientProvider.GetHttpClient(httpClient); - this._serviceUri = new Uri(this._httpClient.BaseAddress ?? config.Endpoint, AzureOpenAIApiRouteFiles); - this._version = config.Version ?? AzureOpenAIDefaultVersion; - this._organization = config.OrganizationId; + this._serviceUri = new Uri(this._httpClient.BaseAddress ?? endpoint, AzureOpenAIApiRouteFiles); + this._version = version ?? AzureOpenAIDefaultVersion; + this._organization = organization; } /// diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextEmbeddingGenerationService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextEmbeddingGenerationService.cs index 555d44c13d69..a385b5aeb1da 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextEmbeddingGenerationService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextEmbeddingGenerationService.cs @@ -25,39 +25,49 @@ public sealed class OpenAITextEmbeddingGenerationService : ITextEmbeddingGenerat /// /// Create an instance of the OpenAI text embedding connector /// - /// Options for the Text Embedding Service. + /// Model name + /// OpenAI API Key + /// OpenAI Organization Id (usually optional) /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. public OpenAITextEmbeddingGenerationService( - OpenAIClientTextEmbeddingGenerationConfig options, - HttpClient? httpClient = null) + string modelId, + string apiKey, + string? organization = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null, + int? dimensions = null) { - Verify.NotNull(options.ModelId); - this._core = new( - options, + modelId: modelId, + apiKey: apiKey, + organization: organization, httpClient: httpClient, - logger: options.LoggerFactory?.CreateLogger(typeof(OpenAITextEmbeddingGenerationService))); + logger: loggerFactory?.CreateLogger(typeof(OpenAITextEmbeddingGenerationService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, options.ModelId); + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); - this._dimensions = options.Dimensions; + this._dimensions = dimensions; } /// /// Create an instance of the OpenAI text embedding connector /// - /// Options for the Text Embedding Service. + /// Model name /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. + /// The number of dimensions the resulting output embeddings should have. Only supported in "text-embedding-3" and later models. public OpenAITextEmbeddingGenerationService( - OpenAITextEmbeddingGenerationConfig options, - OpenAIClient openAIClient) + string modelId, + OpenAIClient openAIClient, + ILoggerFactory? loggerFactory = null, + int? dimensions = null) { - Verify.NotNull(options.ModelId); - - this._core = new(options, openAIClient, options.LoggerFactory?.CreateLogger(typeof(OpenAITextEmbeddingGenerationService))); - this._core.AddAttribute(AIServiceExtensions.ModelIdKey, options.ModelId); + this._core = new(modelId, openAIClient, loggerFactory?.CreateLogger(typeof(OpenAITextEmbeddingGenerationService))); + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); - this._dimensions = options.Dimensions; + this._dimensions = dimensions; } /// diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToAudioService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToAudioService.cs index 514fb6d709a2..177acf539a41 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToAudioService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToAudioService.cs @@ -33,19 +33,22 @@ public sealed class OpenAITextToAudioService : ITextToAudioService /// /// Creates an instance of the with API key auth. /// - /// Service configuration + /// Model name + /// OpenAI API Key + /// OpenAI Organization Id (usually optional) /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAITextToAudioService( - OpenAIClientTextToAudioConfig config, - HttpClient? httpClient = null) + string modelId, + string apiKey, + string? organization = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null) { - Verify.NotNull(config.ModelId); - Verify.NotNull(config.ApiKey); + this._client = new(modelId, apiKey, organization, httpClient, loggerFactory?.CreateLogger(typeof(OpenAITextToAudioService))); - this._client = new(config.ModelId!, config.ApiKey!, config.OrganizationId, httpClient, config.LoggerFactory?.CreateLogger(typeof(OpenAITextToAudioService))); - - this._client.AddAttribute(AIServiceExtensions.ModelIdKey, config.ModelId); - this._client.AddAttribute(OrganizationKey, config.OrganizationId); + this._client.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); + this._client.AddAttribute(OrganizationKey, organization); } /// diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs index 525bc67823f2..ad5a4f592fe3 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.SemanticKernel.Services; using Microsoft.SemanticKernel.TextToImage; namespace Microsoft.SemanticKernel.Connectors.OpenAI; @@ -35,21 +36,37 @@ public sealed class OpenAITextToImageService : ITextToImageService /// private readonly string _authorizationHeaderValue; + /// + /// The model to use for image generation. + /// + private readonly string? _modelId; + /// /// Initializes a new instance of the class. /// - /// Service configuration + /// OpenAI API key, see https://platform.openai.com/account/api-keys + /// OpenAI organization id. This is usually optional unless your account belongs to multiple organizations. + /// The model to use for image generation. /// Custom for HTTP requests. + /// The to use for logging. If null, no logging will be performed. public OpenAITextToImageService( - OpenAIClientTextToImageServiceConfig config, - HttpClient? httpClient = null) + string apiKey, + string? organization = null, + string? modelId = null, + HttpClient? httpClient = null, + ILoggerFactory? loggerFactory = null) { - Verify.NotNullOrWhiteSpace(config.ApiKey); - this._authorizationHeaderValue = $"Bearer {config.ApiKey}"; - this._organizationHeaderValue = config.OrganizationId; + Verify.NotNullOrWhiteSpace(apiKey); + this._authorizationHeaderValue = $"Bearer {apiKey}"; + this._organizationHeaderValue = organization; + this._modelId = modelId; - this._core = new(httpClient, config.LoggerFactory?.CreateLogger(this.GetType())); - this._core.AddAttribute(OpenAIClientCore.OrganizationKey, config.OrganizationId); + this._core = new(httpClient, loggerFactory?.CreateLogger(this.GetType())); + this._core.AddAttribute(OpenAIClientCore.OrganizationKey, organization); + if (modelId is not null) + { + this._core.AddAttribute(AIServiceExtensions.ModelIdKey, modelId); + } this._core.RequestCreated += (_, request) => {