myvoicemaker 0.1.0
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 +579 -0
- package/dist/index.cjs +469 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +280 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +455 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
# myvoicemaker
|
|
2
|
+
|
|
3
|
+
Official JavaScript / TypeScript SDK for the [VoiceMaker](https://myvoicemaker.ai) API.
|
|
4
|
+
|
|
5
|
+
Generate dialect-accurate speech, transcribe audio in Nigerian languages, create lip-sync animations, and more — all from a single, fully typed client.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/myvoicemaker)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Authentication](#authentication)
|
|
17
|
+
- [Supported Languages](#supported-languages)
|
|
18
|
+
- [Modules](#modules)
|
|
19
|
+
- [Text-to-Speech (TTS)](#text-to-speech-tts)
|
|
20
|
+
- [Automatic Speech Recognition (ASR)](#automatic-speech-recognition-asr)
|
|
21
|
+
- [Lip-Sync Animation](#lip-sync-animation)
|
|
22
|
+
- [Explain](#explain)
|
|
23
|
+
- [Usage & Billing](#usage--billing)
|
|
24
|
+
- [Error Handling](#error-handling)
|
|
25
|
+
- [Polling Async Jobs](#polling-async-jobs)
|
|
26
|
+
- [TypeScript](#typescript)
|
|
27
|
+
- [Rate Limits](#rate-limits)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install myvoicemaker
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires **Node.js 18+** (uses native `fetch`). No other runtime dependencies.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { VoiceMaker } from 'myvoicemaker';
|
|
45
|
+
|
|
46
|
+
const client = new VoiceMaker({ apiKey: 'vmk_live_...' });
|
|
47
|
+
|
|
48
|
+
// Generate speech
|
|
49
|
+
const tts = await client.tts.generate({
|
|
50
|
+
text: 'Bawo ni o se wa?',
|
|
51
|
+
voice_id: 'masoyinbo-male-conversational',
|
|
52
|
+
language: 'yo',
|
|
53
|
+
});
|
|
54
|
+
console.log(tts.audio_url);
|
|
55
|
+
|
|
56
|
+
// Transcribe an audio file
|
|
57
|
+
const job = await client.asr.transcribeFile('./sermon.mp3', { language: 'yo' });
|
|
58
|
+
const result = await client.asr.poll(job.job_id, { timeoutMs: 120_000 });
|
|
59
|
+
console.log(result.text);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Authentication
|
|
65
|
+
|
|
66
|
+
All requests require a developer API key passed as a Bearer token. Create and manage your keys from the [VoiceMaker Developer Dashboard](https://myvoicemaker.ai).
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const client = new VoiceMaker({ apiKey: 'vmk_live_...' });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
| Key environment | Prefix | Credits consumed |
|
|
73
|
+
| :--- | :--- | :--- |
|
|
74
|
+
| Production | `vmk_live_` | Yes |
|
|
75
|
+
| Test / Sandbox | `vmk_test_` | No |
|
|
76
|
+
|
|
77
|
+
**Keep your API key secret.** Use environment variables in production:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const client = new VoiceMaker({ apiKey: process.env.VOICEMAKER_API_KEY! });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Configuration options
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const client = new VoiceMaker({
|
|
87
|
+
apiKey: 'vmk_live_...',
|
|
88
|
+
baseUrl: 'https://api.myvoicemaker.ai', // default
|
|
89
|
+
timeoutMs: 30_000, // default: 30 seconds
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Supported Languages
|
|
96
|
+
|
|
97
|
+
| Language | Code | Auto-detect (ASR) |
|
|
98
|
+
| :--- | :--- | :---: |
|
|
99
|
+
| Yoruba | `yo` | ✓ |
|
|
100
|
+
| Igbo | `ig` | ✓ |
|
|
101
|
+
| Hausa | `ha` | ✓ |
|
|
102
|
+
| Nigerian Pidgin | `pcm` | ✓ |
|
|
103
|
+
| English | `en` | ✓ |
|
|
104
|
+
| Auto-detect | `auto` | — |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Modules
|
|
109
|
+
|
|
110
|
+
### Text-to-Speech (TTS)
|
|
111
|
+
|
|
112
|
+
Convert text into natural-sounding speech. Requests are **synchronous** — the audio URL is returned immediately.
|
|
113
|
+
|
|
114
|
+
#### `client.tts.listVoices(params?)`
|
|
115
|
+
|
|
116
|
+
Retrieve all available voices, optionally filtered by language.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const { voices } = await client.tts.listVoices({ language: 'yo' });
|
|
120
|
+
|
|
121
|
+
for (const voice of voices) {
|
|
122
|
+
console.log(`${voice.id} — ${voice.name} (${voice.gender}, ${voice.style})`);
|
|
123
|
+
console.log(` Sample: ${voice.sample_url}`);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Parameters**
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Description |
|
|
130
|
+
| :--- | :--- | :--- |
|
|
131
|
+
| `language` | `string` (optional) | Filter by language code: `yo`, `ig`, `ha`, `pcm`, `en` |
|
|
132
|
+
|
|
133
|
+
**Returns** `VoiceListResponse`
|
|
134
|
+
|
|
135
|
+
| Field | Type |
|
|
136
|
+
| :--- | :--- |
|
|
137
|
+
| `voices` | `Voice[]` |
|
|
138
|
+
|
|
139
|
+
Each `Voice` has: `id`, `name`, `gender`, `language`, `style`, `sample_url`.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
#### `client.tts.generate(params)`
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const result = await client.tts.generate({
|
|
147
|
+
text: 'Nne, ka anyị bido oge a.',
|
|
148
|
+
voice_id: 'sunday-okafor-male-conversational',
|
|
149
|
+
language: 'ig',
|
|
150
|
+
speed: 0.9,
|
|
151
|
+
output_format: 'mp3',
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
console.log(result.audio_url); // https://media.myvoicemaker.ai/...
|
|
155
|
+
console.log(result.duration_seconds); // e.g. 3.2
|
|
156
|
+
console.log(result.credits_used); // e.g. 28
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Parameters**
|
|
160
|
+
|
|
161
|
+
| Parameter | Type | Required | Description |
|
|
162
|
+
| :--- | :--- | :---: | :--- |
|
|
163
|
+
| `text` | `string` | ✓ | Text to synthesise (max 5,000 characters) |
|
|
164
|
+
| `voice_id` | `string` | ✓ | Voice identifier from `listVoices()` |
|
|
165
|
+
| `language` | `string` | ✓ | Language code |
|
|
166
|
+
| `speed` | `number` | | Playback speed: `0.5`–`2.0` (default `1.0`) |
|
|
167
|
+
| `output_format` | `string` | | `mp3` \| `wav` \| `ogg` (default `mp3`) |
|
|
168
|
+
|
|
169
|
+
**Returns** `TtsGenerateResponse`
|
|
170
|
+
|
|
171
|
+
| Field | Type |
|
|
172
|
+
| :--- | :--- |
|
|
173
|
+
| `id` | `string` |
|
|
174
|
+
| `audio_url` | `string` |
|
|
175
|
+
| `duration_seconds` | `number \| null` |
|
|
176
|
+
| `characters` | `number` |
|
|
177
|
+
| `credits_used` | `number` |
|
|
178
|
+
| `language` | `string` |
|
|
179
|
+
| `voice_id` | `string` |
|
|
180
|
+
| `created_at` | `string` (ISO 8601) |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### Automatic Speech Recognition (ASR)
|
|
185
|
+
|
|
186
|
+
Transcribe pre-recorded audio files. Jobs are **asynchronous** — submit a job, then poll for the result.
|
|
187
|
+
|
|
188
|
+
#### `client.asr.transcribe(params)` — from URL
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const job = await client.asr.transcribe({
|
|
192
|
+
audio: 'https://storage.example.com/interview.wav',
|
|
193
|
+
language: 'ha',
|
|
194
|
+
webhookUrl: 'https://myapp.com/webhooks/voicemaker',
|
|
195
|
+
});
|
|
196
|
+
console.log(job.job_id); // use this to poll
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Parameters**
|
|
200
|
+
|
|
201
|
+
| Parameter | Type | Required | Description |
|
|
202
|
+
| :--- | :--- | :---: | :--- |
|
|
203
|
+
| `audio` | `string` | ✓ | Publicly accessible URL of the audio file |
|
|
204
|
+
| `language` | `string` | | Language code or `auto` (default) |
|
|
205
|
+
| `webhookUrl` | `string` | | Callback URL when the job completes |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
#### `client.asr.transcribeFile(filePath, params?)` — from file
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const job = await client.asr.transcribeFile('./hausa-interview.mp3', {
|
|
213
|
+
language: 'ha',
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Parameters**
|
|
218
|
+
|
|
219
|
+
| Parameter | Type | Required | Description |
|
|
220
|
+
| :--- | :--- | :---: | :--- |
|
|
221
|
+
| `filePath` | `string` | ✓ | Absolute or relative path to the audio file |
|
|
222
|
+
| `language` | `string` | | Language code or `auto` (default) |
|
|
223
|
+
| `webhookUrl` | `string` | | Callback URL when the job completes |
|
|
224
|
+
|
|
225
|
+
Supported formats: `.mp3`, `.wav`, `.ogg`, `.m4a`, `.webm` — max 500 MB.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
#### `client.asr.getResult(jobId)`
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
const result = await client.asr.getResult('trans_1a2b3c...');
|
|
233
|
+
console.log(result.status); // 'queued' | 'processing' | 'completed' | 'failed'
|
|
234
|
+
console.log(result.text);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
#### `client.asr.list(params?)`
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
const page = await client.asr.list({ limit: 10, status: 'COMPLETED' });
|
|
243
|
+
|
|
244
|
+
for (const job of page.items) {
|
|
245
|
+
console.log(`${job.job_id}: ${job.text?.slice(0, 60)}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Load the next page
|
|
249
|
+
if (page.nextCursor) {
|
|
250
|
+
const next = await client.asr.list({ cursor: page.nextCursor });
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Parameters**
|
|
255
|
+
|
|
256
|
+
| Parameter | Type | Description |
|
|
257
|
+
| :--- | :--- | :--- |
|
|
258
|
+
| `limit` | `number` | Items per page: 1–100 (default `20`) |
|
|
259
|
+
| `cursor` | `string` | Pagination cursor from a previous response |
|
|
260
|
+
| `status` | `string` | Filter: `QUEUED` \| `PROCESSING` \| `COMPLETED` \| `FAILED` |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
#### `client.asr.poll(jobId, options?)` — wait for completion
|
|
265
|
+
|
|
266
|
+
Polls `getResult` at a regular interval until the job reaches a terminal state (`completed` or `failed`).
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const result = await client.asr.poll(job.job_id, {
|
|
270
|
+
intervalMs: 3_000, // poll every 3 seconds (default: 2 000)
|
|
271
|
+
timeoutMs: 120_000, // give up after 2 minutes (default: 120 000)
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
if (result.status === 'completed') {
|
|
275
|
+
console.log(`Transcript: ${result.text}`);
|
|
276
|
+
console.log(`Language detected: ${result.detected_language}`);
|
|
277
|
+
console.log(`Duration: ${result.duration_seconds}s`);
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Throws `TimeoutError` if `timeoutMs` is exceeded before the job completes.
|
|
282
|
+
|
|
283
|
+
**TranscriptionJob shape**
|
|
284
|
+
|
|
285
|
+
| Field | Type |
|
|
286
|
+
| :--- | :--- |
|
|
287
|
+
| `job_id` | `string` |
|
|
288
|
+
| `status` | `'queued' \| 'processing' \| 'completed' \| 'failed'` |
|
|
289
|
+
| `language` | `string` |
|
|
290
|
+
| `detected_language` | `string \| null` |
|
|
291
|
+
| `text` | `string \| null` |
|
|
292
|
+
| `confidence` | `number \| null` |
|
|
293
|
+
| `duration_seconds` | `number \| null` |
|
|
294
|
+
| `credits_used` | `number \| null` |
|
|
295
|
+
| `created_at` | `string` (ISO 8601) |
|
|
296
|
+
| `completed_at` | `string \| null` (ISO 8601) |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### Lip-Sync Animation
|
|
301
|
+
|
|
302
|
+
Generate a lip-sync video by combining a portrait image with an audio file. Jobs are **asynchronous**.
|
|
303
|
+
|
|
304
|
+
#### `client.animate.generate(params)`
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const job = await client.animate.generate({
|
|
308
|
+
image_url: 'https://example.com/speaker-portrait.jpg',
|
|
309
|
+
audio_url: tts.audio_url,
|
|
310
|
+
output_format: 'mp4',
|
|
311
|
+
});
|
|
312
|
+
console.log(job.job_id);
|
|
313
|
+
console.log(`Estimated credits: ${job.estimated_credits}`);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Parameters**
|
|
317
|
+
|
|
318
|
+
| Parameter | Type | Required | Description |
|
|
319
|
+
| :--- | :--- | :---: | :--- |
|
|
320
|
+
| `image_url` | `string` | ✓ | URL of the source portrait image (max 5 MB, up to 4K) |
|
|
321
|
+
| `audio_url` | `string` | ✓ | URL of the audio file (max 30 seconds) |
|
|
322
|
+
| `output_format` | `string` | | `mp4` \| `webm` (default `mp4`) |
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
#### `client.animate.getResult(jobId)`
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
const result = await client.animate.getResult('anim_1a2b3c...');
|
|
330
|
+
console.log(result.status); // 'queued' | 'processing' | 'completed' | 'failed'
|
|
331
|
+
console.log(result.video_url); // null until completed
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
#### `client.animate.poll(jobId, options?)`
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
const result = await client.animate.poll(job.job_id, {
|
|
340
|
+
intervalMs: 5_000,
|
|
341
|
+
timeoutMs: 300_000,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
if (result.status === 'completed') {
|
|
345
|
+
console.log(`Video: ${result.video_url}`);
|
|
346
|
+
console.log(`Duration: ${result.duration_seconds}s`);
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
### Explain
|
|
353
|
+
|
|
354
|
+
Process text in Nigerian languages — explain, summarise, translate, or simplify content using AI.
|
|
355
|
+
|
|
356
|
+
> **Note:** This module targets a planned endpoint. Check the [changelog](https://myvoicemaker.ai/docs/changelog) for availability.
|
|
357
|
+
|
|
358
|
+
#### `client.explain.process(params)`
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
const result = await client.explain.process({
|
|
362
|
+
text: 'Ìwé Mímọ̀ sọ pé...',
|
|
363
|
+
language: 'yo',
|
|
364
|
+
action: 'translate',
|
|
365
|
+
target_language: 'en',
|
|
366
|
+
max_tokens: 500,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
console.log(result.result); // translated text
|
|
370
|
+
console.log(result.tokens_used); // e.g. 145
|
|
371
|
+
console.log(result.credits_used); // e.g. 145
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Parameters**
|
|
375
|
+
|
|
376
|
+
| Parameter | Type | Required | Description |
|
|
377
|
+
| :--- | :--- | :---: | :--- |
|
|
378
|
+
| `text` | `string` | ✓ | Input text to process |
|
|
379
|
+
| `language` | `string` | ✓ | Source language code |
|
|
380
|
+
| `action` | `string` | ✓ | `explain` \| `summarize` \| `translate` \| `simplify` |
|
|
381
|
+
| `target_language` | `string` | | Required when `action` is `translate` |
|
|
382
|
+
| `max_tokens` | `number` | | Response length limit: 1–2000 (default `500`) |
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### Usage & Billing
|
|
387
|
+
|
|
388
|
+
#### `client.usage.getBalance()`
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
const balance = await client.usage.getBalance();
|
|
392
|
+
|
|
393
|
+
console.log(`Tier: ${balance.tier}`);
|
|
394
|
+
console.log(`Credits remaining: ${balance.credits_remaining.toLocaleString()}`);
|
|
395
|
+
console.log(`Credits used: ${balance.credits_used.toLocaleString()}`);
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Returns** `UsageBalanceResponse`
|
|
399
|
+
|
|
400
|
+
| Field | Type |
|
|
401
|
+
| :--- | :--- |
|
|
402
|
+
| `account_id` | `string` |
|
|
403
|
+
| `tier` | `'free' \| 'starter' \| 'growth' \| 'pro' \| 'enterprise'` |
|
|
404
|
+
| `credits_remaining` | `number` |
|
|
405
|
+
| `credits_used` | `number` |
|
|
406
|
+
| `credits_total` | `number` (present only if credits were ever purchased) |
|
|
407
|
+
| `credits_expire` | `string \| null` |
|
|
408
|
+
| `created_at` | `string` (ISO 8601) |
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
#### `client.usage.getBreakdown(params)`
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
const report = await client.usage.getBreakdown({
|
|
416
|
+
start_date: '2026-05-01T00:00:00Z',
|
|
417
|
+
end_date: '2026-05-31T23:59:59Z',
|
|
418
|
+
module: 'asr', // optional filter
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
for (const entry of report.breakdown) {
|
|
422
|
+
console.log(`${entry.module}: ${entry.requests} requests, ${entry.credits_used} credits`);
|
|
423
|
+
}
|
|
424
|
+
console.log(`Total: ${report.total_credits_used} credits`);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Parameters**
|
|
428
|
+
|
|
429
|
+
| Parameter | Type | Required | Description |
|
|
430
|
+
| :--- | :--- | :---: | :--- |
|
|
431
|
+
| `start_date` | `string` | ✓ | ISO 8601 datetime (inclusive) |
|
|
432
|
+
| `end_date` | `string` | ✓ | ISO 8601 datetime (inclusive) |
|
|
433
|
+
| `module` | `string` | | Filter: `tts` \| `asr` \| `animate` \| `explain` |
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Error Handling
|
|
438
|
+
|
|
439
|
+
Every API error is thrown as a typed exception that extends `VoiceMakerAPIError`.
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import {
|
|
443
|
+
VoiceMakerError,
|
|
444
|
+
AuthenticationError,
|
|
445
|
+
InsufficientCreditsError,
|
|
446
|
+
RateLimitError,
|
|
447
|
+
ValidationError,
|
|
448
|
+
NotFoundError,
|
|
449
|
+
TimeoutError,
|
|
450
|
+
} from 'myvoicemaker';
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
const result = await client.tts.generate({ ... });
|
|
454
|
+
} catch (err) {
|
|
455
|
+
if (err instanceof AuthenticationError) {
|
|
456
|
+
console.error('Invalid or expired API key');
|
|
457
|
+
} else if (err instanceof InsufficientCreditsError) {
|
|
458
|
+
console.error('Not enough credits. Top up at myvoicemaker.ai/billing');
|
|
459
|
+
} else if (err instanceof RateLimitError) {
|
|
460
|
+
const wait = err.retryAfter ?? 60;
|
|
461
|
+
console.error(`Rate limited. Retry in ${wait}s`);
|
|
462
|
+
} else if (err instanceof ValidationError) {
|
|
463
|
+
console.error('Invalid parameters:', err.issues);
|
|
464
|
+
} else if (err instanceof TimeoutError) {
|
|
465
|
+
console.error(`Job ${err.jobId} timed out after ${err.timeoutMs}ms`);
|
|
466
|
+
} else if (err instanceof VoiceMakerError) {
|
|
467
|
+
console.error(`API error ${err.status}: ${err.detail}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Error classes
|
|
473
|
+
|
|
474
|
+
| Class | HTTP Status | Description |
|
|
475
|
+
| :--- | :--- | :--- |
|
|
476
|
+
| `AuthenticationError` | 401 | Missing or invalid API key |
|
|
477
|
+
| `InsufficientCreditsError` | 402 | Insufficient purchased credits |
|
|
478
|
+
| `PermissionError` | 403 | Key lacks required scope or plan |
|
|
479
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
480
|
+
| `FileSizeLimitError` | 413 | Audio file exceeds plan size limit |
|
|
481
|
+
| `UnsupportedMediaTypeError` | 415 | Unsupported file format |
|
|
482
|
+
| `ValidationError` | 422 | Invalid request parameters (check `.issues`) |
|
|
483
|
+
| `RateLimitError` | 429 | Rate limit or concurrency limit exceeded |
|
|
484
|
+
| `ServerError` | 500/503 | Internal server error |
|
|
485
|
+
| `TimeoutError` | — | `poll()` timed out waiting for job completion |
|
|
486
|
+
|
|
487
|
+
All HTTP error classes expose:
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
err.status // HTTP status code
|
|
491
|
+
err.error // Short error title from the API
|
|
492
|
+
err.detail // Human-readable explanation
|
|
493
|
+
err.requestId // Request ID for support (from X-Request-Id header)
|
|
494
|
+
err.issues // Validation issues array (ValidationError only)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Polling Async Jobs
|
|
500
|
+
|
|
501
|
+
ASR and Animation jobs are processed asynchronously. The SDK's `poll()` helper handles the retry loop for you:
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
// Submit
|
|
505
|
+
const job = await client.asr.transcribeFile('./audio.mp3', { language: 'en' });
|
|
506
|
+
|
|
507
|
+
// Poll until done
|
|
508
|
+
const result = await client.asr.poll(job.job_id, {
|
|
509
|
+
intervalMs: 2_000, // how often to check (default: 2 000 ms)
|
|
510
|
+
timeoutMs: 120_000, // maximum wait time (default: 120 000 ms)
|
|
511
|
+
});
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Alternatively, manage polling manually:
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
let result = await client.asr.getResult(job.job_id);
|
|
518
|
+
|
|
519
|
+
while (result.status === 'queued' || result.status === 'processing') {
|
|
520
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
521
|
+
result = await client.asr.getResult(job.job_id);
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## TypeScript
|
|
528
|
+
|
|
529
|
+
The SDK is written in TypeScript and ships with full type declarations. No additional `@types` packages are needed.
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
import type {
|
|
533
|
+
VoiceMakerConfig,
|
|
534
|
+
TranscriptionJob,
|
|
535
|
+
TtsGenerateResponse,
|
|
536
|
+
AnimateResultResponse,
|
|
537
|
+
VoiceListResponse,
|
|
538
|
+
Voice,
|
|
539
|
+
UsageBalanceResponse,
|
|
540
|
+
SupportedLanguage,
|
|
541
|
+
JobStatus,
|
|
542
|
+
PollOptions,
|
|
543
|
+
} from 'myvoicemaker';
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
All response objects, request parameters, error classes, and union literals are exported directly from the package root.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Rate Limits
|
|
551
|
+
|
|
552
|
+
Rate limits are enforced per API key and vary by plan:
|
|
553
|
+
|
|
554
|
+
| Plan | Requests / min | Concurrent jobs |
|
|
555
|
+
| :--- | :--- | :--- |
|
|
556
|
+
| Growth | 60 | 5 |
|
|
557
|
+
| Pro | 120 | 10 |
|
|
558
|
+
| Enterprise | Custom | Custom |
|
|
559
|
+
|
|
560
|
+
When a limit is exceeded the SDK throws `RateLimitError`. The `Retry-After` header value (seconds) is available as `err.retryAfter`.
|
|
561
|
+
|
|
562
|
+
Each API response also includes rate limit metadata in the response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`).
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## Credit Costs
|
|
567
|
+
|
|
568
|
+
| Module | Billable unit | Cost |
|
|
569
|
+
| :--- | :--- | :--- |
|
|
570
|
+
| TTS | Input characters | 1 credit / character |
|
|
571
|
+
| ASR | Audio duration | 5 credits / second |
|
|
572
|
+
| Animate | Video duration | 50 credits / second |
|
|
573
|
+
| Explain | LLM tokens | 1 credit / token |
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## License
|
|
578
|
+
|
|
579
|
+
MIT © [Collins Edim](https://github.com/equalyzai)
|