uncloseai.

C# Examples - Free LLM & TTS AI Service

C# Examples

This page demonstrates how to use the uncloseai. API endpoints with C#. Examples are provided for both .NET 10 (latest) and Mono (cross-platform) runtimes.

Available Endpoints:

Both chat hostnames currently serve the same model, turboderp/Qwen3.8-27B-exl3 (read live from /v1/models). Hostnames are routing labels, not model names: every example below asks the endpoint which model it serves instead of hard-coding an id, so a model swap on the cards never breaks your code. The served model reasons before it answers (the reasoning arrives in a separate reasoning field), so give it room: the samples ask for 600 tokens because at 150 the budget ran out before the answer began.

Many endpoints from environment variables

Our clients (uncloseai-cli, uncloseai.js, opencompletion and the downloadable implementation for every language on this site) share one convention, so an endpoint is configuration, never code:

VariableMeaning
MODEL_ENDPOINT_NBase URL of the N-th OpenAI-compatible endpoint, ending in /v1. The only required variable. Scan N from 0 upward and skip gaps: uncloseai-cli counts from 0, the per-language implementations from 1.
MODEL_API_KEY_NBearer key for endpoint N. Unset means no key, which is all our free relay needs; a cloud endpoint sets one.
MODEL_ID_NModel id to send. Unset means ask /v1/models and take the first id, the rule used by every sample on this page.
MODEL_LABEL_NA display name for endpoint N; defaults to its hostname.
TTS_ENDPOINT_NThe same shape for text-to-speech endpoints.
export MODEL_ENDPOINT_0="https://hermes.ai.unturf.com/v1"
export MODEL_ENDPOINT_1="https://qwen.ai.unturf.com/v1"
# export MODEL_API_KEY_1="sk-..."      # only for an endpoint that needs one
export TTS_ENDPOINT_0="https://speech.ai.unturf.com/v1"

The first endpoint is the default; the rest fail over, in order. The C# implementation under /languages/ reads these variables and discovers each endpoint's models at startup.

Runtime Options

Runtime Best For Setup
.NET 10 Latest features, best performance, Windows/Linux/macOS dotnet new console
Mono Legacy systems, embedded, wide platform support mcs Program.cs

.NET 10 Examples

Using the official OpenAI .NET SDK with .NET 10. This provides the cleanest API with full async/await support.

Setup

# Create new project
dotnet new console -n UncloseAI
cd UncloseAI

# Add OpenAI package
dotnet add package OpenAI --version 2.5.0

Non-Streaming (hermes.ai.unturf.com)

using System.ClientModel;
using OpenAI;
using OpenAI.Chat;

var openAI = new OpenAIClient(
    new ApiKeyCredential("choose-any-value"),
    new OpenAIClientOptions
    {
        Endpoint = new Uri("https://hermes.ai.unturf.com/v1")
    }
);

// Ask the endpoint which model it serves; never hard-code an id.
string model = (await openAI.GetOpenAIModelClient().GetModelsAsync()).Value[0].Id;
ChatClient client = openAI.GetChatClient(model);

ChatCompletion completion = await client.CompleteChatAsync(
    new List<ChatMessage>
    {
        new UserChatMessage("Give a Python Fizzbuzz solution in one line of code?")
    },
    new ChatCompletionOptions
    {
        Temperature = 0.5f,
        MaxTokens = 600
    }
);

Console.WriteLine(completion.Content[0].Text);

Streaming (hermes.ai.unturf.com)

using System.ClientModel;
using OpenAI;
using OpenAI.Chat;

var openAI = new OpenAIClient(
    new ApiKeyCredential("choose-any-value"),
    new OpenAIClientOptions
    {
        Endpoint = new Uri("https://hermes.ai.unturf.com/v1")
    }
);

// Ask the endpoint which model it serves; never hard-code an id.
string model = (await openAI.GetOpenAIModelClient().GetModelsAsync()).Value[0].Id;
ChatClient client = openAI.GetChatClient(model);

var streamingUpdates = client.CompleteChatStreamingAsync(
    new List<ChatMessage>
    {
        new UserChatMessage("Write a short poem about coding")
    },
    new ChatCompletionOptions
    {
        Temperature = 0.5f,
        MaxTokens = 200
    }
);

await foreach (var update in streamingUpdates)
{
    foreach (var contentPart in update.ContentUpdate)
    {
        Console.Write(contentPart.Text);
    }
}

Text-to-Speech

using OpenAI.Audio;

var client = new AudioClient(
    model: "tts-1-f5",
    apiKey: "choose-any-value",
    new OpenAIClientOptions
    {
        Endpoint = new Uri("https://speech.ai.unturf.com/v1")
    }
);

BinaryData speech = await client.GenerateSpeechAsync(
    "Hello! This is a test of text to speech.",
    new GeneratedSpeechVoice("foxhop"),
    new SpeechGenerationOptions { Speed = 1.0f }
);

await File.WriteAllBytesAsync("speech.mp3", speech.ToArray());
Console.WriteLine("Audio saved to speech.mp3");

Mono Examples

Using HttpClient directly with Mono runtime. No external packages required - works with the built-in System.Net.Http.

Setup

# Install Mono (Ubuntu/Debian)
sudo apt install mono-complete

# Compile
mcs -r:System.Net.Http.dll Program.cs

# Run
mono Program.exe

Non-Streaming (hermes.ai.unturf.com)

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static readonly HttpClient client = new HttpClient();

    static async Task Main()
    {
        // Ask the endpoint which model it serves; never hard-code an id.
        var models = await client.GetStringAsync("https://hermes.ai.unturf.com/v1/models");
        // data[0].id without a JSON package, the same simplified parse as the stream loop
        var idStart = models.IndexOf("\"", models.IndexOf("\"id\"") + 4) + 1;
        var model = models.Substring(idStart, models.IndexOf("\"", idStart) - idStart);

        var payload = $@"{{
            ""model"": ""{model}"",
            ""messages"": [{{""role"": ""user"", ""content"": ""Give a Python Fizzbuzz solution in one line of code?""}}],
            ""max_tokens"": 600
        }}";

        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(
            "https://hermes.ai.unturf.com/v1/chat/completions",
            content
        );

        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
    }
}

Streaming (hermes.ai.unturf.com)

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static readonly HttpClient client = new HttpClient();

    static async Task Main()
    {
        // Ask the endpoint which model it serves; never hard-code an id.
        var models = await client.GetStringAsync("https://hermes.ai.unturf.com/v1/models");
        // data[0].id without a JSON package, the same simplified parse as the stream loop
        var idStart = models.IndexOf("\"", models.IndexOf("\"id\"") + 4) + 1;
        var model = models.Substring(idStart, models.IndexOf("\"", idStart) - idStart);

        var payload = $@"{{
            ""model"": ""{model}"",
            ""messages"": [{{""role"": ""user"", ""content"": ""Write a short poem about coding""}}],
            ""max_tokens"": 200,
            ""stream"": true
        }}";

        var request = new HttpRequestMessage(HttpMethod.Post, "https://hermes.ai.unturf.com/v1/chat/completions");
        request.Content = new StringContent(payload, Encoding.UTF8, "application/json");

        var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        using var stream = await response.Content.ReadAsStreamAsync();
        using var reader = new StreamReader(stream);

        while (!reader.EndOfStream)
        {
            var line = await reader.ReadLineAsync();
            if (line?.StartsWith("data: ") == true)
            {
                var json = line.Substring(6);
                if (json != "[DONE]")
                {
                    // Extract content from JSON (simplified)
                    var start = json.IndexOf("\"content\":\"") + 11;
                    if (start > 10)
                    {
                        var end = json.IndexOf("\"", start);
                        if (end > start)
                        {
                            Console.Write(json.Substring(start, end - start));
                        }
                    }
                }
            }
        }
    }
}

Text-to-Speech

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static readonly HttpClient client = new HttpClient();

    static async Task Main()
    {
        var payload = @"{
            ""model"": ""tts-1-f5"",
            ""input"": ""Hello! This is a test of text to speech."",
            ""voice"": ""foxhop""
        }";

        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(
            "https://speech.ai.unturf.com/v1/audio/speech",
            content
        );

        var audioBytes = await response.Content.ReadAsByteArrayAsync();
        File.WriteAllBytes("speech.mp3", audioBytes);
        Console.WriteLine("Audio saved to speech.mp3");
    }
}

Available voices: foxhop, aria, clara, elena, grace, hazel, iris, luna and 33 more, listed live at speech.ai.unturf.com/v1/voices; pass any id as voice.

Full SDK Implementations

For complete SDK implementations with model discovery and advanced features: