Documentation Index
Fetch the complete documentation index at: https://docs.kova.ai/llms.txt
Use this file to discover all available pages before exploring further.
@kova-ai/tts is the official JavaScript/TypeScript client. Works in Node 18+. Source: github.com/evalabs-ai/kova-tts-clients.
The WebSocket helper requires a Node runtime — browsers cannot reliably set the
x-api-key handshake header. Use
Streaming HTTP for browser clients, or proxy the WebSocket through a Node backend.
Install
Initialize
import { KovaTTSClient } from "@kova-ai/tts";
const client = new KovaTTSClient({
apiKey: process.env.KOVA_API_KEY!,
});
By default the client targets https://api.kova.ai/v1/tts. Override baseUrl for staging or self-hosting:
const client = new KovaTTSClient({
apiKey: process.env.KOVA_API_KEY!,
baseUrl: "https://staging.api.kova.ai/v1/tts",
});
Sync TTS
const result = await client.tts({
text: "Hello world.",
voice: "cal",
response_format: { encoding: "mp3" },
timestamps: true,
});
await client.writeAudioFile(result.audio, "out.mp3");
console.log(result.timestamps?.words);
result.audio is the decoded audio bytes (Uint8Array), not base64.
Streaming TTS
streamTTS returns an async iterable of events:
for await (const event of client.streamTTS({
text: "Hello world.",
voice: "cal",
response_format: { encoding: "mp3" },
timestamps: true,
})) {
switch (event.type) {
case "audio":
console.log(`audio: ${event.audio.byteLength} bytes`);
break;
case "timestamps":
console.log(event.words);
break;
}
}
WebSocket
import { KovaTTSClient, pcm16ToWavBytes } from "@kova-ai/tts";
import { writeFile } from "node:fs/promises";
const client = new KovaTTSClient({ apiKey: process.env.KOVA_API_KEY! });
const sampleRate = 32000;
const pcmChunks: Uint8Array[] = [];
const ws = await client.connectWebSocket();
await ws.startContext({
contextId: "ctx-1",
voiceId: "cal",
modelId: "default",
responseFormat: { encoding: "pcm", sample_rate: sampleRate },
});
await ws.sendText("ctx-1", "Hello ");
await ws.sendText("ctx-1", "world.");
await ws.flush("ctx-1", "end");
for await (const frame of ws) {
if (frame.type === "audio") {
pcmChunks.push(frame.audio);
} else if (frame.type === "flush_completed" && frame.flush_id === "end") {
break;
}
}
await ws.closeContext("ctx-1");
ws.close();
const merged = concat(pcmChunks);
const wavBytes = pcm16ToWavBytes(merged, { sampleRate });
await writeFile("out.wav", wavBytes);
function concat(chunks: Uint8Array[]): Uint8Array {
const total = chunks.reduce((n, c) => n + c.byteLength, 0);
const out = new Uint8Array(total);
let offset = 0;
for (const c of chunks) { out.set(c, offset); offset += c.byteLength; }
return out;
}
Helpers
| Symbol | What it does |
|---|
client.writeAudioFile(audio, path) | Write decoded audio bytes to disk. |
decodeBase64ToBytes(value) | Top-level — decode a base64 string to Uint8Array. |
decodePcm16LeBase64(value) | Top-level — decode a base64 PCM16-LE chunk to Int16Array. |
pcm16ToWavBytes(pcm, { sampleRate, channels? }) | Top-level — wrap raw int16 PCM in a WAV header. Returns Uint8Array you write yourself with node:fs/promises. |
For listing voices, use raw HTTP — the SDK does not currently expose a listVoices method:
const resp = await fetch("https://api.kova.ai/v1/tts/speakers", {
headers: { "x-api-key": process.env.KOVA_API_KEY! },
});
const { speaker_ids } = await resp.json();
Errors
The SDK throws a KovaTTSError on non-2xx responses. The error carries the HTTP status and the parsed JSON body:
import { KovaTTSClient, KovaTTSError } from "@kova-ai/tts";
try {
await client.tts({ text: "hi", voice: "bad-voice" });
} catch (e) {
if (e instanceof KovaTTSError) {
console.log(e.status, e.body);
}
}
See Errors for the full status-code reference.
See also