Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/chataize/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.
https://github.com/chataize/generative-cs
ai chatbot chatgpt chatgpt-api csharp dotnet function-calling gemini gemini-api gemini-pro generative-ai gpt gpt-3 gpt-4 language-model library openai openai-api
Last synced: 2 months ago
JSON representation
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.
- Host: GitHub
- URL: https://github.com/chataize/generative-cs
- Owner: chataize
- License: gpl-3.0
- Created: 2023-12-17T13:43:43.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2024-11-08T16:39:09.000Z (2 months ago)
- Last Synced: 2024-11-08T17:33:43.761Z (2 months ago)
- Topics: ai, chatbot, chatgpt, chatgpt-api, csharp, dotnet, function-calling, gemini, gemini-api, gemini-pro, generative-ai, gpt, gpt-3, gpt-4, language-model, library, openai, openai-api
- Language: C#
- Homepage: https://www.chataize.com
- Size: 587 KB
- Stars: 37
- Watchers: 3
- Forks: 9
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Generative CS
Generative AI library for .NET 9.0 with built-in OpenAI ChatGPT and Google Gemini API clients and support for C# function calling via reflection.![](https://github.com/chataize/generative-cs/assets/124832798/a0b46290-105d-487b-9145-6ce57a1879f7)
## Supported Features
### OpenAI
- [x] Chat Completion
- [x] Text Embedding
- [x] Text-to-Speech
- [x] Speech-to-Text
- [x] Transcription
- [x] Translation
- [x] Moderation
- [x] Response Streaming
- [x] Function Calling
- [ ] Image Generation
- [ ] Assistants API
- [ ] Files API
### Gemini
- [x] Chat Completion
- [x] Function Calling
- [ ] Text Embedding
- [ ] Moderation
- [ ] Response Streaming
- [ ] Multi-Modal Requests
### Miscellaneous
- [x] Dependency Injection
- [x] Time Awareness
- [x] Message/Character Count Limiting
- [x] Message Pinning
- [x] Auto-Reattempt on Failure
- [ ] Token Counting
- [ ] XML Documentation
- [ ] Unit Tests## Installation
### .NET CLI
```bash
dotnet add package ChatAIze.GenerativeCS
```
### Package Manager Console
```powershell
Install-Package ChatAIze.GenerativeCS
```## Clients
### Single Instance
```cs
using ChatAIze.GenerativeCS.Clients;var openAIClient = new OpenAIClient("");
var geminiClient = new GeminiClient("");
```
### Dependency Injection
```cs
using ChatAIze.GenerativeCS.Extensions;builder.Services.AddOpenAIClient("");
builder.Services.AddGeminiClient("");
```
> [!NOTE]
> By default, both `OpenAIClient` and `GeminiClient` 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
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
string response = await client.CompleteAsync("Write an article about Bitcoin.");Console.WriteLine(response);
```
### Streamed Prompt
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
await foreach (string chunk in client.StreamCompletionAsync("Write an article about Bitcoin."))
{
Console.Write(chunk);
}
```
### Chat
```cs
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Models;var client = new OpenAIClient("");
var chat = new Chat();while (true)
{
string message = Console.ReadLine()!;
chat.FromUser(message);string response = await client.CompleteAsync(chat);
Console.WriteLine(response);
}
```
### Streamed Chat
```cs
using ChatAIze.GenerativeCS.Clients;
using ChatAIze.GenerativeCS.Models;var client = new OpenAIClient("");
var chat = new Chat();while (true)
{
string message = Console.ReadLine()!;
chat.FromUser(message);await foreach (string chunk in client.StreamCompletionAsync(chat))
{
Console.Write(chunk);
}
}
```
> [!NOTE]
> Chatbot responses, function calls, and function results are automatically added to the chat.
> You don't need to and should not call ```chat.FromAssistant(...)``` manually, unless you want to *inject* custom messages (e.g. welcome message).
## Embeddings
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
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
```cs
var client = new OpenAIClient("");
await client.SynthesizeSpeechAsync("The quick brown fox jumps over the lazy dog", "speech.mp3");
```
#### Synthesize to Byte Array
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
byte[] speech = await client.SynthesizeSpeechAsync("The quick brown fox jumps over the lazy dog");
```
### Speech-to-Text
#### Transcript From File
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
string transcript = await client.TranscriptAsync("speech.mp3");
```
#### Transcript From Byte Array
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
byte[] audio = await File.ReadAllBytesAsync("speech.mp3");
string transcript = await client.TranscriptAsync(audio);
```
#### Translate From File
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
string translation = await client.TranslateAsync("speech.mp3");
```
#### Translate From Byte Array
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
byte[] audio = await File.ReadAllBytesAsync("speech.mp3");
string translation = await client.TranslateAsync(audio);
```## Moderation
```cs
using ChatAIze.GenerativeCS.Clients;var client = new OpenAIClient("");
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:
> ```cs
> using ChatAIze.GenerativeCS.Options.OpenAI;
> ```
> If you use **Gemini** client add:
> ```cs
> using ChatAIze.GenerativeCS.Options.Gemini;
> ```
### Dependency Injection
#### OpenAI Client
```cs
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Extensions;builder.Services.AddOpenAIClient(configure =>
{
configure.ApiKey = "";
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
```cs
using ChatAIze.GenerativeCS.Constants;
using ChatAIze.GenerativeCS.Extensions;builder.Services.AddGeminiClient(configure =>
{
configure.ApiKey = "";
configure.DefaultCompletionOptions = new ChatCompletionOptions()
{
Model = ChatCompletionModels.Gemini.GeminiPro,
MessageLimit = 10
// set other chat completion options here
};
// set other options here
});
```
### Chat Completion
#### OpenAI Client
```cs
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("", options); // via constructor
client.DefaultCompletionOptions = options; // via property// Set for single request:
string response = await client.CompleteAsync(prompt, options);
string response = await client.CompleteAsync(chat, options);
```
#### Gemini Client
```cs
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("", options); // via constructor
client.DefaultCompletionOptions = options; // via property// Set for single request:
string response = await client.CompleteAsync(prompt, options);
string response = await client.CompleteAsync(chat, options);
```
### Embeddings
```cs
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("", 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
```cs
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("", 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
```cs
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("", options); // via constructor
client.DefaultTranscriptionOptions = options; // via property// Set for single request:
string transcript = await client.TranscriptAsync("speech.mp3", options);
```
#### Translation
```cs
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("", options); // via constructor
client.DefaultTranslationOptions = options; // via property// Set for single request:
string translation = await client.TranslateAsync("speech.mp3", options);
```
#### Moderation
```cs
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("", 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
```cs
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 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
```cs
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
```cs
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
```cs
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
```cs
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 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.
```cs
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`
```cs
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.
```cs
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.
```cs
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 chat even when message and character limits are exceeded.
```cs
using ChatAIze.GenerativeCS.Enums;
using ChatAIze.GenerativeCS.Models;var chat = new Chat();
chat.FromUser("This will always be the first message", PinLocation.Begin);
chat.FromSystem("This message will never be truncated due to limits.", PinLocation.Automatic);
chat.FromUser("This will always be the last (most recent) message", PinLocation.End);
```