# Koldan WebSocket SDK for C#

`Koldan.WebSocket.Sdk` is a C# SDK for Koldan real-time speech recognition.

## Install

Download and extract `koldan-websocket-sdk-csharp-<version>.zip`, then install from the included local NuGet package folder:

```bash
dotnet add package Koldan.WebSocket.Sdk --source ./koldan-websocket-sdk-csharp/nuget
```

## Quick Start

```csharp
using Koldan.WebSocket.Sdk;

using var client = new KoldanStreamingClient(new KoldanStreamingClientOptions
{
    BaseUrl = new Uri(Environment.GetEnvironmentVariable("KOLDAN_BASE_URL")!),
    ApiKey = Environment.GetEnvironmentVariable("KOLDAN_API_KEY")
});

var model = (await client.ListStreamingModelsAsync()).First().Id;
var pcmFile = Environment.GetEnvironmentVariable("KOLDAN_PCM_FILE")
    ?? "example-16kHz-S16LE-mono.pcm";

await using var session = await client.StartSessionAsync(new StreamingSessionOptions
{
    Model = model,
    Language = "he",
    EnableEndpointDetection = true
});

var reader = Task.Run(async () =>
{
    await foreach (var message in session.Messages.ReadAllAsync())
    {
        switch (message)
        {
            case PartialResultMessage partial:
                Console.WriteLine($"Partial: {partial.Transcript}");
                break;
            case FinalResultMessage final:
                Console.WriteLine($"Final: {final.Transcript}");
                break;
            case SessionCompletedMessage:
                return;
            case ErrorMessage error:
                throw new KoldanStreamingProtocolException($"{error.Code}: {error.Message}");
        }
    }
});

foreach (var frame in ReadPcmFrames(pcmFile, bytesPerFrame: 3200))
{
    await session.SendAudioAsync(frame);
    await Task.Delay(TimeSpan.FromMilliseconds(100));
}

await session.CompleteAsync();
await reader;

static IEnumerable<byte[]> ReadPcmFrames(string path, int bytesPerFrame)
{
    using var file = File.OpenRead(path);
    var buffer = new byte[bytesPerFrame];
    int read;

    while ((read = file.Read(buffer, 0, buffer.Length)) > 0)
    {
        var frame = new byte[read];
        Buffer.BlockCopy(buffer, 0, frame, 0, read);
        yield return frame;
    }
}
```

## Audio Format

The WebSocket endpoint accepts binary frames containing raw PCM audio:

- 16-bit signed little-endian
- mono
- usually 16 kHz
- recommended frame size: 20-100 ms
- maximum frame size: 65,536 bytes

For 16 kHz, 16-bit mono audio, a 100 ms frame is `16,000 * 2 * 0.1 = 3,200` bytes.
Provide your own raw PCM file through `KOLDAN_PCM_FILE`. If that variable is not set, the example looks for `example-16kHz-S16LE-mono.pcm` in the current working directory. The SDK archive does not include audio files.

## Model Discovery

`ListStreamingModelsAsync()` calls `GET /api/v1/speech-services/models` and returns only aliases where `capabilities.supportsStreaming` is `true`.

The SDK sends `X-API-Key` when `ApiKey` is configured, or `Authorization: Bearer ...` when `BearerToken` is configured. WebSocket authentication is sent inside the `session.start` message, matching the Koldan protocol.

## NAudio Microphone Example

The `examples/NAudioMicrophone` project captures microphone audio with NAudio as 16 kHz, 16-bit, mono PCM and streams it to Koldan.

```powershell
$env:KOLDAN_BASE_URL = "https://koldan.example"
$env:KOLDAN_API_KEY = "kk-..."
$env:KOLDAN_MODEL = "medical-streaming"
dotnet run --project .\examples\NAudioMicrophone\Koldan.WebSocket.Sdk.Examples.NAudioMicrophone.csproj
```

For internal development environments with a private certificate, set `KOLDAN_ALLOW_INVALID_TLS=true`. Do not use that setting in production.
