Skip to content

Commit

Permalink
OpenAI-DotNet 7.7.8 (#293)
Browse files Browse the repository at this point in the history
- Updated OpenAIClientSettings.ctr to allow for domain http protocol override (i.e. http://localhost:8080 or http://0.0.0.0:8080)
- Updated OpenAIClientSettings.BaseRequest public for easier access when implementing custom proxies.
- Updated OpenAIClientSettings.IsAzureDeployment public for easier access when implementing custom proxies.

## OpenAI-DotNet-Proxy 7.7.8
- Added OpenAIProxyStartup.CreateWebApplication to create modern WebApplication
- Updated OpenAI-DotNet-Test-Proxy to use WebApplication implementation
  • Loading branch information
StephenHodgson authored May 4, 2024
1 parent 5244be0 commit 5633315
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 25 deletions.
7 changes: 5 additions & 2 deletions OpenAI-DotNet-Proxy/OpenAI-DotNet-Proxy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
<PackageTags>OpenAI, AI, ML, API, gpt, gpt-4, gpt-3.5-turbo, gpt-3, chatGPT, api-proxy, proxy, gateway</PackageTags>
<Title>OpenAI API Proxy</Title>
<PackageId>OpenAI-DotNet-Proxy</PackageId>
<Version>7.7.7</Version>
<Version>7.7.8</Version>
<Company>RageAgainstThePixel</Company>
<RootNamespace>OpenAI.Proxy</RootNamespace>
<PackageIcon>OpenAI-DotNet-Icon.png</PackageIcon>
<PackageReleaseNotes>Version 7.7.7
<PackageReleaseNotes>Version 7.7.8
- Added OpenAIProxyStartup.CreateWebApplication to create modern WebApplication
- Updated OpenAI-DotNet-Test-Proxy to use WebApplication implementation
Version 7.7.7
- Added ValidateAuthenticationAsync
</PackageReleaseNotes>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
Expand Down
28 changes: 27 additions & 1 deletion OpenAI-DotNet-Proxy/Proxy/OpenAIProxyStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Linq;
using System.Net.Http;
using System.Security.Authentication;
using System.Text.Json;
using System.Threading.Tasks;
using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;

Expand Down Expand Up @@ -99,6 +100,31 @@ public static IHost CreateDefaultHost<T>(string[] args, OpenAIClient openAIClien
}).Build();
}

/// <summary>
/// Creates a new <see cref="WebApplication"/> that acts as a proxy web api for OpenAI.
/// </summary>
/// <typeparam name="T"><see cref="IAuthenticationFilter"/> type to use to validate your custom issued tokens.</typeparam>
/// <param name="args">Startup args.</param>
/// <param name="openAIClient"><see cref="OpenAIClient"/> with configured <see cref="OpenAIAuthentication"/> and <see cref="OpenAIClientSettings"/>.</param>
public static WebApplication CreateWebApplication<T>(string[] args, OpenAIClient openAIClient) where T : class, IAuthenticationFilter
{
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.AllowSynchronousIO = false;
options.Limits.MinRequestBodyDataRate = null;
options.Limits.MinResponseDataRate = null;
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(2);
});
builder.Services.AddSingleton(openAIClient);
builder.Services.AddSingleton<IAuthenticationFilter, T>();
var app = builder.Build();
var startup = new OpenAIProxyStartup();
startup.Configure(app, app.Environment);
return app;
}

private static async Task HealthEndpoint(HttpContext context)
{
// Respond with a 200 OK status code and a plain text message
Expand Down Expand Up @@ -167,7 +193,7 @@ private async Task HandleRequest(HttpContext httpContext, string endpoint)
catch (Exception e)
{
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
await httpContext.Response.WriteAsync(e.Message);
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(new { error = new { e.Message, e.StackTrace } }));
}
}

Expand Down
21 changes: 16 additions & 5 deletions OpenAI-DotNet-Proxy/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ In this example, we demonstrate how to set up and use `OpenAIProxyStartup` in a
- Powershell install: `Install-Package OpenAI-DotNet-Proxy`
- Manually editing .csproj: `<PackageReference Include="OpenAI-DotNet-Proxy" />`
3. Create a new class that inherits from `AbstractAuthenticationFilter` and override the `ValidateAuthentication` method. This will implement the `IAuthenticationFilter` that you will use to check user session token against your internal server.
4. In `Program.cs`, create a new proxy web application by calling `OpenAIProxyStartup.CreateDefaultHost` method, passing your custom `AuthenticationFilter` as a type argument.
4. In `Program.cs`, create a new proxy web application by calling `OpenAIProxyStartup.CreateWebApplication` method, passing your custom `AuthenticationFilter` as a type argument.
5. Create `OpenAIAuthentication` and `OpenAIClientSettings` as you would normally with your API keys, org id, or Azure settings.

```csharp
Expand All @@ -63,7 +63,19 @@ public partial class Program
{
// You will need to implement your own class to properly test
// custom issued tokens you've setup for your end users.
if (!request.Authorization.ToString().Contains(userToken))
if (!request.Authorization.ToString().Contains(TestUserToken))
{
throw new AuthenticationException("User is not authorized");
}
}

public override async Task ValidateAuthenticationAsync(IHeaderDictionary request)
{
await Task.CompletedTask; // remote resource call
// You will need to implement your own class to properly test
// custom issued tokens you've setup for your end users.
if (!request.Authorization.ToString().Contains(TestUserToken))
{
throw new AuthenticationException("User is not authorized");
}
Expand All @@ -74,9 +86,8 @@ public partial class Program
{
var auth = OpenAIAuthentication.LoadFromEnv();
var settings = new OpenAIClientSettings(/* your custom settings if using Azure OpenAI */);
var openAIClient = new OpenAIClient(auth, settings);
var proxy = OpenAIProxyStartup.CreateDefaultHost<AuthenticationFilter>(args, openAIClient);
proxy.Run();
using var openAIClient = new OpenAIClient(auth, settings);
OpenAIProxyStartup.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
}
}
```
Expand Down
7 changes: 2 additions & 5 deletions OpenAI-DotNet-Tests-Proxy/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using OpenAI.Proxy;
using System.Security.Authentication;
using System.Threading.Tasks;
Expand All @@ -16,7 +15,6 @@ public partial class Program
{
private const string TestUserToken = "aAbBcCdDeE123456789";

// ReSharper disable once ClassNeverInstantiated.Local
private class AuthenticationFilter : AbstractAuthenticationFilter
{
public override void ValidateAuthentication(IHeaderDictionary request)
Expand Down Expand Up @@ -46,9 +44,8 @@ public static void Main(string[] args)
{
var auth = OpenAIAuthentication.LoadFromEnv();
var settings = new OpenAIClientSettings(/* your custom settings if using Azure OpenAI */);
var openAIClient = new OpenAIClient(auth, settings);
var proxy = OpenAIProxyStartup.CreateDefaultHost<AuthenticationFilter>(args, openAIClient);
proxy.Run();
using var openAIClient = new OpenAIClient(auth, settings);
OpenAIProxyStartup.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
}
}
}
13 changes: 7 additions & 6 deletions OpenAI-DotNet/Authentication/OpenAIClientSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace OpenAI
/// </summary>
public sealed class OpenAIClientSettings
{
internal const string Https = "https://";
internal const string OpenAIDomain = "api.openai.com";
internal const string DefaultOpenAIApiVersion = "v1";
internal const string AzureOpenAIDomain = "openai.azure.com";
Expand All @@ -24,7 +25,7 @@ public OpenAIClientSettings()
ApiVersion = "v1";
DeploymentId = string.Empty;
BaseRequest = $"/{ApiVersion}/";
BaseRequestUrlFormat = $"https://{ResourceName}{BaseRequest}{{0}}";
BaseRequestUrlFormat = $"{Https}{ResourceName}{BaseRequest}{{0}}";
UseOAuthAuthentication = true;
}

Expand All @@ -51,11 +52,11 @@ public OpenAIClientSettings(string domain, string apiVersion = DefaultOpenAIApiV
apiVersion = DefaultOpenAIApiVersion;
}

ResourceName = domain;
ResourceName = domain.Contains("http") ? domain : $"{Https}{domain}";
ApiVersion = apiVersion;
DeploymentId = string.Empty;
BaseRequest = $"/{ApiVersion}/";
BaseRequestUrlFormat = $"https://{ResourceName}{BaseRequest}{{0}}";
BaseRequestUrlFormat = $"{ResourceName}{BaseRequest}{{0}}";
UseOAuthAuthentication = true;
}

Expand Down Expand Up @@ -97,7 +98,7 @@ public OpenAIClientSettings(string resourceName, string deploymentId, string api
DeploymentId = deploymentId;
ApiVersion = apiVersion;
BaseRequest = $"/openai/deployments/{DeploymentId}/";
BaseRequestUrlFormat = $"https://{ResourceName}.{AzureOpenAIDomain}{BaseRequest}{{0}}";
BaseRequestUrlFormat = $"{Https}{ResourceName}.{AzureOpenAIDomain}{BaseRequest}{{0}}";
defaultQueryParameters.Add("api-version", ApiVersion);
UseOAuthAuthentication = useActiveDirectoryAuthentication;
}
Expand All @@ -108,13 +109,13 @@ public OpenAIClientSettings(string resourceName, string deploymentId, string api

public string DeploymentId { get; }

internal string BaseRequest { get; }
public string BaseRequest { get; }

internal string BaseRequestUrlFormat { get; }

internal bool UseOAuthAuthentication { get; }

internal bool IsAzureDeployment => BaseRequestUrlFormat.Contains(AzureOpenAIDomain);
public bool IsAzureDeployment => BaseRequestUrlFormat.Contains(AzureOpenAIDomain);

private readonly Dictionary<string, string> defaultQueryParameters = new();

Expand Down
1 change: 0 additions & 1 deletion OpenAI-DotNet/Common/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ internal Function(string name, string description, MethodInfo method, object ins
MethodInfo = method;
Parameters = method.GenerateJsonSchema();
Instance = instance;

functionCache[Name] = this;
}

Expand Down
6 changes: 5 additions & 1 deletion OpenAI-DotNet/OpenAI-DotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ More context [on Roger Pincombe's blog](https://rogerpincombe.com/openai-dotnet-
<AssemblyOriginatorKeyFile>OpenAI-DotNet.pfx</AssemblyOriginatorKeyFile>
<IncludeSymbols>True</IncludeSymbols>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<Version>7.7.7</Version>
<Version>7.7.8</Version>
<PackageReleaseNotes>
Version 7.7.8
- Updated OpenAIClientSettings.ctr to allow for domain http protocol override (i.e. http://localhost:8080 or http://0.0.0.0:8080)
- Updated OpenAIClientSettings.BaseRequest public for easier access when implementing custom proxies.
- Updated OpenAIClientSettings.IsAzureDeployment public for easier access when implementing custom proxies.
Version 7.7.7
- Updated static models list
- Added gpt-4-turbo
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ In this example, we demonstrate how to set up and use `OpenAIProxyStartup` in a
- Powershell install: `Install-Package OpenAI-DotNet-Proxy`
- Manually editing .csproj: `<PackageReference Include="OpenAI-DotNet-Proxy" />`
3. Create a new class that inherits from `AbstractAuthenticationFilter` and override the `ValidateAuthentication` method. This will implement the `IAuthenticationFilter` that you will use to check user session token against your internal server.
4. In `Program.cs`, create a new proxy web application by calling `OpenAIProxyStartup.CreateDefaultHost` method, passing your custom `AuthenticationFilter` as a type argument.
4. In `Program.cs`, create a new proxy web application by calling `OpenAIProxyStartup.CreateWebApplication` method, passing your custom `AuthenticationFilter` as a type argument.
5. Create `OpenAIAuthentication` and `OpenAIClientSettings` as you would normally with your API keys, org id, or Azure settings.

```csharp
Expand All @@ -299,7 +299,19 @@ public partial class Program
{
// You will need to implement your own class to properly test
// custom issued tokens you've setup for your end users.
if (!request.Authorization.ToString().Contains(userToken))
if (!request.Authorization.ToString().Contains(TestUserToken))
{
throw new AuthenticationException("User is not authorized");
}
}

public override async Task ValidateAuthenticationAsync(IHeaderDictionary request)
{
await Task.CompletedTask; // remote resource call
// You will need to implement your own class to properly test
// custom issued tokens you've setup for your end users.
if (!request.Authorization.ToString().Contains(TestUserToken))
{
throw new AuthenticationException("User is not authorized");
}
Expand All @@ -311,8 +323,7 @@ public partial class Program
var auth = OpenAIAuthentication.LoadFromEnv();
var settings = new OpenAIClientSettings(/* your custom settings if using Azure OpenAI */);
using var openAIClient = new OpenAIClient(auth, settings);
var proxy = OpenAIProxyStartup.CreateDefaultHost<AuthenticationFilter>(args, openAIClient);
proxy.Run();
OpenAIProxyStartup.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
}
}
```
Expand Down

0 comments on commit 5633315

Please sign in to comment.