ChatAIze.GenerativeCS
0.4.0
See the version list below for details.
dotnet add package ChatAIze.GenerativeCS --version 0.4.0
NuGet\Install-Package ChatAIze.GenerativeCS -Version 0.4.0
<PackageReference Include="ChatAIze.GenerativeCS" Version="0.4.0" />
paket add ChatAIze.GenerativeCS --version 0.4.0
#r "nuget: ChatAIze.GenerativeCS, 0.4.0"
// Install ChatAIze.GenerativeCS as a Cake Addin #addin nuget:?package=ChatAIze.GenerativeCS&version=0.4.0 // Install ChatAIze.GenerativeCS as a Cake Tool #tool nuget:?package=ChatAIze.GenerativeCS&version=0.4.0
Generative CS
Generative AI library for .NET 8.0 with built-in OpenAI ChatGPT and Google Gemini API clients and support for C# function calling via reflection.
Supported Features
OpenAI
- Chat Completion
- Text Embedding
- Text-to-Speech
- Speech-to-Text
- Transcription
- Translation
- Moderation
- Response Streaming
- Function Calling
- Image Generation
- Assistants API
- Files API
Gemini
- Chat Completion
- Function Calling
- Text Embedding
- Moderation
- Response Streaming
- Multi-Modal Requests
Miscellaneous
- Dependency Injection
- Time Awareness
- Message/Character Count Limiting
- Message Pinning
- Auto-Reattempt on Failure
- Token Counting
- XML Documentation
- Unit Tests
Installation
.NET CLI
dotnet add package ChatAIze.GenerativeCS
Package Manager Console
Install-Package ChatAIze.GenerativeCS
Clients
Single Instance
using ChatAIze.GenerativeCS.Clients;
var openAIClient = new OpenAIClient("<OPENAI API KEY>");
var geminiClient = new GeminiClient("<GEMINI API KEY>");
Dependency Injection
using ChatAIze.GenerativeCS.Extensions;
builder.Services.AddOpenAIClient("<OPENAI API KEY>");
builder.Services.AddGeminiClient("<GEMINI API KEY>");
[!NOTE] By default, both
OpenAIClient
andGeminiClient
services are registered as singleton. It's advised not to change global client options after the web application has already been launched. Use per-request options instead.
Chat Completion
Simple Prompt
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
string response = await client.CompleteAsync("Write an article about Bitcoin.");
Console.WriteLine(response);
Streamed Prompt
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
await foreach (string chunk in client.StreamCompletionAsync("Write an article about Bitcoin."))
{
Console.Write(chunk);
}
Conversation
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Models;
var client = new OpenAIClient("<OPENAI API KEY>");
var conversation = new ChatConversation();
while (true)
{
string message = Console.ReadLine()!;
conversation.FromUser(message);
string response = await client.CompleteAsync(conversation);
Console.WriteLine(response);
}
Streamed Conversation
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Models;
var client = new OpenAIClient("<OPENAI API KEY>");
var conversation = new ChatConversation();
while (true)
{
string message = Console.ReadLine()!;
conversation.FromUser(message);
await foreach (string chunk in client.StreamCompletionAsync(conversation))
{
Console.Write(chunk);
}
}
[!NOTE] Chatbot responses, function calls, and function results are automatically added to the conversation. You don't need to and should not call
conversation.FromAssistant(...)
manually, unless you want to inject custom messages (e.g. welcome message).
Embeddings
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
float[] vectorEmbedding = await client.GetEmbeddingAsync("The quick brown fox jumps over the lazy dog");
string base64Embedding = await client.GetBase64EmbeddingAsync("The quick brown fox jumps over the lazy dog");
Audio
Text-to-Speech
Synthesize to File
var client = new OpenAIClient("<OPENAI API KEY>");
await client.SynthesizeSpeechAsync("The quick brown fox jumps over the lazy dog", "speech.mp3");
Synthesize to Byte Array
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
byte[] speech = await client.SynthesizeSpeechAsync("The quick brown fox jumps over the lazy dog");
Speech-to-Text
Transcript From File
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
string transcript = await client.TranscriptAsync("speech.mp3");
Transcript From Byte Array
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
byte[] audio = await File.ReadAllBytesAsync("speech.mp3");
string transcript = await client.TranscriptAsync(audio);
Translate From File
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
string translation = await client.TranslateAsync("speech.mp3");
Translate From Byte Array
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
byte[] audio = await File.ReadAllBytesAsync("speech.mp3");
string translation = await client.TranslateAsync(audio);
Moderation
using ChatAIze.GenerativeCS.Clients;
var client = new OpenAIClient("<OPENAI API KEY>");
var result = await client.ModerateAsync("I am going to blow up your house in Minecraft.");
Console.WriteLine(result.IsFlagged); // true
Console.WriteLine(result.IsViolence); // true
Console.WriteLine(result.ViolenceScore); // 0,908397912979126
Options
[!NOTE] Per-request options take precedence over default client options.
[!TIP] If you use OpenAI client add:
using ChatAIze.GenerativeCS.Options.OpenAI;
If you use Gemini client add:
using ChatAIze.GenerativeCS.Options.Gemini;
Dependency Injection
OpenAI Client
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Extensions;
builder.Services.AddOpenAIClient(configure =>
{
configure.ApiKey = "<OPENAI API KEY>";
configure.DefaultCompletionOptions = new ChatCompletionOptions()
{
Model = ChatCompletionModels.OpenAI.GPT4o,
Temperature = 1.0
// set other chat completion options here
};
configure.DefaultEmbeddingOptions = new EmbeddingOptions()
{
Model = EmbeddingModels.OpenAI.TextEmbedding3Large,
MaxAttempts = 5
// set other embeding options here
};
// set other options here
});
Gemini Client
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Extensions;
builder.Services.AddGeminiClient(configure =>
{
configure.ApiKey = "<GEMINI API KEY>";
configure.DefaultCompletionOptions = new ChatCompletionOptions()
{
Model = ChatCompletionModels.Gemini.GeminiPro,
MessageLimit = 10
// set other chat completion options here
};
// set other options here
});
Chat Completion
OpenAI Client
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Models;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new ChatCompletionOptions
{
Model = ChatCompletionModels.OpenAI.GPT4o,
UserTrackingId = "USER_ID_1234",
MaxAttempts = 5,
MaxOutputTokens = 2000,
MessageLimit = 10,
CharacterLimit = 20000,
Seed = 1234,
Temperature = 1.0,
TopP = 1,
FrequencyPenalty = 0.0,
PresencePenalty = 0.0,
IsJsonMode = false,
IsTimeAware = true,
StopWords = ["11.", "end"],
Functions = [new ChatFunction("ToggleDarkMode")],
DefaultFunctionCallback = async (name, arguments, cancellationToken) =>
{
await Console.Out.WriteLineAsync($"Function {name} called with arguments {arguments}");
return new { Success = true, Property1 = "ABC", Property2 = 123 };
},
AddMessageCallback = async (message) =>
{
// Called every time a new message is added, including function calls and results:
await Console.Out.WriteLineAsync($"Message added: {message}");
},
TimeCallback = () => DateTime.Now
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultCompletionOptions = options; // via property
// Set for single request:
string response = await client.CompleteAsync(prompt, options);
string response = await client.CompleteAsync(conversation, options);
Gemini Client
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Models;
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions
{
Model = ChatCompletionModels.Gemini.Gemini15Flash,
MaxAttempts = 5,
MessageLimit = 10,
CharacterLimit = 20000,
IsTimeAware = true,
Functions = [new ChatFunction("ToggleDarkMode")],
DefaultFunctionCallback = async (name, arguments, cancellationToken) =>
{
await Console.Out.WriteLineAsync($"Function {name} called with arguments {arguments}");
return new { Success = true, Property1 = "ABC", Property2 = 123 };
},
TimeCallback = () => DateTime.Now
};
// Set for entire client:
var client = new GeminiClient("<GEMINI API KEY>", options); // via constructor
client.DefaultCompletionOptions = options; // via property
// Set for single request:
string response = await client.CompleteAsync(prompt, options);
string response = await client.CompleteAsync(conversation, options);
Embeddings
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new EmbeddingOptions
{
Model = EmbeddingModels.OpenAI.TextEmbedding3Large,
User = "USER_ID_1234",
MaxAttempts = 5
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultEmbeddingOptions = options; // via property
// Set for single request:
float[] embedding = await client.GetEmbeddingAsync("The quick brown fox jumps over the lazy dog", options);
Audio
Text-to-Speech
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Enums;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new TextToSpeechOptions
{
Model = TextToSpeechModels.OpenAI.TTS1,
Voice = TextToSpeechVoice.Alloy,
Speed = 1.0,
MaxAttempts = 5,
ResponseFormat = VoiceResponseFormat.MP3
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultTextToSpeechOptions = options; // via property
// Set for single request:
await client.SynthesizeSpeechAsync("The quick brown fox jumps over the lazy dog", "speech.mp3", options);
Transcription
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Enums;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new TranscriptionOptions
{
Model = SpeechRecognitionModels.OpenAI.Whisper1,
Language = "en",
Prompt = "ZyntriQix, Digique Plus, CynapseFive, VortiQore V8, EchoNix Array, ...",
Temperature = 0.0,
MaxAttempts = 5,
ResponseFormat = TranscriptionResponseFormat.Text
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultTranscriptionOptions = options; // via property
// Set for single request:
string transcript = await client.TranscriptAsync("speech.mp3", options);
Translation
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Enums;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new TranslationOptions
{
Model = SpeechRecognitionModels.OpenAI.Whisper1,
Prompt = "ZyntriQix, Digique Plus, CynapseFive, VortiQore V8, EchoNix Array, ...",
Temperature = 0.0,
MaxAttempts = 5,
ResponseFormat = TranscriptionResponseFormat.Text
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultTranslationOptions = options; // via property
// Set for single request:
string translation = await client.TranslateAsync("speech.mp3", options);
Moderation
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Options.OpenAI;
var options = new ModerationOptions
{
Model = ModerationModels.OpenAI.TextModerationStable,
MaxAttempts = 5
};
// Set for entire client:
var client = new OpenAIClient("<OPENAI API KEY>", options); // via constructor
client.DefaultModerationOptions = options; // via property
// Set for single request:
var result = await client.ModerateAsync("I am going going to blow up your house in Minecraft.", options);
Function Calling
Top-Level Methods
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
void ToggleDarkMode(bool isOn)
{
Console.WriteLine($"Dark mode set to: {isOn}");
}
string GetCurrentWeather(string location)
{
return $"The weather in {location} is 72 degrees and sunny.";
}
async Task<object> SendEmailAsync(string recipient, string subject, string body)
{
await Task.Delay(3000);
return new { Success = true, Property1 = "ABC", Property2 = 123 };
}
var options = new ChatCompletionOptions();
options.AddFunction(ToggleDarkMode);
options.AddFunction(GetCurrentWeather);
options.AddFunction(SendEmailAsync);
Static Class Methods
using System.ComponentModel;
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions();
options.AddFunction(SmartHome.CheckFrontCamera);
options.AddFunction(SmartHome.SetFrontDoorLockAsync);
options.AddFunction(SmartHome.SetTemperature);
public static class SmartHome
{
[Description("Checks if there is someone waiting at the front door.")]
public static object CheckFrontCamera()
{
return new { Success = true, IsPersonDetected = true };
}
public static async Task SetFrontDoorLockAsync(bool isLocked)
{
await Task.Delay(3000);
Console.WriteLine($"Front door locked: {isLocked}");
}
public static void SetTemperature(string room, int temperature)
{
Console.WriteLine($"Temperature in {room} has been set to {temperature} degrees.");
}
}
Class Instance Methods
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions();
var product = new Product();
options.AddFunction(product.GetDescription);
options.AddFunction(product.Rename);
options.AddFunction(product.Delete);
public class Product
{
public string? Name { get; set; }
public string GetDescription()
{
return $"This is a {Name}";
}
public void Rename(string name)
{
Name = name;
}
public void Delete()
{
Console.WriteLine($"Deleting product: {Name}");
}
}
Anonymous Functions
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions();
options.AddFunction("GetCurrentWeather", (string location) =>
{
return "The current weather is sunny";
});
options.AddFunction("GetCurrentWeather", async () =>
{
await Task.Delay(3000);
return "The current weather is sunny";
});
options.AddFunction("GetCurrentWeather", "Gets the current weathe in default location.", async () =>
{
await Task.Delay(3000);
return new WeatherData(20, 50);
});
public record WeatherData(int Temperature, int Humidity);
Default Function Callback
using ChatAIze.GenerativeCS.Models;
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions();
options.AddFunction("GetUserLocation");
options.AddFunction("GetCurrentWeather", new FunctionParameter(typeof(string), "location"));
List<FunctionParameter> parameters = [new(typeof(string), "room"), new(typeof(int), "temperature")];
options.AddFunction("SetRoomTemperature", parameters);
options.DefaultFunctionCallback = async (name, parameters, cancellationToken) =>
{
if (name == "GetUserLocation")
{
return "London";
}
if (name == "GetCurrentWeather")
{
return new { Temperature = 20, Weather = "Sunny" };
}
if (name == "SetRoomTemperature")
{
await Task.Delay(3000, cancellationToken);
return new { IsSuccess = true };
}
return new { Error = $"Unknown function: {name}" };
};
Additional Features
Time Awareness
You can configure both Gemini and OpenAI clients to be aware of the current date and time.
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions
{
IsTimeAware = true,
// other completion options
};
By default, GenerativeCS uses DateTime.Now
, but you can change the source of current time by specifying custom TimeCallback
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions
{
IsTimeAware = true,
TimeCallback = () => new DateTime(2024, 1, 14),
};
Limits
Message Limit
The maximum number of messages sent in a single chat completion request. The oldest messages will be removed one by one until the limit is satisfied.
- Pinned messages count toward the limit and have priority but are never truncated.
- The limit does include function calls and results.
- Function definitions are not considered messages.
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions
{
MessageLimit = 10,
};
Character Limit
The maximum number of characters sent in a single chat completion request. The oldest messages will be removed one by one until the limit is satisfied.
- Pinned messages count toward the limit and have priority but are never truncated.
- The limit does include function calls and results.
- Function definitions are not considered messages.
using ChatAIze.GenerativeCS.Options.OpenAI;
// or
using ChatAIze.GenerativeCS.Options.Gemini;
var options = new ChatCompletionOptions
{
CharacterLimit = 10,
};
Message Pinning
Messages can be pinned to ensure they stay in the conversation even when message and character limits are exceeded.
using ChatAIze.GenerativeCS.Enums;
using ChatAIze.GenerativeCS.Models;
var conversation = new ChatConversation();
conversation.FromUser("This will always be the first message", PinLocation.Begin);
conversation.FromSystem("This message will never be truncated due to limits.", PinLocation.Automatic);
conversation.FromUser("This will always be the last (most recent) message", PinLocation.End);
Product | Versions 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. |
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.2)
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 |
---|---|---|
0.11.18 | 102 | 11/17/2024 |
0.11.17 | 77 | 11/16/2024 |
0.11.16 | 73 | 11/16/2024 |
0.11.15 | 69 | 11/16/2024 |
0.11.14 | 68 | 11/15/2024 |
0.11.13 | 75 | 11/15/2024 |
0.11.12 | 75 | 11/14/2024 |
0.11.11 | 80 | 11/14/2024 |
0.11.10 | 87 | 11/13/2024 |
0.11.9 | 75 | 11/13/2024 |
0.11.8 | 74 | 11/12/2024 |
0.11.7 | 92 | 11/10/2024 |
0.11.6 | 76 | 11/10/2024 |
0.11.5 | 86 | 11/10/2024 |
0.11.4 | 83 | 11/9/2024 |
0.11.3 | 76 | 11/9/2024 |
0.11.2 | 78 | 11/8/2024 |
0.11.1 | 80 | 11/8/2024 |
0.11.0 | 91 | 11/3/2024 |
0.10.6 | 94 | 11/2/2024 |
0.10.5 | 78 | 11/2/2024 |
0.10.4 | 86 | 11/1/2024 |
0.10.3 | 72 | 11/1/2024 |
0.10.2 | 69 | 10/31/2024 |
0.10.1 | 81 | 10/27/2024 |
0.10.0 | 80 | 10/27/2024 |
0.9.1 | 125 | 10/19/2024 |
0.9.0 | 135 | 10/18/2024 |
0.8.6 | 88 | 10/8/2024 |
0.8.5 | 103 | 10/6/2024 |
0.8.4 | 83 | 10/6/2024 |
0.8.3 | 86 | 10/6/2024 |
0.8.2 | 85 | 10/6/2024 |
0.8.1 | 84 | 10/6/2024 |
0.8.0 | 80 | 10/6/2024 |
0.7.0 | 104 | 9/27/2024 |
0.6.2 | 410 | 9/5/2024 |
0.6.1 | 110 | 8/27/2024 |
0.6.0 | 120 | 8/25/2024 |
0.5.0 | 110 | 8/23/2024 |
0.4.1 | 138 | 8/15/2024 |
0.4.0 | 131 | 8/15/2024 |
0.3.6 | 133 | 7/18/2024 |
0.3.5 | 818 | 5/15/2024 |
0.3.4 | 418 | 4/19/2024 |
0.3.3 | 359 | 3/26/2024 |
0.3.2 | 212 | 3/26/2024 |
0.3.1 | 191 | 3/26/2024 |
0.3.0 | 211 | 3/26/2024 |
0.2.1 | 791 | 1/31/2024 |
0.2.0 | 581 | 1/31/2024 |
0.1.3 | 619 | 1/20/2024 |
0.1.2 | 638 | 1/14/2024 |
0.1.1 | 635 | 1/14/2024 |