Skip to content

Commit 71f30cc

Browse files
committed
feat: support dependency injection
this is a breaking change, it is not backwards compatible closes OkGoDoIt#41
1 parent 945dd2a commit 71f30cc

File tree

6 files changed

+86
-64
lines changed

6 files changed

+86
-64
lines changed

OpenAI_API/APIAuthentication.cs

-28
Original file line numberDiff line numberDiff line change
@@ -157,34 +157,6 @@ public static APIAuthentication LoadFromPath(string directory = null, string fil
157157

158158
return new APIAuthentication(key, org);
159159
}
160-
161-
162-
/// <summary>
163-
/// Tests the api key against the OpenAI API, to ensure it is valid. This hits the models endpoint so should not be charged for usage.
164-
/// </summary>
165-
/// <returns><see langword="true"/> if the api key is valid, or <see langword="false"/> if empty or not accepted by the OpenAI API.</returns>
166-
public async Task<bool> ValidateAPIKey()
167-
{
168-
if (string.IsNullOrEmpty(ApiKey))
169-
return false;
170-
171-
var api = new OpenAIAPI(this);
172-
173-
List<Models.Model> results;
174-
175-
try
176-
{
177-
results = await api.Models.GetModelsAsync();
178-
}
179-
catch (Exception ex)
180-
{
181-
Debug.WriteLine(ex.ToString());
182-
return false;
183-
}
184-
185-
return (results.Count > 0);
186-
}
187-
188160
}
189161

190162
internal static class AuthHelpers

OpenAI_API/EndpointBase.cs

+6-11
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,19 @@ protected string Url
4848
}
4949
}
5050

51-
/// <summary>
52-
/// Gets an HTTPClient with the appropriate authorization and other headers set
53-
/// </summary>
51+
/// <summary>Configures an HttpClient with the appropriate authorization and other headers set</summary>
5452
/// <returns>The fully initialized HttpClient</returns>
5553
/// <exception cref="AuthenticationException">Thrown if there is no valid authentication. Please refer to <see href="https://github.com/OkGoDoIt/OpenAI-API-dotnet#authentication"/> for details.</exception>
56-
protected HttpClient GetClient()
54+
internal static HttpClient ConfigureClient(HttpClient client, APIAuthentication auth)
5755
{
58-
if (_Api.Auth?.ApiKey is null)
56+
if (auth?.ApiKey is null)
5957
{
6058
throw new AuthenticationException("You must provide API authentication. Please refer to https://github.com/OkGoDoIt/OpenAI-API-dotnet#authentication for details.");
6159
}
6260

63-
HttpClient client = new HttpClient();
64-
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _Api.Auth.ApiKey);
61+
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", auth.ApiKey);
6562
client.DefaultRequestHeaders.Add("User-Agent", Value);
66-
if (!string.IsNullOrEmpty(_Api.Auth.OpenAIOrganization)) client.DefaultRequestHeaders.Add("OpenAI-Organization", _Api.Auth.OpenAIOrganization);
63+
if (!string.IsNullOrEmpty(auth.OpenAIOrganization)) client.DefaultRequestHeaders.Add("OpenAI-Organization", auth.OpenAIOrganization);
6764

6865
return client;
6966
}
@@ -99,8 +96,6 @@ private async Task<HttpResponseMessage> HttpRequestRaw(string url = null, HttpMe
9996
if (verb == null)
10097
verb = HttpMethod.Get;
10198

102-
var client = GetClient();
103-
10499
HttpResponseMessage response = null;
105100
string resultAsString = null;
106101
HttpRequestMessage req = new HttpRequestMessage(verb, url);
@@ -118,7 +113,7 @@ private async Task<HttpResponseMessage> HttpRequestRaw(string url = null, HttpMe
118113
req.Content = stringContent;
119114
}
120115
}
121-
response = await client.SendAsync(req, streaming ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead);
116+
response = await this._Api.Client.SendAsync(req, streaming ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead);
122117

123118
if (response.IsSuccessStatusCode)
124119
{

OpenAI_API/IOpenAI.cs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#nullable enable
2+
namespace OpenAI_API;
3+
using OpenAI_API.Completions;
4+
using OpenAI_API.Embedding;
5+
using OpenAI_API.Files;
6+
using OpenAI_API.Models;
7+
8+
/// <summary>Entry point to the OpenAPI API, handling auth and allowing access to the various API endpoints</summary>
9+
public interface IOpenAI
10+
{
11+
/// <summary>Text generation is the core function of the API. You give the API a prompt, and it generates a completion. The way you “program” the API to do a task is by simply describing the task in plain english or providing a few written examples. This simple approach works for a wide range of use cases, including summarization, translation, grammar correction, question answering, chatbots, composing emails, and much more (see the prompt library for inspiration).</summary>
12+
public CompletionEndpoint Completions { get; }
13+
14+
/// <summary>The API lets you transform text into a vector (list) of floating point numbers. The distance between two vectors measures their relatedness. Small distances suggest high relatedness and large distances suggest low relatedness.</summary>
15+
public EmbeddingEndpoint Embeddings { get; }
16+
17+
/// <summary>The API endpoint for querying available Engines/models</summary>
18+
public ModelsEndpoint Models { get; }
19+
20+
/// <summary>The API lets you do operations with files. You can upload, delete or retrieve files. Files can be used for fine-tuning, search, etc.</summary>
21+
public FilesEndpoint Files { get; }
22+
}
23+

OpenAI_API/OpenAIAPI.cs

+19-21
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
1-
using OpenAI_API.Completions;
1+
using Microsoft.Extensions.Logging;
2+
using OpenAI_API.Completions;
23
using OpenAI_API.Embedding;
34
using OpenAI_API.Files;
45
using OpenAI_API.Models;
6+
using System.Net.Http;
57

68
namespace OpenAI_API
79
{
810
/// <summary>
911
/// Entry point to the OpenAPI API, handling auth and allowing access to the various API endpoints
1012
/// </summary>
11-
public class OpenAIAPI
12-
{
13+
public class OpenAIAPI: IOpenAI
14+
{
1315
/// <summary>
1416
/// Base url for OpenAI
1517
/// </summary>
1618
public string ApiUrlBase = "https://api.openai.com/v1/";
17-
18-
/// <summary>
19-
/// The API authentication information to use for API calls
20-
/// </summary>
21-
public APIAuthentication Auth { get; set; }
2219

23-
/// <summary>
24-
/// Creates a new entry point to the OpenAPI API, handling auth and allowing access to the various API endpoints
25-
/// </summary>
26-
/// <param name="apiKeys">The API authentication information to use for API calls, or <see langword="null"/> to attempt to use the <see cref="APIAuthentication.Default"/>, potentially loading from environment vars or from a config file.</param>
27-
public OpenAIAPI(APIAuthentication apiKeys = null)
20+
/// <summary>The HTTP client configured with the authentication headers.</summary>
21+
internal HttpClient Client { get; }
22+
23+
/// <summary>
24+
/// Creates a new entry point to the OpenAPI API, handling auth and allowing access to the various API endpoints
25+
/// </summary>
26+
/// <param name="httpClient">The HTTP client configured with the authentication headers.</param>
27+
public OpenAIAPI(
28+
HttpClient httpClient)
2829
{
29-
this.Auth = apiKeys.ThisOrDefault();
30-
Completions = new CompletionEndpoint(this);
31-
Models = new ModelsEndpoint(this);
32-
Files = new FilesEndpoint(this);
33-
Embeddings = new EmbeddingEndpoint(this);
30+
this.Client = httpClient;
31+
this.Completions = new CompletionEndpoint(this);
32+
this.Models = new ModelsEndpoint(this);
33+
this.Files = new FilesEndpoint(this);
34+
this.Embeddings = new EmbeddingEndpoint(this);
3435
}
3536

3637
/// <summary>
@@ -52,8 +53,5 @@ public OpenAIAPI(APIAuthentication apiKeys = null)
5253
/// The API lets you do operations with files. You can upload, delete or retrieve files. Files can be used for fine-tuning, search, etc.
5354
/// </summary>
5455
public FilesEndpoint Files { get; }
55-
56-
57-
5856
}
5957
}

OpenAI_API/OpenAIApiExtensions.cs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#nullable enable
2+
namespace Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Configuration;
4+
using OpenAI_API;
5+
6+
static class OpenAIApiExtensions
7+
{
8+
/// <summary>Register <see cref="IOpenAI"/> for DI services. Read configuration from appsettings <code>"openAI": { "key": "", "org": "" }</code></summary>
9+
/// <param name="services"></param>
10+
/// <param name="configuration"></param>
11+
/// <returns></returns>
12+
public static IServiceCollection AddOpenAIService(this IServiceCollection services, IConfiguration configuration)
13+
{
14+
var section = configuration.GetSection("openAI");
15+
if (!section.Exists()) return services;
16+
17+
string? key = section["key"];
18+
if (key is null) return services;
19+
20+
string? organisation = section["org"];
21+
return services.AddOpenAIService(new APIAuthentication(key, organisation));
22+
}
23+
24+
public static IServiceCollection AddOpenAIService(this IServiceCollection services, APIAuthentication auth)
25+
{
26+
services.AddHttpClient<IOpenAI, OpenAIAPI>(client =>
27+
EndpointBase.ConfigureClient(client, auth));
28+
29+
return services;
30+
}
31+
}

OpenAI_API/OpenAI_API.csproj

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netstandard2.0</TargetFramework>
5-
<LangVersion>8.0</LangVersion>
4+
<TargetFramework>net7.0</TargetFramework>
65
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
76
<Authors>OkGoDoIt (Roger Pincombe)</Authors>
87
<Product>OpenAI API</Product>
@@ -30,7 +29,8 @@
3029
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
3130

3231
<Deterministic>true</Deterministic>
33-
32+
<ImplicitUsings>enable</ImplicitUsings>
33+
<LangVersion>latest</LangVersion>
3434
</PropertyGroup>
3535

3636
<ItemGroup>
@@ -41,7 +41,10 @@
4141
</ItemGroup>
4242

4343
<ItemGroup>
44-
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.1.1" />
44+
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
45+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
46+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
47+
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
4548
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
4649
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
4750
</ItemGroup>

0 commit comments

Comments
 (0)