Zaiets.OpenAI.Lite 1.0.0

dotnet add package Zaiets.OpenAI.Lite --version 1.0.0
                    
NuGet\Install-Package Zaiets.OpenAI.Lite -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zaiets.OpenAI.Lite" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zaiets.OpenAI.Lite" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Zaiets.OpenAI.Lite" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zaiets.OpenAI.Lite --version 1.0.0
                    
#r "nuget: Zaiets.OpenAI.Lite, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zaiets.OpenAI.Lite@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zaiets.OpenAI.Lite&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Zaiets.OpenAI.Lite&version=1.0.0
                    
Install as a Cake Tool

Zaiets.OpenAI.Lite

NuGet License: MIT

Minimal OpenAI API client for .NET 8 — GPT-4, embeddings, function calling, streaming, and multi-turn conversations without the overhead of heavy SDKs.

Author: Vladyslav Zaiets — CTO & Software Architect | sarmkadan.com


Installation

dotnet add package Zaiets.OpenAI.Lite

Quick Start

using Zaiets.OpenAI.Lite;

var client = new OpenAIClient("sk-...");

// Single question
string answer = await client.Chat.AskAsync("What is the capital of France?");
Console.WriteLine(answer); // Paris

Features

Feature API
Chat completions (GPT-4o, GPT-4, etc.) client.Chat.CompleteAsync(request)
Single-question shortcut client.Chat.AskAsync(message)
Server-Sent Events streaming client.Chat.StreamAsync(request)
JSON structured output client.Chat.AskJsonAsync<T>(message)
Multi-turn conversation new ConversationBuilder(client.Chat, systemPrompt)
Text embeddings client.Embeddings.EmbedAsync(text)
Batch embeddings client.Embeddings.EmbedBatchAsync(texts)
Semantic similarity search client.Embeddings.FindSimilarAsync(query, candidates)
Function / tool calling loop client.Chat.RunToolLoopAsync(request, toolbox)
Dependency injection services.AddOpenAILite(apiKey)
List available models client.ListModelsAsync()

Chat Completions

Simple request

var request = new ChatCompletionRequest
{
    Model = OpenAIModels.Gpt4o,
    Temperature = 0.7f,
    Messages =
    [
        new ChatMessage(ChatRole.System, "You are a concise assistant."),
        new ChatMessage(ChatRole.User, "Explain dependency injection in one sentence."),
    ],
};

var response = await client.Chat.CompleteAsync(request);
Console.WriteLine(response.Text);
Console.WriteLine($"Tokens used: {response.Usage?.TotalTokens}");

Fluent builder style

using Zaiets.OpenAI.Lite.Extensions;

var request = new ChatCompletionRequest { Model = OpenAIModels.Gpt4oMini }
    .WithSystem("You are a code reviewer.")
    .AddUserMessage("Review this method: public int Add(int a, int b) => a + b;")
    .WithTemperature(0.2f)
    .WithMaxTokens(512);

var response = await client.Chat.CompleteAsync(request);

Streaming

var request = new ChatCompletionRequest
{
    Model = OpenAIModels.Gpt4o,
    Messages = [new ChatMessage(ChatRole.User, "Write a short poem about .NET.")],
};

await foreach (var chunk in client.Chat.StreamAsync(request))
{
    Console.Write(chunk); // prints tokens as they arrive
}

JSON structured output

record CityInfo(string Capital, string Population, string Language);

var city = await client.Chat.AskJsonAsync<CityInfo>(
    "Return JSON with capital, population, and official language of Germany.",
    model: OpenAIModels.Gpt4oMini);

Console.WriteLine(city?.Capital); // Berlin

Multi-Turn Conversations

ConversationBuilder keeps message history and sends the full context on every turn:

var conv = new ConversationBuilder(client.Chat, "You are a helpful travel assistant.")
    .WithModel(OpenAIModels.Gpt4oMini)
    .WithTemperature(0.7f);

string r1 = await conv.SendAsync("I want to visit Japan. Best time of year?");
string r2 = await conv.SendAsync("What about visa requirements for EU citizens?");
string r3 = await conv.SendAsync("Give me a 7-day Tokyo itinerary.");

// Stream a turn
await foreach (var chunk in conv.StreamAsync("Translate 'thank you' to Japanese."))
    Console.Write(chunk);

// Reset to start a new topic (keeps system prompt)
conv.Reset();

Embeddings

// Single embedding
float[] vector = await client.Embeddings.EmbedAsync("Hello, world!");

// Cosine similarity
float similarity = EmbeddingsClient.CosineSimilarity(vectorA, vectorB);
// 1.0 = identical meaning, 0.0 = unrelated

// Semantic search
var results = await client.Embeddings.FindSimilarAsync(
    query: "How do I handle errors in C#?",
    candidates: new[]
    {
        "Exception handling with try/catch",
        "Sorting algorithms in C#",
        "Using ILogger for structured logging",
        "Result pattern for error handling",
    },
    topK: 2);

foreach (var (text, score) in results)
    Console.WriteLine($"{score:F3}  {text}");

Function Calling

Build a FunctionToolbox, register handlers, then let the model call them:

var toolbox = new FunctionToolbox()
    .Register(
        name: "get_weather",
        description: "Returns current weather for a city.",
        parameters: ParameterSchemaBuilder.Create()
            .AddString("city", "The city name")
            .AddString("unit", "Temperature unit", required: false, enumValues: ["celsius", "fahrenheit"])
            .Build(),
        handler: (args, ct) =>
        {
            // parse args and call your real weather API here
            using var doc = JsonDocument.Parse(args);
            var city = doc.RootElement.GetProperty("city").GetString();
            return Task.FromResult($"{{\"city\":\"{city}\",\"temp\":22,\"condition\":\"sunny\"}}");
        })
    .Register(
        name: "search_web",
        description: "Search the web for recent information.",
        parameters: ParameterSchemaBuilder.Create()
            .AddString("query", "The search query")
            .Build(),
        handler: (args, ct) => Task.FromResult("{\"results\": [\"result1\", \"result2\"]}"));

var request = new ChatCompletionRequest
{
    Model = OpenAIModels.Gpt4oMini,
    Messages = [new ChatMessage(ChatRole.User, "What's the weather like in Kyiv right now?")],
};

// Automatically loops: model calls tool → result appended → model replies
var finalResponse = await client.Chat.RunToolLoopAsync(request, toolbox, maxIterations: 5);
Console.WriteLine(finalResponse.Text);

Dependency Injection (ASP.NET Core)

// Program.cs
builder.Services.AddOpenAILite(
    apiKey: builder.Configuration["OpenAI:ApiKey"]!,
    options =>
    {
        options.Timeout = TimeSpan.FromMinutes(2);
        options.OrganizationId = builder.Configuration["OpenAI:OrgId"];
    });

// In your service / controller
public class MyService(OpenAIClient openAI)
{
    public async Task<string> SummarizeAsync(string text)
        => await openAI.Chat.AskAsync($"Summarize: {text}", OpenAIModels.Gpt4oMini);
}

Custom Base URL (Azure, Ollama, vLLM)

// Azure OpenAI
var azureOptions = new OpenAIClientOptions
{
    BaseUrl = "https://my-resource.openai.azure.com/openai/deployments/my-deployment/",
};
var azureClient = new OpenAIClient(apiKey: Environment.GetEnvironmentVariable("AZURE_OAI_KEY")!, azureOptions);

// Local Ollama
var ollamaOptions = new OpenAIClientOptions { BaseUrl = "http://localhost:11434/v1/" };
var ollamaClient = new OpenAIClient(apiKey: "ollama", ollamaOptions);
string reply = await ollamaClient.Chat.AskAsync("Hello!", model: "llama3.2");

Model Constants

OpenAIModels.Gpt4o            // gpt-4o
OpenAIModels.Gpt4oMini        // gpt-4o-mini  (default, cheapest capable model)
OpenAIModels.Gpt4Turbo        // gpt-4-turbo
OpenAIModels.O1               // o1 reasoning
OpenAIModels.O3Mini           // o3-mini reasoning
OpenAIModels.TextEmbedding3Small  // text-embedding-3-small (1536 dims)
OpenAIModels.TextEmbedding3Large  // text-embedding-3-large (3072 dims)

Error Handling

using Zaiets.OpenAI.Lite.Exceptions;

try
{
    var answer = await client.Chat.AskAsync("Hello");
}
catch (OpenAIAuthException)      { /* invalid API key */ }
catch (OpenAIRateLimitException) { /* 429 - back off and retry */ }
catch (OpenAIValidationException e) { Console.WriteLine(e.Message); /* bad request */ }
catch (OpenAIException e)        { Console.WriteLine($"API error {e.StatusCode}: {e.Message}"); }

License

MIT — see LICENSE.

© 2025 Vladyslav Zaiets

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 95 5/3/2026