Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAI-DotNet 7.7.8 #293

Merged
merged 3 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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