naijalingo 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/index.cjs +40 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -4
- package/dist/index.d.ts +22 -4
- package/dist/index.js +39 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -145,6 +145,14 @@ const audio = await client.tts.clone(
|
|
|
145
145
|
);
|
|
146
146
|
await audio.save("cloned.mp3");
|
|
147
147
|
|
|
148
|
+
// The backend persists the clone and returns a reusable voice ID.
|
|
149
|
+
const greeting = await client.tts.generate("Nnoo, kedu ka i mere?", {
|
|
150
|
+
voice: audio.voiceId,
|
|
151
|
+
});
|
|
152
|
+
await greeting.save("cloned_voice_greeting.wav");
|
|
153
|
+
|
|
154
|
+
// `speaker: audio.voiceId` is equivalent.
|
|
155
|
+
|
|
148
156
|
// From a Buffer
|
|
149
157
|
import { readFileSync } from "node:fs";
|
|
150
158
|
const buf = readFileSync("reference.wav");
|
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
AudioResponse: () => AudioResponse,
|
|
24
24
|
AudioStream: () => AudioStream,
|
|
25
25
|
AuthenticationError: () => AuthenticationError,
|
|
26
|
+
CloneResponse: () => CloneResponse,
|
|
26
27
|
ConnectionError: () => ConnectionError,
|
|
27
28
|
InferenceCapacityError: () => InferenceCapacityError,
|
|
28
29
|
NaijaLingo: () => NaijaLingo,
|
|
@@ -97,7 +98,7 @@ var BaseClient = class {
|
|
|
97
98
|
this.baseUrl = base.replace(/\/+$/, "");
|
|
98
99
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
99
100
|
this.defaultHeaders = {
|
|
100
|
-
"User-Agent": "naijalingo-js/0.1.
|
|
101
|
+
"User-Agent": "naijalingo-js/0.1.2"
|
|
101
102
|
};
|
|
102
103
|
if (this.apiKey) {
|
|
103
104
|
this.defaultHeaders["X-API-Key"] = this.apiKey;
|
|
@@ -253,12 +254,14 @@ var BaseClient = class {
|
|
|
253
254
|
);
|
|
254
255
|
}
|
|
255
256
|
async postMultipart(path, form, timeoutMs) {
|
|
256
|
-
|
|
257
|
+
return this.request("POST", path, {
|
|
257
258
|
body: form,
|
|
258
259
|
timeoutMs: timeoutMs ?? Math.max(this.timeout, 6e5)
|
|
259
260
|
// Let fetch set multipart boundary — do not set Content-Type
|
|
260
261
|
});
|
|
261
|
-
|
|
262
|
+
}
|
|
263
|
+
async delete(path) {
|
|
264
|
+
await this.request("DELETE", path);
|
|
262
265
|
}
|
|
263
266
|
};
|
|
264
267
|
function sleep(ms) {
|
|
@@ -491,6 +494,21 @@ var AudioResponse = class {
|
|
|
491
494
|
return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;
|
|
492
495
|
}
|
|
493
496
|
};
|
|
497
|
+
var CloneResponse = class extends AudioResponse {
|
|
498
|
+
voiceId;
|
|
499
|
+
voiceCode;
|
|
500
|
+
voiceName;
|
|
501
|
+
cloneId;
|
|
502
|
+
jobId;
|
|
503
|
+
constructor(content, mediaType, metadata) {
|
|
504
|
+
super(content, mediaType);
|
|
505
|
+
this.voiceId = metadata.voiceId;
|
|
506
|
+
this.voiceCode = metadata.voiceCode;
|
|
507
|
+
this.voiceName = metadata.voiceName;
|
|
508
|
+
this.cloneId = metadata.cloneId;
|
|
509
|
+
this.jobId = metadata.jobId;
|
|
510
|
+
}
|
|
511
|
+
};
|
|
494
512
|
var AudioStream = class {
|
|
495
513
|
chunks;
|
|
496
514
|
collected = null;
|
|
@@ -603,9 +621,16 @@ var TTS = class {
|
|
|
603
621
|
}
|
|
604
622
|
const { blob, filename } = await toAudioBlob(audioFile);
|
|
605
623
|
form.append("audio", blob, filename);
|
|
606
|
-
const
|
|
624
|
+
const response = await this.client.postMultipart("/v1/audio/clone", form);
|
|
625
|
+
const content = new Uint8Array(await response.arrayBuffer());
|
|
607
626
|
const mediaType = MEDIA_TYPES[responseFormat] ?? "application/octet-stream";
|
|
608
|
-
return new
|
|
627
|
+
return new CloneResponse(content, mediaType, {
|
|
628
|
+
voiceId: response.headers.get("X-Voice-ID"),
|
|
629
|
+
voiceCode: response.headers.get("X-Voice-Code"),
|
|
630
|
+
voiceName: response.headers.get("X-Voice-Name"),
|
|
631
|
+
cloneId: response.headers.get("X-Clone-ID"),
|
|
632
|
+
jobId: response.headers.get("X-Job-ID")
|
|
633
|
+
});
|
|
609
634
|
}
|
|
610
635
|
async listSpeakers(options = {}) {
|
|
611
636
|
const data = await this.client.getJson("/v1/speakers", {
|
|
@@ -619,6 +644,14 @@ var TTS = class {
|
|
|
619
644
|
const data = await this.client.getJson(`/v1/speakers/${speakerId}`);
|
|
620
645
|
return speakerFromDict(data);
|
|
621
646
|
}
|
|
647
|
+
/** Permanently delete a cloned voice owned by this API key. */
|
|
648
|
+
async deleteVoice(voiceId) {
|
|
649
|
+
const normalizedVoiceId = voiceId.trim();
|
|
650
|
+
if (!normalizedVoiceId) {
|
|
651
|
+
throw new Error("voiceId is required");
|
|
652
|
+
}
|
|
653
|
+
await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);
|
|
654
|
+
}
|
|
622
655
|
async listLanguages() {
|
|
623
656
|
const data = await this.client.getJson("/v1/languages");
|
|
624
657
|
return languageListFromDict(data);
|
|
@@ -677,7 +710,7 @@ function guessMime(filename) {
|
|
|
677
710
|
}
|
|
678
711
|
|
|
679
712
|
// src/index.ts
|
|
680
|
-
var VERSION = "0.1.
|
|
713
|
+
var VERSION = "0.1.2";
|
|
681
714
|
var NaijaLingo = class {
|
|
682
715
|
_client;
|
|
683
716
|
tts;
|
|
@@ -706,6 +739,7 @@ var NaijaLingo = class {
|
|
|
706
739
|
AudioResponse,
|
|
707
740
|
AudioStream,
|
|
708
741
|
AuthenticationError,
|
|
742
|
+
CloneResponse,
|
|
709
743
|
ConnectionError,
|
|
710
744
|
InferenceCapacityError,
|
|
711
745
|
NaijaLingo,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts"],"sourcesContent":["/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.1\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n","/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.1\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<AudioResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const content = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n"],"mappings":"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","names":["bytes"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts"],"sourcesContent":["/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n","/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n\n async delete(path: string): Promise<void> {\n await this.request(\"DELETE\", path);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n /** Permanently delete a cloned voice owned by this API key. */\n async deleteVoice(voiceId: string): Promise<void> {\n const normalizedVoiceId = voiceId.trim();\n if (!normalizedVoiceId) {\n throw new Error(\"voiceId is required\");\n }\n await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n"],"mappings":"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","names":["bytes"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -15,7 +15,8 @@ declare class BaseClient {
|
|
|
15
15
|
getJson(path: string, params?: Record<string, string | undefined | null>): Promise<Record<string, unknown>>;
|
|
16
16
|
postBytes(path: string, body: Record<string, unknown>): Promise<Uint8Array>;
|
|
17
17
|
postStream(path: string, body: Record<string, unknown>): AsyncGenerator<Uint8Array, void, unknown>;
|
|
18
|
-
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<
|
|
18
|
+
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<Response>;
|
|
19
|
+
delete(path: string): Promise<void>;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/** A speaker voice identity. */
|
|
@@ -126,6 +127,21 @@ declare class AudioResponse {
|
|
|
126
127
|
get length(): number;
|
|
127
128
|
toString(): string;
|
|
128
129
|
}
|
|
130
|
+
/** Audio and reusable voice metadata returned from a clone request. */
|
|
131
|
+
declare class CloneResponse extends AudioResponse {
|
|
132
|
+
readonly voiceId: string | null;
|
|
133
|
+
readonly voiceCode: string | null;
|
|
134
|
+
readonly voiceName: string | null;
|
|
135
|
+
readonly cloneId: string | null;
|
|
136
|
+
readonly jobId: string | null;
|
|
137
|
+
constructor(content: Uint8Array, mediaType: string, metadata: {
|
|
138
|
+
voiceId: string | null;
|
|
139
|
+
voiceCode: string | null;
|
|
140
|
+
voiceName: string | null;
|
|
141
|
+
cloneId: string | null;
|
|
142
|
+
jobId: string | null;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
129
145
|
/** Streaming audio response — yields byte chunks as they arrive. */
|
|
130
146
|
declare class AudioStream implements AsyncIterable<Uint8Array> {
|
|
131
147
|
private readonly chunks;
|
|
@@ -146,9 +162,11 @@ declare class TTS {
|
|
|
146
162
|
* Generate speech using a cloned voice from a reference audio file.
|
|
147
163
|
* `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.
|
|
148
164
|
*/
|
|
149
|
-
clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<
|
|
165
|
+
clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<CloneResponse>;
|
|
150
166
|
listSpeakers(options?: ListSpeakersOptions): Promise<SpeakerList>;
|
|
151
167
|
getSpeaker(speakerId: string): Promise<Speaker>;
|
|
168
|
+
/** Permanently delete a cloned voice owned by this API key. */
|
|
169
|
+
deleteVoice(voiceId: string): Promise<void>;
|
|
152
170
|
listLanguages(): Promise<LanguageList>;
|
|
153
171
|
health(): Promise<HealthStatus>;
|
|
154
172
|
}
|
|
@@ -202,7 +220,7 @@ declare class ConnectionError extends NaijaLingoError {
|
|
|
202
220
|
* ```
|
|
203
221
|
*/
|
|
204
222
|
|
|
205
|
-
declare const VERSION = "0.1.
|
|
223
|
+
declare const VERSION = "0.1.2";
|
|
206
224
|
|
|
207
225
|
declare class NaijaLingo {
|
|
208
226
|
private readonly _client;
|
|
@@ -216,4 +234,4 @@ declare class NaijaLingo {
|
|
|
216
234
|
serviceInfo(): Promise<ServiceInfo>;
|
|
217
235
|
}
|
|
218
236
|
|
|
219
|
-
export { type APIInfo, AudioResponse, AudioStream, AuthenticationError, type ClientOptions, type CloneOptions, ConnectionError, type GenerateOptions, type HealthStatus, InferenceCapacityError, type Language, type LanguageList, type ListSpeakersOptions, type Model, type ModelList, NaijaLingo, NaijaLingoError, NotFoundError, RateLimitError, type ResponseFormat, ServerError, type ServiceInfo, type Speaker, type SpeakerList, type StreamOptions, TTS, VERSION };
|
|
237
|
+
export { type APIInfo, AudioResponse, AudioStream, AuthenticationError, type ClientOptions, type CloneOptions, CloneResponse, ConnectionError, type GenerateOptions, type HealthStatus, InferenceCapacityError, type Language, type LanguageList, type ListSpeakersOptions, type Model, type ModelList, NaijaLingo, NaijaLingoError, NotFoundError, RateLimitError, type ResponseFormat, ServerError, type ServiceInfo, type Speaker, type SpeakerList, type StreamOptions, TTS, VERSION };
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ declare class BaseClient {
|
|
|
15
15
|
getJson(path: string, params?: Record<string, string | undefined | null>): Promise<Record<string, unknown>>;
|
|
16
16
|
postBytes(path: string, body: Record<string, unknown>): Promise<Uint8Array>;
|
|
17
17
|
postStream(path: string, body: Record<string, unknown>): AsyncGenerator<Uint8Array, void, unknown>;
|
|
18
|
-
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<
|
|
18
|
+
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<Response>;
|
|
19
|
+
delete(path: string): Promise<void>;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/** A speaker voice identity. */
|
|
@@ -126,6 +127,21 @@ declare class AudioResponse {
|
|
|
126
127
|
get length(): number;
|
|
127
128
|
toString(): string;
|
|
128
129
|
}
|
|
130
|
+
/** Audio and reusable voice metadata returned from a clone request. */
|
|
131
|
+
declare class CloneResponse extends AudioResponse {
|
|
132
|
+
readonly voiceId: string | null;
|
|
133
|
+
readonly voiceCode: string | null;
|
|
134
|
+
readonly voiceName: string | null;
|
|
135
|
+
readonly cloneId: string | null;
|
|
136
|
+
readonly jobId: string | null;
|
|
137
|
+
constructor(content: Uint8Array, mediaType: string, metadata: {
|
|
138
|
+
voiceId: string | null;
|
|
139
|
+
voiceCode: string | null;
|
|
140
|
+
voiceName: string | null;
|
|
141
|
+
cloneId: string | null;
|
|
142
|
+
jobId: string | null;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
129
145
|
/** Streaming audio response — yields byte chunks as they arrive. */
|
|
130
146
|
declare class AudioStream implements AsyncIterable<Uint8Array> {
|
|
131
147
|
private readonly chunks;
|
|
@@ -146,9 +162,11 @@ declare class TTS {
|
|
|
146
162
|
* Generate speech using a cloned voice from a reference audio file.
|
|
147
163
|
* `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.
|
|
148
164
|
*/
|
|
149
|
-
clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<
|
|
165
|
+
clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<CloneResponse>;
|
|
150
166
|
listSpeakers(options?: ListSpeakersOptions): Promise<SpeakerList>;
|
|
151
167
|
getSpeaker(speakerId: string): Promise<Speaker>;
|
|
168
|
+
/** Permanently delete a cloned voice owned by this API key. */
|
|
169
|
+
deleteVoice(voiceId: string): Promise<void>;
|
|
152
170
|
listLanguages(): Promise<LanguageList>;
|
|
153
171
|
health(): Promise<HealthStatus>;
|
|
154
172
|
}
|
|
@@ -202,7 +220,7 @@ declare class ConnectionError extends NaijaLingoError {
|
|
|
202
220
|
* ```
|
|
203
221
|
*/
|
|
204
222
|
|
|
205
|
-
declare const VERSION = "0.1.
|
|
223
|
+
declare const VERSION = "0.1.2";
|
|
206
224
|
|
|
207
225
|
declare class NaijaLingo {
|
|
208
226
|
private readonly _client;
|
|
@@ -216,4 +234,4 @@ declare class NaijaLingo {
|
|
|
216
234
|
serviceInfo(): Promise<ServiceInfo>;
|
|
217
235
|
}
|
|
218
236
|
|
|
219
|
-
export { type APIInfo, AudioResponse, AudioStream, AuthenticationError, type ClientOptions, type CloneOptions, ConnectionError, type GenerateOptions, type HealthStatus, InferenceCapacityError, type Language, type LanguageList, type ListSpeakersOptions, type Model, type ModelList, NaijaLingo, NaijaLingoError, NotFoundError, RateLimitError, type ResponseFormat, ServerError, type ServiceInfo, type Speaker, type SpeakerList, type StreamOptions, TTS, VERSION };
|
|
237
|
+
export { type APIInfo, AudioResponse, AudioStream, AuthenticationError, type ClientOptions, type CloneOptions, CloneResponse, ConnectionError, type GenerateOptions, type HealthStatus, InferenceCapacityError, type Language, type LanguageList, type ListSpeakersOptions, type Model, type ModelList, NaijaLingo, NaijaLingoError, NotFoundError, RateLimitError, type ResponseFormat, ServerError, type ServiceInfo, type Speaker, type SpeakerList, type StreamOptions, TTS, VERSION };
|
package/dist/index.js
CHANGED
|
@@ -60,7 +60,7 @@ var BaseClient = class {
|
|
|
60
60
|
this.baseUrl = base.replace(/\/+$/, "");
|
|
61
61
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
62
62
|
this.defaultHeaders = {
|
|
63
|
-
"User-Agent": "naijalingo-js/0.1.
|
|
63
|
+
"User-Agent": "naijalingo-js/0.1.2"
|
|
64
64
|
};
|
|
65
65
|
if (this.apiKey) {
|
|
66
66
|
this.defaultHeaders["X-API-Key"] = this.apiKey;
|
|
@@ -216,12 +216,14 @@ var BaseClient = class {
|
|
|
216
216
|
);
|
|
217
217
|
}
|
|
218
218
|
async postMultipart(path, form, timeoutMs) {
|
|
219
|
-
|
|
219
|
+
return this.request("POST", path, {
|
|
220
220
|
body: form,
|
|
221
221
|
timeoutMs: timeoutMs ?? Math.max(this.timeout, 6e5)
|
|
222
222
|
// Let fetch set multipart boundary — do not set Content-Type
|
|
223
223
|
});
|
|
224
|
-
|
|
224
|
+
}
|
|
225
|
+
async delete(path) {
|
|
226
|
+
await this.request("DELETE", path);
|
|
225
227
|
}
|
|
226
228
|
};
|
|
227
229
|
function sleep(ms) {
|
|
@@ -454,6 +456,21 @@ var AudioResponse = class {
|
|
|
454
456
|
return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;
|
|
455
457
|
}
|
|
456
458
|
};
|
|
459
|
+
var CloneResponse = class extends AudioResponse {
|
|
460
|
+
voiceId;
|
|
461
|
+
voiceCode;
|
|
462
|
+
voiceName;
|
|
463
|
+
cloneId;
|
|
464
|
+
jobId;
|
|
465
|
+
constructor(content, mediaType, metadata) {
|
|
466
|
+
super(content, mediaType);
|
|
467
|
+
this.voiceId = metadata.voiceId;
|
|
468
|
+
this.voiceCode = metadata.voiceCode;
|
|
469
|
+
this.voiceName = metadata.voiceName;
|
|
470
|
+
this.cloneId = metadata.cloneId;
|
|
471
|
+
this.jobId = metadata.jobId;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
457
474
|
var AudioStream = class {
|
|
458
475
|
chunks;
|
|
459
476
|
collected = null;
|
|
@@ -566,9 +583,16 @@ var TTS = class {
|
|
|
566
583
|
}
|
|
567
584
|
const { blob, filename } = await toAudioBlob(audioFile);
|
|
568
585
|
form.append("audio", blob, filename);
|
|
569
|
-
const
|
|
586
|
+
const response = await this.client.postMultipart("/v1/audio/clone", form);
|
|
587
|
+
const content = new Uint8Array(await response.arrayBuffer());
|
|
570
588
|
const mediaType = MEDIA_TYPES[responseFormat] ?? "application/octet-stream";
|
|
571
|
-
return new
|
|
589
|
+
return new CloneResponse(content, mediaType, {
|
|
590
|
+
voiceId: response.headers.get("X-Voice-ID"),
|
|
591
|
+
voiceCode: response.headers.get("X-Voice-Code"),
|
|
592
|
+
voiceName: response.headers.get("X-Voice-Name"),
|
|
593
|
+
cloneId: response.headers.get("X-Clone-ID"),
|
|
594
|
+
jobId: response.headers.get("X-Job-ID")
|
|
595
|
+
});
|
|
572
596
|
}
|
|
573
597
|
async listSpeakers(options = {}) {
|
|
574
598
|
const data = await this.client.getJson("/v1/speakers", {
|
|
@@ -582,6 +606,14 @@ var TTS = class {
|
|
|
582
606
|
const data = await this.client.getJson(`/v1/speakers/${speakerId}`);
|
|
583
607
|
return speakerFromDict(data);
|
|
584
608
|
}
|
|
609
|
+
/** Permanently delete a cloned voice owned by this API key. */
|
|
610
|
+
async deleteVoice(voiceId) {
|
|
611
|
+
const normalizedVoiceId = voiceId.trim();
|
|
612
|
+
if (!normalizedVoiceId) {
|
|
613
|
+
throw new Error("voiceId is required");
|
|
614
|
+
}
|
|
615
|
+
await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);
|
|
616
|
+
}
|
|
585
617
|
async listLanguages() {
|
|
586
618
|
const data = await this.client.getJson("/v1/languages");
|
|
587
619
|
return languageListFromDict(data);
|
|
@@ -640,7 +672,7 @@ function guessMime(filename) {
|
|
|
640
672
|
}
|
|
641
673
|
|
|
642
674
|
// src/index.ts
|
|
643
|
-
var VERSION = "0.1.
|
|
675
|
+
var VERSION = "0.1.2";
|
|
644
676
|
var NaijaLingo = class {
|
|
645
677
|
_client;
|
|
646
678
|
tts;
|
|
@@ -668,6 +700,7 @@ export {
|
|
|
668
700
|
AudioResponse,
|
|
669
701
|
AudioStream,
|
|
670
702
|
AuthenticationError,
|
|
703
|
+
CloneResponse,
|
|
671
704
|
ConnectionError,
|
|
672
705
|
InferenceCapacityError,
|
|
673
706
|
NaijaLingo,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.1\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<AudioResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const content = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n","/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.1\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n"],"mappings":"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","names":["bytes"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n\n async delete(path: string): Promise<void> {\n await this.request(\"DELETE\", path);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n /** Permanently delete a cloned voice owned by this API key. */\n async deleteVoice(voiceId: string): Promise<void> {\n const normalizedVoiceId = voiceId.trim();\n if (!normalizedVoiceId) {\n throw new Error(\"voiceId is required\");\n }\n await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n","/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n"],"mappings":"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","names":["bytes"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naijalingo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Official Node.js SDK for 9jaLingo — AI-powered Text-to-Speech and Voice Cloning for Nigerian languages including Hausa, Igbo, Yoruba, and Nigerian Pidgin with 240+ speaker voices.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "9jaLingo <support@9jalingo.org>",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
|
+
"test": "npm run build && node --test test/**/*.test.mjs",
|
|
55
56
|
"prepublishOnly": "npm run build"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|