Ai.Tlbx.VoiceAssistant
8.5.0
dotnet add package Ai.Tlbx.VoiceAssistant --version 8.5.0
NuGet\Install-Package Ai.Tlbx.VoiceAssistant -Version 8.5.0
<PackageReference Include="Ai.Tlbx.VoiceAssistant" Version="8.5.0" />
<PackageVersion Include="Ai.Tlbx.VoiceAssistant" Version="8.5.0" />
<PackageReference Include="Ai.Tlbx.VoiceAssistant" />
paket add Ai.Tlbx.VoiceAssistant --version 8.5.0
#r "nuget: Ai.Tlbx.VoiceAssistant, 8.5.0"
#:package Ai.Tlbx.VoiceAssistant@8.5.0
#addin nuget:?package=Ai.Tlbx.VoiceAssistant&version=8.5.0
#tool nuget:?package=Ai.Tlbx.VoiceAssistant&version=8.5.0
AI Voice Assistant Toolkit
Real-time voice conversations with AI in .NET — OpenAI, Google Gemini, and xAI Grok in one unified API.
Quick Start (Blazor Server)
1. Install packages:
dotnet add package Ai.Tlbx.VoiceAssistant
dotnet add package Ai.Tlbx.VoiceAssistant.Provider.OpenAi # and/or .Google, .XAi
dotnet add package Ai.Tlbx.VoiceAssistant.Hardware.Web
2. Add API keys (appsettings.json):
{
"VoiceProviders": {
"OpenAI": "sk-...",
"Google": "AIza...",
"xAI": "xai-..."
}
}
3. Configure services (Program.cs):
// Register provider factory and audio hardware
builder.Services.AddSingleton<IVoiceProviderFactory, VoiceProviderFactory>();
builder.Services.AddScoped<IAudioHardwareAccess, WebAudioAccess>();
4. Create a voice page (Voice.razor):
@page "/voice"
@inject IVoiceProviderFactory ProviderFactory
@inject IAudioHardwareAccess AudioHardware
@inject IConfiguration Config
<select @bind="_selectedProvider">
<option value="openai">OpenAI</option>
<option value="google">Google Gemini</option>
<option value="xai">xAI Grok</option>
</select>
<button @onclick="Toggle">@(_assistant?.IsRecording == true ? "Stop" : "Talk")</button>
@foreach (var msg in _messages)
{
<p><b>@msg.Role:</b> @msg.Content</p>
}
@code {
private VoiceAssistant? _assistant;
private List<ChatMessage> _messages = new();
private string _selectedProvider = "openai";
private async Task Toggle()
{
if (_assistant?.IsRecording == true)
{
await _assistant.StopAsync();
return;
}
// Create provider based on selection
var (provider, settings) = _selectedProvider switch
{
"openai" => (
ProviderFactory.CreateOpenAi(Config["VoiceProviders:OpenAI"]!),
(IVoiceSettings)new OpenAiVoiceSettings { Instructions = "You are helpful." }
),
"google" => (
ProviderFactory.CreateGoogle(Config["VoiceProviders:Google"]!),
(IVoiceSettings)new GoogleVoiceSettings { Instructions = "You are helpful." }
),
"xai" => (
ProviderFactory.CreateXai(Config["VoiceProviders:xAI"]!),
(IVoiceSettings)new XaiVoiceSettings { Instructions = "You are helpful." }
),
_ => throw new InvalidOperationException()
};
_assistant = new VoiceAssistant(provider, AudioHardware);
_assistant.OnMessageReceived = msg => InvokeAsync(() => { _messages.Add(msg); StateHasChanged(); });
await _assistant.StartAsync(settings);
}
}
That's it. Select a provider, talk to the AI, get voice responses back.
All Packages
Switch Providers in One Line
// OpenAI
var provider = factory.CreateOpenAi(apiKey);
var settings = new OpenAiVoiceSettings { Voice = AssistantVoice.Alloy };
// Google Gemini
var provider = factory.CreateGoogle(apiKey);
var settings = new GoogleVoiceSettings { Voice = GeminiVoice.Puck };
// xAI Grok
var provider = factory.CreateXai(apiKey);
var settings = new XaiVoiceSettings { Voice = XaiVoice.Ara };
Same VoiceAssistant API, same tool definitions — just swap the provider.
Tools: Just Write C#
Define tools with plain C# records. Schema is auto-inferred — no JSON, no manual mapping:
[Description("Get weather for a location")]
public class WeatherTool : VoiceToolBase<WeatherTool.Args>
{
public record Args(
[property: Description("City name")] string Location,
[property: Description("Temperature unit")] TemperatureUnit Unit = TemperatureUnit.Celsius
);
public override string Name => "get_weather";
public override Task<string> ExecuteAsync(Args args)
{
return Task.FromResult(CreateSuccessResult(new { temp = 22, location = args.Location }));
}
}
public enum TemperatureUnit { Celsius, Fahrenheit }
Universal translation: The same tool works on OpenAI, Google, and xAI. Required/optional parameters, enums, nested objects — all inferred from C# types.
Register in DI:
builder.Services.AddTransient<IVoiceTool, WeatherTool>();
Writing Custom Tools
Basic Pattern
- Create a record for arguments — use
[Description]attributes for AI guidance - Extend
VoiceToolBase<TArgs>— add[Description]to the class itself - Implement
ExecuteAsync— return results viaToolSuccessResult<T>
[Description("Search for products in the catalog")]
public class ProductSearchTool : VoiceToolBase<ProductSearchTool.Args>
{
public record Args(
[property: Description("Search query keywords")] string Query,
[property: Description("Maximum results to return")] int MaxResults = 10,
[property: Description("Filter by category")] string? Category = null
);
public override string Name => "search_products";
public override async Task<string> ExecuteAsync(Args args)
{
var products = await _catalogService.SearchAsync(args.Query, args.MaxResults, args.Category);
var result = new ToolSuccessResult<ProductSearchResult>(new ProductSearchResult
{
Products = products,
TotalFound = products.Count
});
return JsonSerializer.Serialize(result, YourJsonContext.Default.ToolSuccessResultProductSearchResult);
}
}
Required vs Optional Parameters
- Required: No default value, non-nullable → AI must provide or ask user
- Optional: Has default value OR nullable (
string?) → AI can omit
public record Args(
string RequiredParam, // Required - AI must provide
string OptionalWithDefault = "default", // Optional - has default
string? OptionalNullable = null // Optional - nullable
);
Returning Results
Always use the provided result types for consistent AI interpretation:
// Success with data
var result = new ToolSuccessResult<YourDataType>(data);
return JsonSerializer.Serialize(result, YourJsonContext.Default.ToolSuccessResultYourDataType);
// Error
return CreateErrorResult("Something went wrong");
AOT Compatibility
For Native AOT or Blazor WebAssembly with trimming, reflection-based JSON serialization won't work. You need source-generated JSON contexts.
Step 1: Create a JSON context for your tool types
[JsonSerializable(typeof(ToolSuccessResult<ProductSearchResult>))]
[JsonSerializable(typeof(ProductSearchTool.Args), TypeInfoPropertyName = "ProductSearchToolArgs")]
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
public partial class MyToolsJsonContext : JsonSerializerContext
{
}
Step 2: Register the type info with your tool
// In your DI setup or tool initialization
var tool = new ProductSearchTool();
tool.SetJsonTypeInfo(MyToolsJsonContext.Default.ProductSearchToolArgs);
Step 3: Use source-generated serialization in ExecuteAsync
return JsonSerializer.Serialize(result, MyToolsJsonContext.Default.ToolSuccessResultProductSearchResult);
AOT Checklist
| Item | Non-AOT | AOT |
|---|---|---|
| Args deserialization | Automatic (reflection) | Call SetJsonTypeInfo() |
| Result serialization | Can use JsonSerializer.Serialize<T>() |
Must use JsonSerializer.Serialize(value, context.TypeInfo) |
| Enum handling | Automatic | Include enum types in [JsonSerializable] |
| Nested types | Automatic | Include all nested types in context |
Dependency Injection with Tools
Tools can use constructor injection:
public class DatabaseTool : VoiceToolBase<DatabaseTool.Args>
{
private readonly IDbConnection _db;
public DatabaseTool(IDbConnection db) => _db = db;
// ...
}
// Registration
builder.Services.AddTransient<IVoiceTool, DatabaseTool>();
Key Features
Studio-Quality Audio Processing
The Hardware.Web package includes an AudioWorklet-based audio chain:
- 48kHz capture with browser echo cancellation, noise suppression, and auto gain
- De-esser (high-shelf EQ) to tame sibilance before amplification
- Compressor (8:1 ratio) for consistent loudness across whispers and shouts
- Anti-aliasing filter (Butterworth LPF) before downsampling
- Provider-specific sample rates: 16kHz for Google, 24kHz for OpenAI/xAI
Provider-Agnostic Architecture
Write once, run on any provider. The orchestrator handles:
- Audio format conversion (PCM 16-bit, provider-specific sample rates)
- Tool schema translation per provider
- Streaming audio playback with interruption support
- Chat history management
Built-in Tools
TimeTool— Current time in any timezoneWeatherTool— Mock weather (demo)CalculatorTool— Basic math operations
Native Apps (Windows/Linux)
Note: Native desktop support works but is less polished than the web implementation. Good for experiments and prototypes.
// Windows (requires Windows 10+)
dotnet add package Ai.Tlbx.VoiceAssistant.Hardware.Windows
// Linux (requires libasound2-dev)
dotnet add package Ai.Tlbx.VoiceAssistant.Hardware.Linux
var provider = new OpenAiVoiceProvider(apiKey, logger);
var hardware = new WindowsAudioHardware(); // or LinuxAudioDevice
var assistant = new VoiceAssistant(provider, hardware);
await assistant.StartAsync(settings);
Console.ReadKey(); // Talk now
await assistant.StopAsync();
Requirements
- .NET 9.0 or .NET 10.0
- API Key: OpenAI, Google AI Studio, or xAI
- Web: Modern browser with microphone permission (HTTPS or localhost)
- Windows: Windows 10+
- Linux:
sudo apt-get install libasound2-dev
License
MIT — do whatever you want.
<p align="center"> <a href="https://www.nuget.org/packages/Ai.Tlbx.VoiceAssistant/">NuGet</a> • <a href="https://github.com/AiTlbx/Ai.Tlbx.VoiceAssistant/issues">Issues</a> • <a href="https://github.com/AiTlbx/Ai.Tlbx.VoiceAssistant">GitHub</a> </p>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. 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 is compatible. 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. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Options (>= 9.0.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Options (>= 9.0.0)
NuGet packages (7)
Showing the top 5 NuGet packages that depend on Ai.Tlbx.VoiceAssistant:
| Package | Downloads |
|---|---|
|
Ai.Tlbx.VoiceAssistant.Provider.OpenAi
OpenAI provider implementation for the Voice Assistant toolkit. Enables real-time conversation with OpenAI's GPT models through WebSocket connections. |
|
|
Ai.Tlbx.VoiceAssistant.Hardware.Web
Web-specific audio provider for Voice Assistant toolkit |
|
|
Ai.Tlbx.VoiceAssistant.WebUi
Blazor UI components for Voice Assistant toolkit |
|
|
Ai.Tlbx.VoiceAssistant.Hardware.Windows
Windows-specific hardware integration for voice assistant audio processing |
|
|
Ai.Tlbx.VoiceAssistant.Hardware.Linux
Linux-specific hardware integration for voice assistant audio processing |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 8.5.0 | 98 | 2/28/2026 |
| 8.4.0 | 98 | 2/28/2026 |
| 8.3.0 | 171 | 2/24/2026 |
| 8.2.1 | 173 | 2/24/2026 |
| 8.2.0 | 174 | 2/24/2026 |
| 8.1.5 | 194 | 2/2/2026 |
| 8.1.4 | 198 | 1/22/2026 |
| 8.1.3 | 208 | 1/14/2026 |
| 8.1.2 | 183 | 1/14/2026 |
| 8.1.1 | 207 | 1/12/2026 |
| 8.1.0 | 170 | 1/12/2026 |
| 6.5.0 | 382 | 12/18/2025 |
| 6.4.1 | 347 | 12/16/2025 |
| 6.2.2 | 354 | 12/16/2025 |
| 6.2.1 | 399 | 11/21/2025 |
| 6.1.4 | 367 | 11/12/2025 |
| 6.1.3 | 356 | 11/12/2025 |
| 6.1.2 | 355 | 11/12/2025 |
| 6.1.1 | 247 | 10/25/2025 |
| 6.0.1 | 245 | 10/22/2025 |