Skip to content

Commit

Permalink
Add registration of IOpenAiClient as a dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
rodion-m committed Oct 20, 2023
1 parent 8a9a7da commit 350ae6f
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 15 deletions.
3 changes: 2 additions & 1 deletion samples/ChatGpt.BlazorExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
// make sure that you have added the OpenAICredentials:ApiKey to your secrets.json
// or environment variables
builder.Services.AddChatGptEntityFrameworkIntegration(
options => options.UseSqlite("Data Source=chats.db"));
options => options.UseSqlite("Data Source=chats.db"))
.AddServerSideBlazor();

var app = builder.Build();

Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>2.8.0</Version>
<Version>2.9.0</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
Expand Down
7 changes: 2 additions & 5 deletions src/OpenAI.ChatGpt.AspNetCore/ChatGPTFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ namespace OpenAI.ChatGpt.AspNetCore;
/// Factory for creating <see cref="ChatGPT" /> instances from DI.
/// </summary>
/// <example>
/// builder.Services.AddHttpClient&lt;ChatGPTFactory&lt;(client =>
/// {
/// client.DefaultRequestHeaders.Authorization = builder.Configuration["OpenAICredentials:ApiKey"];
/// })
/// builder.Services.AddHttpClient&lt;ChatGPTFactory&lt;("OpenAiClient")
/// .AddPolicyHandler(GetRetryPolicy())
/// .AddPolicyHandler(GetCircuitBreakerPolicy());
/// </example>
Expand Down Expand Up @@ -72,7 +69,7 @@ private OpenAiClient CreateOpenAiClient(
IHttpClientFactory httpClientFactory,
IOptions<OpenAICredentials> credentials)
{
var httpClient = httpClientFactory.CreateClient(nameof(ChatGPTFactory));
var httpClient = httpClientFactory.CreateClient(OpenAiClient.HttpClientName);
httpClient.DefaultRequestHeaders.Authorization = credentials.Value.GetAuthHeader();
httpClient.BaseAddress = new Uri(credentials.Value.ApiHost);
return new OpenAiClient(httpClient);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class ServiceCollectionExtensions
public static IServiceCollection AddChatGptInMemoryIntegration(
this IServiceCollection services,
bool injectInMemoryChatService = true,
bool injectOpenAiClient = true,
string credentialsConfigSectionPath = CredentialsConfigSectionPathDefault,
string completionsConfigSectionPath = ChatGPTConfigSectionPathDefault)
{
Expand All @@ -27,12 +28,17 @@ public static IServiceCollection AddChatGptInMemoryIntegration(
throw new ArgumentException("Value cannot be null or whitespace.",
nameof(completionsConfigSectionPath));
}
services.AddChatGptIntegrationCore(credentialsConfigSectionPath, completionsConfigSectionPath);
services.AddChatGptIntegrationCore(
credentialsConfigSectionPath,
completionsConfigSectionPath,
injectOpenAiClient: injectOpenAiClient
);
services.AddSingleton<IChatHistoryStorage, InMemoryChatHistoryStorage>();
if(injectInMemoryChatService)
{
services.AddScoped<ChatService>(CreateChatService);
}

return services;
}

Expand Down Expand Up @@ -62,7 +68,8 @@ public static IServiceCollection AddChatGptIntegrationCore(
this IServiceCollection services,
string credentialsConfigSectionPath = CredentialsConfigSectionPathDefault,
string completionsConfigSectionPath = ChatGPTConfigSectionPathDefault,
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped,
bool injectOpenAiClient = true
)
{
ArgumentNullException.ThrowIfNull(services);
Expand All @@ -86,12 +93,34 @@ public static IServiceCollection AddChatGptIntegrationCore(
.Configure(_ => { }) //optional
.ValidateDataAnnotations()
.ValidateOnStart();

services.AddHttpClient();

if (services.All(it => it.ServiceType != typeof(IHttpClientFactory)))
{
services.AddHttpClient(OpenAiClient.HttpClientName);
}

services.AddSingleton<ITimeProvider, TimeProviderUtc>();
services.Add(new ServiceDescriptor(typeof(ChatGPTFactory), typeof(ChatGPTFactory), serviceLifetime));

if (injectOpenAiClient)
{
AddOpenAiClient(services);
}

return services;
}

private static void AddOpenAiClient(IServiceCollection services)
{
services.AddSingleton<IOpenAiClient>(provider =>
{
var credentials = provider.GetRequiredService<IOptions<OpenAICredentials>>().Value;
var factory = provider.GetRequiredService<IHttpClientFactory>();
var httpClient = factory.CreateClient(OpenAiClient.HttpClientName);
httpClient.DefaultRequestHeaders.Authorization = credentials.GetAuthHeader();
httpClient.BaseAddress = new Uri(credentials.ApiHost);
var client = new OpenAiClient(httpClient);
return client;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public static IServiceCollection AddChatGptEntityFrameworkIntegration(
Action<DbContextOptionsBuilder> optionsAction,
string credentialsConfigSectionPath = CredentialsConfigSectionPathDefault,
string completionsConfigSectionPath = ChatGPTConfigSectionPathDefault,
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped,
bool injectOpenAiClient = true)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(optionsAction);
Expand All @@ -30,7 +31,7 @@ public static IServiceCollection AddChatGptEntityFrameworkIntegration(
}

services.AddChatGptIntegrationCore(
credentialsConfigSectionPath, completionsConfigSectionPath, serviceLifetime);
credentialsConfigSectionPath, completionsConfigSectionPath, serviceLifetime, injectOpenAiClient);
services.AddDbContext<ChatGptDbContext>(optionsAction, serviceLifetime);
switch (serviceLifetime)
{
Expand Down
1 change: 1 addition & 0 deletions src/OpenAI.ChatGpt/OpenAI.ChatGpt.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<ItemGroup>
<InternalsVisibleTo Include="OpenAI.ChatGpt.UnitTests" />
<InternalsVisibleTo Include="OpenAI.ChatGpt.IntegrationTests" />
<InternalsVisibleTo Include="OpenAI.ChatGpt.AspNetCore" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions src/OpenAI.ChatGpt/OpenAiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@
using OpenAI.ChatGpt.Exceptions;
using OpenAI.ChatGpt.Models.ChatCompletion;
using OpenAI.ChatGpt.Models.ChatCompletion.Messaging;
using OpenAI.ChatGpt.Models.Images;

namespace OpenAI.ChatGpt;

/// <summary> Thread-safe OpenAI client. </summary>
[Fody.ConfigureAwait(false)]
public class OpenAiClient : IOpenAiClient, IDisposable
{
internal const string HttpClientName = "OpenAiClient";
private const string DefaultHost = "https://api.openai.com/v1/";
private const string ImagesEndpoint = "images/generations";
private const string ChatCompletionsEndpoint = "chat/completions";

private static readonly Uri DefaultHostUri = new(DefaultHost);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public void AddChatGptCoreIntegration_added_expected_services()

provider.GetRequiredService<IHttpClientFactory>();
provider.GetRequiredService<ITimeProvider>();
provider.GetRequiredService<IOpenAiClient>();
}

[Fact]
Expand Down

0 comments on commit 350ae6f

Please sign in to comment.