Skip to content
Open
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
140 changes: 140 additions & 0 deletions DEPENDENCY_INJECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# OpenAI .NET Dependency Injection Extensions

This document demonstrates the new dependency injection features added to the OpenAI .NET library.

## Quick Start

### 1. Basic Registration

```csharp
using OpenAI.Extensions.DependencyInjection;

// Register individual clients
builder.Services.AddOpenAIChat("gpt-4o", "your-api-key");
builder.Services.AddOpenAIEmbeddings("text-embedding-3-small", "your-api-key");

// Register OpenAI client factory
builder.Services.AddOpenAI("your-api-key");
builder.Services.AddOpenAIChat("gpt-4o"); // Uses registered OpenAIClient
```

### 2. Configuration-Based Registration

**appsettings.json:**
```json
{
"OpenAI": {
"ApiKey": "your-api-key",
"DefaultChatModel": "gpt-4o",
"DefaultEmbeddingModel": "text-embedding-3-small",
"Endpoint": "https://api.openai.com/v1",
"OrganizationId": "your-org-id"
}
}
```

**Program.cs:**
```csharp
using OpenAI.Extensions.DependencyInjection;

// Configure from appsettings.json
builder.Services.AddOpenAIFromConfiguration(builder.Configuration);

// Add clients using default models from configuration
builder.Services.AddChatClientFromConfiguration();
builder.Services.AddEmbeddingClientFromConfiguration();

// Or add all common clients at once
builder.Services.AddAllOpenAIClientsFromConfiguration();
```

### 3. Controller Usage

```csharp
[ApiController]
[Route("api/[controller]")]
public class ChatController : ControllerBase
{
private readonly ChatClient _chatClient;
private readonly EmbeddingClient _embeddingClient;

public ChatController(ChatClient chatClient, EmbeddingClient embeddingClient)
{
_chatClient = chatClient;
_embeddingClient = embeddingClient;
}

[HttpPost("chat")]
public async Task<IActionResult> Chat([FromBody] string message)
{
var completion = await _chatClient.CompleteChatAsync(message);
return Ok(new { response = completion.Content[0].Text });
}

[HttpPost("embeddings")]
public async Task<IActionResult> GetEmbeddings([FromBody] string text)
{
var embedding = await _embeddingClient.GenerateEmbeddingAsync(text);
var vector = embedding.ToFloats();
return Ok(new { dimensions = vector.Length, vector = vector.ToArray() });
}
}
```

## Available Extension Methods

### Core Extensions (ServiceCollectionExtensions)

- **AddOpenAI()** - Register OpenAIClient factory
- Overloads: API key, ApiKeyCredential, configuration action
- **AddOpenAIChat()** - Register ChatClient
- Direct or via existing OpenAIClient
- **AddOpenAIEmbeddings()** - Register EmbeddingClient
- **AddOpenAIAudio()** - Register AudioClient
- **AddOpenAIImages()** - Register ImageClient
- **AddOpenAIModeration()** - Register ModerationClient

### Configuration Extensions (ServiceCollectionExtensionsAdvanced)

- **AddOpenAIFromConfiguration()** - Bind from IConfiguration
- **AddChatClientFromConfiguration()** - Add ChatClient from config
- **AddEmbeddingClientFromConfiguration()** - Add EmbeddingClient from config
- **AddAudioClientFromConfiguration()** - Add AudioClient from config
- **AddImageClientFromConfiguration()** - Add ImageClient from config
- **AddModerationClientFromConfiguration()** - Add ModerationClient from config
- **AddAllOpenAIClientsFromConfiguration()** - Add all clients from config

## Configuration Options (OpenAIServiceOptions)

Extends `OpenAIClientOptions` with:

- **ApiKey** - API key (falls back to OPENAI_API_KEY environment variable)
- **DefaultChatModel** - Default: "gpt-4o"
- **DefaultEmbeddingModel** - Default: "text-embedding-3-small"
- **DefaultAudioModel** - Default: "whisper-1"
- **DefaultImageModel** - Default: "dall-e-3"
- **DefaultModerationModel** - Default: "text-moderation-latest"

Plus all base options: Endpoint, OrganizationId, ProjectId, etc.

## Key Features

✅ **Thread-Safe Singleton Registration** - All clients registered as singletons for optimal performance
✅ **Configuration Binding** - Full support for IConfiguration and appsettings.json
✅ **Environment Variable Fallback** - Automatic fallback to OPENAI_API_KEY
✅ **Multiple Registration Patterns** - Direct, factory-based, and configuration-based
✅ **Comprehensive Error Handling** - Clear error messages for missing configuration
✅ **.NET Standard 2.0 Compatible** - Works with all .NET implementations
✅ **Fully Tested** - covering all scenarios
✅ **Backward Compatible** - No breaking changes to existing code

## Error Handling

The extension methods provide clear error messages for common configuration issues:

- Missing API keys
- Missing configuration sections
- Invalid model specifications
- Missing required services

All methods validate input parameters and throw appropriate exceptions with helpful messages.
80 changes: 79 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,82 @@ AudioClient whisperClient = client.GetAudioClient("whisper-1");

The OpenAI clients are **thread-safe** and can be safely registered as **singletons** in ASP.NET Core's Dependency Injection container. This maximizes resource efficiency and HTTP connection reuse.

> ** For detailed dependency injection documentation, see [DEPENDENCY_INJECTION.md](DEPENDENCY_INJECTION.md)**

### Using Extension Methods (Recommended)

The library provides convenient extension methods for `IServiceCollection` to simplify client registration:

```csharp
using OpenAI.Extensions.DependencyInjection;

// Register individual clients with API key
builder.Services.AddOpenAIChat("gpt-4o", "your-api-key");
builder.Services.AddOpenAIEmbeddings("text-embedding-3-small");

// Or register the main OpenAI client factory
builder.Services.AddOpenAI("your-api-key");
builder.Services.AddOpenAIChat("gpt-4o"); // Uses the registered OpenAIClient
```

### Configuration from appsettings.json

Configure OpenAI services using configuration files:

```json
{
"OpenAI": {
"ApiKey": "your-api-key",
"Endpoint": "https://api.openai.com/v1",
"DefaultChatModel": "gpt-4o",
"DefaultEmbeddingModel": "text-embedding-3-small",
"OrganizationId": "your-org-id"
}
}
```

```csharp
// Register services from configuration
builder.Services.AddOpenAIFromConfiguration(builder.Configuration);

// Add specific clients using default models from configuration
builder.Services.AddChatClientFromConfiguration();
builder.Services.AddEmbeddingClientFromConfiguration();

// Or add all common clients at once
builder.Services.AddAllOpenAIClientsFromConfiguration();
```

### Advanced Configuration

For more complex scenarios, you can use the configuration action overloads:

```csharp
builder.Services.AddOpenAI("your-api-key", options =>
{
options.Endpoint = new Uri("https://your-custom-endpoint.com");
options.OrganizationId = "your-org-id";
options.ProjectId = "your-project-id";
});
```

### Using Environment Variables

The extension methods automatically fall back to the `OPENAI_API_KEY` environment variable:

```csharp
// This will use the OPENAI_API_KEY environment variable
builder.Services.AddOpenAIChat("gpt-4o");

// Or configure from appsettings.json with environment variable fallback
builder.Services.AddOpenAIFromConfiguration(builder.Configuration);
```


### Manual Registration (Legacy)

You can still register clients manually if needed:

Register the `ChatClient` as a singleton in your `Program.cs`:

```csharp
Expand All @@ -157,7 +233,9 @@ builder.Services.AddSingleton<ChatClient>(serviceProvider =>
});
```

Then inject and use the client in your controllers or services:
### Injection and Usage

Once registered, inject and use the clients in your controllers or services:

```csharp
[ApiController]
Expand Down
38 changes: 38 additions & 0 deletions src/Custom/DependencyInjection/OpenAIServiceOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace OpenAI.Extensions.DependencyInjection;

/// <summary>
/// Configuration options for OpenAI client services when using dependency injection.
/// This extends the base OpenAIClientOptions with DI-specific settings.
/// </summary>
public class OpenAIServiceOptions : OpenAIClientOptions
{
/// <summary>
/// The OpenAI API key. If not provided, the OPENAI_API_KEY environment variable will be used.
/// </summary>
public string ApiKey { get; set; }

/// <summary>
/// The default chat model to use when registering ChatClient without specifying a model.
/// </summary>
public string DefaultChatModel { get; set; } = "gpt-4o";

/// <summary>
/// The default embedding model to use when registering EmbeddingClient without specifying a model.
/// </summary>
public string DefaultEmbeddingModel { get; set; } = "text-embedding-3-small";

/// <summary>
/// The default audio model to use when registering AudioClient without specifying a model.
/// </summary>
public string DefaultAudioModel { get; set; } = "whisper-1";

/// <summary>
/// The default image model to use when registering ImageClient without specifying a model.
/// </summary>
public string DefaultImageModel { get; set; } = "dall-e-3";

/// <summary>
/// The default moderation model to use when registering ModerationClient without specifying a model.
/// </summary>
public string DefaultModerationModel { get; set; } = "text-moderation-latest";
}
Loading