Skip to content

Commit

Permalink
OpenAI-DotNet 8.1.1 (#336)
Browse files Browse the repository at this point in the history
- Added overloads to Assistant streaming event callbacks to include
event name: Func<String, IServerSentEvent, Task>

# OpenAI-DotNet-Proxy 8.1.1

- Renamed OpenAIProxyStartup -> OpenAIProxy
  • Loading branch information
StephenHodgson authored Jun 30, 2024
1 parent 3fdd926 commit 1ed0c2a
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 175 deletions.
88 changes: 46 additions & 42 deletions OpenAI-DotNet-Proxy/OpenAI-DotNet-Proxy.csproj
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>false</ImplicitUsings>
<Nullable>disable</Nullable>
<SignAssembly>false</SignAssembly>
<Authors>Stephen Hodgson</Authors>
<Product>OpenAI-DotNet-Proxy</Product>
<Description>A simple Proxy API gateway for OpenAI-DotNet to make authenticated requests from a front end application without exposing your API keys.</Description>
<Copyright>2024</Copyright>
<PackageLicenseExpression>CC0-1.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/RageAgainstThePixel/OpenAI-DotNet</PackageProjectUrl>
<RepositoryUrl>https://github.com/RageAgainstThePixel/OpenAI-DotNet</RepositoryUrl>
<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.10</Version>
<Company>RageAgainstThePixel</Company>
<RootNamespace>OpenAI.Proxy</RootNamespace>
<PackageIcon>OpenAI-DotNet-Icon.png</PackageIcon>
<PackageReleaseNotes>Version 7.7.10
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>disable</Nullable>
<Title>OpenAI API Proxy</Title>
<Product>OpenAI-DotNet-Proxy</Product>
<PackageId>OpenAI-DotNet-Proxy</PackageId>
<RootNamespace>OpenAI.Proxy</RootNamespace>
<Authors>Stephen Hodgson</Authors>
<Company>RageAgainstThePixel</Company>
<Description>A simple Proxy API gateway for OpenAI-DotNet to make authenticated requests from a front end application without exposing your API keys.</Description>
<Copyright>2024</Copyright>
<PackageLicenseExpression>CC0-1.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/RageAgainstThePixel/OpenAI-DotNet</PackageProjectUrl>
<RepositoryUrl>https://github.com/RageAgainstThePixel/OpenAI-DotNet</RepositoryUrl>
<PackageTags>OpenAI, AI, ML, API, gpt, gpt-4, gpt-3.5-turbo, gpt-3, chatGPT, api-proxy, proxy, gateway</PackageTags>
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<PackageIcon>OpenAI-DotNet-Icon.png</PackageIcon>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<SignAssembly>false</SignAssembly>
<ImplicitUsings>false</ImplicitUsings>
<Version>8.1.1</Version>
<PackageReleaseNotes>
Version 8.1.1
- Renamed OpenAIProxyStartup to OpenAIProxy
Version 7.7.10
- Updated EndpointRouteBuilder with optional route prefix parameter
Version 7.7.9
- Slight refactor of OpenAIProxyStartup to remove duplicate code
Expand All @@ -28,26 +36,22 @@ Version 7.7.8
- Updated OpenAI-DotNet-Test-Proxy to use WebApplication implementation
Version 7.7.7
- Added ValidateAuthenticationAsync
</PackageReleaseNotes>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<IncludeSymbols>True</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenAI-DotNet\OpenAI-DotNet.csproj" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<None Include="..\OpenAI-DotNet\Assets\OpenAI-DotNet-Icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<None Update="Readme.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenAI-DotNet\OpenAI-DotNet.csproj" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<None Include="..\OpenAI-DotNet\Assets\OpenAI-DotNet-Icon.png">
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<None Update="Readme.md">
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>
114 changes: 114 additions & 0 deletions OpenAI-DotNet-Proxy/Proxy/OpenAIProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading.Tasks;

namespace OpenAI.Proxy
{
/// <summary>
/// Used in ASP.NET Core WebApps to start your own OpenAI web api proxy.
/// </summary>
public class OpenAIProxy
{
private OpenAIClient openAIClient;
private IAuthenticationFilter authenticationFilter;

/// <summary>
/// Configures the <see cref="OpenAIClient"/> and <see cref="IAuthenticationFilter"/> services.
/// </summary>
/// <param name="services">Services collection.</param>
public void ConfigureServices(IServiceCollection services)
=> SetupServices(services.BuildServiceProvider());

/// <summary>
/// Configures the <see cref="IApplicationBuilder"/> to handle requests and forward them to OpenAI API.
/// </summary>
/// <param name="app"><see cref="IApplicationBuilder"/>.</param>
/// <param name="env"><see cref="IWebHostEnvironment"/>.</param>
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

SetupServices(app.ApplicationServices);

app.UseHttpsRedirection();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/health", HealthEndpoint);
endpoints.MapOpenAIEndpoints(openAIClient, authenticationFilter);
});
}

/// <summary>
/// Creates a new <see cref="IHost"/> 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 IHost CreateDefaultHost<T>(string[] args, OpenAIClient openAIClient) where T : class, IAuthenticationFilter
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<OpenAIProxy>();
webBuilder.ConfigureKestrel(ConfigureKestrel);
})
.ConfigureServices(services =>
{
services.AddSingleton(openAIClient);
services.AddSingleton<IAuthenticationFilter, T>();
}).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(ConfigureKestrel);
builder.Services.AddSingleton(openAIClient);
builder.Services.AddSingleton<IAuthenticationFilter, T>();
var app = builder.Build();
var startup = new OpenAIProxy();
startup.Configure(app, app.Environment);
return app;
}

private static void ConfigureKestrel(KestrelServerOptions options)
{
options.AllowSynchronousIO = false;
options.Limits.MinRequestBodyDataRate = null;
options.Limits.MinResponseDataRate = null;
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(2);
}

private void SetupServices(IServiceProvider serviceProvider)
{
openAIClient ??= serviceProvider.GetRequiredService<OpenAIClient>();
authenticationFilter ??= serviceProvider.GetRequiredService<IAuthenticationFilter>();
}

private static async Task HealthEndpoint(HttpContext context)
{
// Respond with a 200 OK status code and a plain text message
context.Response.StatusCode = StatusCodes.Status200OK;
const string contentType = "text/plain";
context.Response.ContentType = contentType;
const string content = "OK";
await context.Response.WriteAsync(content);
}
}
}
104 changes: 10 additions & 94 deletions OpenAI-DotNet-Proxy/Proxy/OpenAIProxyStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,113 +2,29 @@

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading.Tasks;

namespace OpenAI.Proxy
{
/// <summary>
/// Used in ASP.NET Core WebApps to start your own OpenAI web api proxy.
/// </summary>
[Obsolete("Use OpenAIProxy")]
public class OpenAIProxyStartup
{
private OpenAIClient openAIClient;
private IAuthenticationFilter authenticationFilter;
private OpenAIProxy openAIProxy;

private OpenAIProxy OpenAIProxy => openAIProxy ??= new OpenAIProxy();

/// <summary>
/// Configures the <see cref="OpenAIClient"/> and <see cref="IAuthenticationFilter"/> services.
/// </summary>
/// <param name="services">Services collection.</param>
public void ConfigureServices(IServiceCollection services)
=> SetupServices(services.BuildServiceProvider());
=> OpenAIProxy.ConfigureServices(services);

/// <summary>
/// Configures the <see cref="IApplicationBuilder"/> to handle requests and forward them to OpenAI API.
/// </summary>
/// <param name="app"><see cref="IApplicationBuilder"/>.</param>
/// <param name="env"><see cref="IWebHostEnvironment"/>.</param>
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

SetupServices(app.ApplicationServices);

app.UseHttpsRedirection();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/health", HealthEndpoint);
endpoints.MapOpenAIEndpoints(openAIClient, authenticationFilter);
});
}

/// <summary>
/// Creates a new <see cref="IHost"/> 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 IHost CreateDefaultHost<T>(string[] args, OpenAIClient openAIClient) where T : class, IAuthenticationFilter
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<OpenAIProxyStartup>();
webBuilder.ConfigureKestrel(ConfigureKestrel);
})
.ConfigureServices(services =>
{
services.AddSingleton(openAIClient);
services.AddSingleton<IAuthenticationFilter, T>();
}).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(ConfigureKestrel);
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 void ConfigureKestrel(KestrelServerOptions options)
{
options.AllowSynchronousIO = false;
options.Limits.MinRequestBodyDataRate = null;
options.Limits.MinResponseDataRate = null;
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(2);
}
=> OpenAIProxy.Configure(app, env);

private void SetupServices(IServiceProvider serviceProvider)
{
openAIClient ??= serviceProvider.GetRequiredService<OpenAIClient>();
authenticationFilter ??= serviceProvider.GetRequiredService<IAuthenticationFilter>();
}
public static IHost CreateDefaultHost<T>(string[] args, OpenAIClient openAIClient)
where T : class, IAuthenticationFilter => OpenAIProxy.CreateDefaultHost<T>(args, openAIClient);

private static async Task HealthEndpoint(HttpContext context)
{
// Respond with a 200 OK status code and a plain text message
context.Response.StatusCode = StatusCodes.Status200OK;
const string contentType = "text/plain";
context.Response.ContentType = contentType;
const string content = "OK";
await context.Response.WriteAsync(content);
}
public static WebApplication CreateWebApplication<T>(string[] args, OpenAIClient openAIClient)
where T : class, IAuthenticationFilter => OpenAIProxy.CreateWebApplication<T>(args, openAIClient);
}
}
6 changes: 3 additions & 3 deletions OpenAI-DotNet-Proxy/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ This setup allows your front end application to securely communicate with your b

### Back End Example

In this example, we demonstrate how to set up and use `OpenAIProxyStartup` in a new ASP.NET Core web app. The proxy server will handle authentication and forward requests to the OpenAI API, ensuring that your API keys and other sensitive information remain secure.
In this example, we demonstrate how to set up and use `OpenAIProxy` in a new ASP.NET Core web app. The proxy server will handle authentication and forward requests to the OpenAI API, ensuring that your API keys and other sensitive information remain secure.

1. Create a new [ASP.NET Core minimal web API](https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0) project.
2. Add the OpenAI-DotNet nuget package to your project.
- 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.CreateWebApplication` method, passing your custom `AuthenticationFilter` as a type argument.
4. In `Program.cs`, create a new proxy web application by calling `OpenAIProxy.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 Down Expand Up @@ -87,7 +87,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);
OpenAIProxyStartup.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
OpenAIProxy.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion OpenAI-DotNet-Tests-Proxy/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static void Main(string[] args)
var auth = OpenAIAuthentication.LoadFromEnv();
var settings = new OpenAIClientSettings(/* your custom settings if using Azure OpenAI */);
using var openAIClient = new OpenAIClient(auth, settings);
OpenAIProxyStartup.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
OpenAIProxy.CreateWebApplication<AuthenticationFilter>(args, openAIClient).Run();
}
}
}
2 changes: 1 addition & 1 deletion OpenAI-DotNet-Tests/OpenAI-DotNet-Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<IsPackable>false</IsPackable>
<SignAssembly>false</SignAssembly>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
Expand Down
Loading

0 comments on commit 1ed0c2a

Please sign in to comment.