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 8.1.1 #336

Merged
merged 1 commit into from
Jun 30, 2024
Merged
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
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
@@ -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
@@ -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
@@ -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
@@ -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();
}
}
```
2 changes: 1 addition & 1 deletion OpenAI-DotNet-Tests-Proxy/Program.cs
Original file line number Diff line number Diff line change
@@ -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
@@ -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" />
Loading