@transcribe-api/sdk 0.1.3 → 0.1.5

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.
Files changed (4) hide show
  1. package/README.md +389 -54
  2. package/index.js +1143 -1354
  3. package/package.json +1 -1
  4. package/worker.js +543 -296
package/README.md CHANGED
@@ -1,75 +1,410 @@
1
- # Transcribe API JavaScript SDK
2
-
3
- Official JavaScript SDK for Transcribe API.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @transcribe-api/sdk
9
- ```
10
-
11
- ## Usage
12
-
1
+ # Transcribe API JavaScript SDK
2
+
3
+ Official JavaScript SDK for Transcribe API.
4
+
5
+ Use this SDK to send one file, many files, local uploads, remote audio URLs, webhook jobs, and large multipart uploads to the Transcribe API from Node.js and modern JavaScript runtimes.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @transcribe-api/sdk
11
+ ```
12
+
13
+ ## Import
14
+
15
+ ```js
16
+ import { TranscribeAPI, TranscribeAPIError } from "@transcribe-api/sdk";
17
+ ```
18
+
19
+ The default export is also `TranscribeAPI`:
20
+
21
+ ```js
22
+ import TranscribeAPI from "@transcribe-api/sdk";
23
+ ```
24
+
25
+ ## Quick start
26
+
13
27
  ```js
14
28
  import { TranscribeAPI } from "@transcribe-api/sdk";
15
-
29
+
30
+ const client = new TranscribeAPI({
31
+ apiKey: process.env.TRANSCRIBE_API_KEY,
32
+ polling: {
33
+ interval: 10,
34
+ timeout: 15 * 60,
35
+ },
36
+ });
37
+
38
+ const result = await client.transcribe({
39
+ language: "en",
40
+ files: [
41
+ { reference_id: "meeting_001", file: "./meeting.mp3" },
42
+ ],
43
+ });
44
+
45
+ console.log(result);
46
+ ```
47
+
48
+ `client.transcribe({ files: [...] })` is the main API for both single-file and multi-file transcription.
49
+
50
+ ## How `transcribe` routes work
51
+
52
+ The SDK automatically chooses the right API flow:
53
+
54
+ - One small local file is sent through the direct synchronous upload path.
55
+ - Remote URLs, webhook jobs, multiple files, files larger than 30 MB, and files estimated over 10 minutes are sent through the async job flow.
56
+ - Large local async uploads use signed R2 upload URLs returned by the API.
57
+ - Multipart upload is used automatically when the backend returns multipart upload instructions.
58
+ - If `polling` is configured, async calls wait until the job reaches a terminal status.
59
+ - If `polling` is not configured, async calls return the upload-completion/job response. Use `client.jobs.get(job_id)` or `client.waitForJobCompletion(job_id, ...)` to check later.
60
+
61
+ Terminal job statuses are `completed`, `failed`, and `insufficient_funds`. Completed job responses include `result_url` when the API has a result file ready.
62
+
63
+ ## Client options
64
+
65
+ ```js
16
66
  const client = new TranscribeAPI({
17
67
  apiKey: "YOUR_API_KEY",
68
+ baseUrl: "https://api.transcribeapi.com/v1",
69
+ uploadConcurrency: 4,
18
70
  showLogs: true,
71
+ logger: console,
19
72
  polling: {
20
73
  interval: 10,
21
74
  timeout: 15 * 60,
22
75
  },
23
76
  });
24
-
25
- const transcript = await client.transcribe({
26
- file: "audio.mp3",
27
- });
28
-
29
- const asyncJob = await client.transcribe({
30
- file: "long-audio.mp3",
31
- multipartConcurrency: 8,
32
- });
33
-
34
- const batchJob = await client.batch.transcribe({
77
+ ```
78
+
79
+ | Option | Description |
80
+ | --- | --- |
81
+ | `apiKey` | Required. Your Transcribe API key. |
82
+ | `baseUrl` | Optional. Defaults to `https://api.transcribeapi.com/v1`. |
83
+ | `uploadConcurrency` | Optional. Number of in-flight upload PUTs. Defaults to `1` and is capped at `32`. |
84
+ | `showLogs` | Optional. Prints upload progress, upload completion, polling status, and final result info. |
85
+ | `logger` | Optional. Logger object with a `log` method. Defaults to `console`. |
86
+ | `polling` | Optional. `{ interval, timeout }` in seconds. `interval` must be at least `10`. Omit or set to `null`/`false` to disable automatic polling. |
87
+
88
+ ## File inputs
89
+
90
+ Each item in `files` must be an object with either `file` or `url`:
91
+
92
+ ```js
93
+ { reference_id: "episode_1", file: "./episode.mp3" }
94
+ { reference_id: "episode_2", url: "https://example.com/signed-audio-url.mp3" }
95
+ ```
96
+
97
+ Supported local/upload inputs:
98
+
99
+ - Node.js local file path strings, such as `"./audio.mp3"`.
100
+ - `File` objects.
101
+ - `Blob` objects.
102
+ - `{ data, name, type }`, where `data` is a `Uint8Array` or `ArrayBuffer`.
103
+
104
+ Supported remote inputs:
105
+
106
+ - Public or signed URLs using `{ url: "https://..." }`.
107
+
108
+ Do not include both `file` and `url` in the same item.
109
+
110
+ ## Single local file
111
+
112
+ ```js
113
+ const result = await client.transcribe({
114
+ files: [
115
+ { reference_id: "call_001", file: "./call.mp3" },
116
+ ],
117
+ language: "en",
118
+ });
119
+ ```
120
+
121
+ For one small local file, this usually uses the direct upload path. Larger files automatically become async jobs.
122
+
123
+ ## Remote URL transcription
124
+
125
+ ```js
126
+ const job = await client.transcribe({
35
127
  files: [
36
- { reference_id: "episode_1", file: "a.mp3" },
37
- { reference_id: "episode_2", file: "b.wav" },
128
+ { reference_id: "remote_001", url: "https://example.com/audio.mp3" },
38
129
  ],
130
+ language: "en",
39
131
  });
132
+ ```
40
133
 
41
- const remoteJob = await client.transcribe({
42
- file: { url: "https://signed-get-url-from-s3-or-r2" },
43
- });
44
-
45
- const remoteBatchJob = await client.batch.transcribe({
46
- files: [
47
- { reference_id: "episode_1", url: "https://signed-get-url-1" },
48
- { reference_id: "episode_2", url: "https://signed-get-url-2" },
49
- ],
50
- });
51
-
52
- const mixedBatchJob = await client.batch.transcribe({
53
- files: [
54
- { reference_id: "episode_1", file: "local.mp3" },
55
- { reference_id: "episode_2", url: "https://signed-get-url-2" },
56
- ],
134
+ Remote URL jobs are async because the API fetches the audio from the URL.
135
+
136
+ ## Batch and mixed input transcription
137
+
138
+ ```js
139
+ const job = await client.transcribe({
140
+ language: "en",
141
+ uploadConcurrency: 8,
142
+ files: [
143
+ { reference_id: "episode_1", file: "./episode-1.mp3" },
144
+ { reference_id: "episode_2", file: "./episode-2.wav" },
145
+ { reference_id: "episode_3", url: "https://example.com/episode-3.m4a" },
146
+ ],
57
147
  });
58
148
  ```
59
149
 
60
- For Cloudflare Workers and other web-style runtimes, use the Worker entrypoint:
150
+ Local files and remote URLs can be mixed in the same batch. When sending multiple files through `transcribe`, provide a unique `reference_id` for every item.
151
+
152
+ ## Per-file language
153
+
154
+ Set `language` at the top level to apply a default to the whole job. Set `language` on a file item to override the default for that file.
155
+
156
+ ```js
157
+ const job = await client.transcribe({
158
+ language: "en",
159
+ files: [
160
+ { reference_id: "intro", file: "./intro.mp3" },
161
+ { reference_id: "french_segment", file: "./segment.m4a", language: "fr" },
162
+ ],
163
+ });
164
+ ```
165
+
166
+ `language` must be a two-letter language code such as `en`, `fr`, or `es`. Omit it, pass an empty value, or pass `"auto"` to avoid sending an explicit language.
167
+
168
+ ## Excluding outputs or features
169
+
170
+ Use `exclude` to pass API exclusions. Arrays are joined with commas before sending. Valid values are only `vtt`, `segments`, `metadata`, `billing`, and `detected_language`.
171
+
172
+ ```js
173
+ const result = await client.transcribe({
174
+ files: [
175
+ { reference_id: "meeting", file: "./meeting.mp3" },
176
+ ],
177
+ exclude: ["vtt", "segments"],
178
+ });
179
+ ```
180
+
181
+ You can also pass a comma-separated string:
182
+
183
+ ```js
184
+ exclude: "metadata,billing"
185
+ ```
186
+
187
+ ## Webhooks
188
+
189
+ ```js
190
+ const job = await client.transcribe({
191
+ webhookUrl: "https://example.com/transcribe-webhook",
192
+ files: [
193
+ { reference_id: "upload_001", file: "./long-audio.mp3" },
194
+ ],
195
+ });
196
+ ```
197
+
198
+ Any request with `webhookUrl` uses the async job flow.
199
+
200
+ ## Progress and logs
201
+
202
+ Use `onProgress` to receive structured progress events:
203
+
204
+ ```js
205
+ const job = await client.transcribe({
206
+ files: [
207
+ { reference_id: "episode_1", file: "./episode-1.mp3" },
208
+ { reference_id: "episode_2", file: "./episode-2.mp3" },
209
+ ],
210
+ uploadConcurrency: 4,
211
+ onProgress(event) {
212
+ console.log(event);
213
+ },
214
+ });
215
+ ```
216
+
217
+ Common event names:
218
+
219
+ - `upload_urls_received`
220
+ - `upload_started`
221
+ - `upload_progress`
222
+ - `upload_completed`
223
+
224
+ Progress events may include `jobId`, `jobStatus`, `referenceId`, `loaded`, `total`, `fileLoaded`, `fileTotal`, `batchLoaded`, `batchTotal`, `uploadType`, `partNumber`, `totalParts`, and `multipartConcurrency`.
225
+
226
+ Set `showLogs: true` on the client or on a single call to print built-in progress and polling logs:
227
+
228
+ ```js
229
+ const client = new TranscribeAPI({
230
+ apiKey: process.env.TRANSCRIBE_API_KEY,
231
+ showLogs: true,
232
+ });
233
+ ```
234
+
235
+ ## Manual async jobs
236
+
237
+ `transcribe` uploads automatically. Use `createBatchJob` when you want to separate job creation from upload.
238
+
239
+ ```js
240
+ const job = await client.createBatchJob({
241
+ language: "en",
242
+ files: [
243
+ { reference_id: "part_1", file: "./part-1.mp3" },
244
+ { reference_id: "part_2", url: "https://example.com/part-2.mp3" },
245
+ ],
246
+ });
247
+
248
+ console.log(job.jobId);
249
+
250
+ const completion = await job.upload();
251
+ console.log(completion);
252
+ ```
253
+
254
+ For a single large local file, you can also use `createBigFileJob`:
255
+
256
+ ```js
257
+ const job = await client.createBigFileJob({
258
+ file: { reference_id: "large_001", file: "./large.wav" },
259
+ });
260
+
261
+ const completion = await job.upload();
262
+ ```
263
+
264
+ ## Job helpers
265
+
266
+ ```js
267
+ const job = await client.jobs.get("job_id_here");
268
+ const sameJob = await client.jobs.result("job_id_here");
269
+
270
+ const finalJob = await client.waitForJobCompletion("job_id_here", {
271
+ polling: { interval: 10, timeout: 15 * 60 },
272
+ });
273
+ ```
274
+
275
+ Available job helpers:
276
+
277
+ | Method | Description |
278
+ | --- | --- |
279
+ | `client.jobs.get(jobId)` | Fetches `GET /v1/transcribe/{job_id}`. |
280
+ | `client.jobs.result(jobId)` | Alias for `jobs.get`. |
281
+ | `client.jobs.uploadCompleted(jobId)` | Calls `POST /v1/transcribe/{job_id}/upload-completed`. |
282
+ | `client.jobs.complete(jobId)` | Alias for `jobs.uploadCompleted`. |
283
+ | `client.jobs.createBatch(options)` | Creates a batch job and returns a `BatchJob`. |
284
+ | `client.jobs.createBigFile(options)` | Creates a one-file async upload job and returns a `BatchJob`. |
285
+ | `client.waitForJobCompletion(jobId, options)` | Polls until a terminal job status or timeout. |
286
+
287
+ ## Limits and validation
288
+
289
+ - Batch jobs support up to `10,000` files.
290
+ - Batch local upload payloads support up to `10 GB` total local file size.
291
+ - Direct sync routing is used only for one local file up to `30 MB` and about `10 minutes`.
292
+ - Multipart upload starts when the backend returns multipart upload instructions. The SDK sends `size_bytes` for local files at least `128 MB` so the backend can choose multipart.
293
+ - `uploadConcurrency` defaults to `1` and is capped at `32`.
294
+ - `polling.interval` must be at least `10` seconds.
295
+ - Batch local uploads support `mp3`, `mpeg`, `mpga`, `m4a`, `wav`, and `webm`.
296
+ - `.mp4` is not supported.
297
+
298
+ ## Error handling
299
+
300
+ ```js
301
+ try {
302
+ const result = await client.transcribe({
303
+ files: [
304
+ { reference_id: "bad_file", file: "./missing.mp3" },
305
+ ],
306
+ });
307
+ console.log(result);
308
+ } catch (error) {
309
+ if (error instanceof TranscribeAPIError) {
310
+ console.error(error.message);
311
+ console.error(error.code);
312
+ console.error(error.status);
313
+ console.error(error.response);
314
+ console.error(error.toJSON());
315
+ } else {
316
+ throw error;
317
+ }
318
+ }
319
+ ```
320
+
321
+ `TranscribeAPIError` includes `message`, `code`, `status`, `response`, and any extra fields returned by the API or generated by the SDK.
322
+
323
+ ## Cloudflare Workers and web runtimes
324
+
325
+ Use the Worker entrypoint when running in Cloudflare Workers or other web-standard runtimes:
326
+
327
+ ```js
328
+ import { TranscribeAPI, TranscribeAPIError } from "@transcribe-api/sdk/worker";
329
+ ```
330
+
331
+ The Worker entrypoint keeps the same public client API, but these runtimes do not support Node local file path strings such as `"./audio.mp3"`.
332
+
333
+ Supported Worker-safe inputs:
334
+
335
+ - `File` objects, such as files from `request.formData()`.
336
+ - `Blob` objects.
337
+ - `{ data, name, type }`, where `data` is a `Uint8Array` or `ArrayBuffer`.
338
+ - Remote URLs using `{ url: "https://..." }`.
339
+
340
+ Not supported in Worker runtimes:
341
+
342
+ - Local file path strings.
343
+ - Node.js streams.
344
+ - Node-only filesystem APIs.
345
+
346
+ ## Cloudflare Worker quick start
61
347
 
62
348
  ```js
63
349
  import { TranscribeAPI } from "@transcribe-api/sdk/worker";
350
+
351
+ export default {
352
+ async fetch(request, env) {
353
+ const client = new TranscribeAPI({
354
+ apiKey: env.TRANSCRIBE_API_KEY,
355
+ polling: {
356
+ interval: 10,
357
+ timeout: 15 * 60,
358
+ },
359
+ });
360
+
361
+ const result = await client.transcribe({
362
+ language: "en",
363
+ files: [
364
+ {
365
+ reference_id: "sample_001",
366
+ url: "https://example.com/audio.mp3",
367
+ },
368
+ ],
369
+ });
370
+
371
+ return Response.json(result);
372
+ },
373
+ };
64
374
  ```
65
-
66
- Async uploads use signed R2 URLs returned by the API. Multipart upload is used automatically when the backend returns a multipart flow.
67
- Async job creation now goes through `POST /v1/transcribe` for single-file and batch jobs. For batch calls, each item must be `{ reference_id, file }` or `{ reference_id, url }`, and local plus remote entries can be mixed in the same batch. The SDK adds `size_bytes` automatically for large local files when the backend needs multipart upload.
68
- Set `polling.interval` and optional `polling.timeout` in seconds on the client to make async jobs wait for completion automatically. The SDK enforces a minimum polling interval of `10` seconds and stops on `completed`, `failed`, or `insufficient_funds`.
69
- If polling is not configured, use `GET /v1/transcribe/{job_id}` manually. The response always includes the core job fields and adds `result_url` when `job_status` is `completed`.
70
- The SDK defaults `multipartConcurrency` to `8` for reliability. You can increase it up to `32` when your network path is stable.
71
- For Node path uploads, multipart progress is persisted to a sidecar resume file and the SDK will resume the existing big-file job on the next run instead of starting over.
72
- Multipart uploads also adaptively reduce concurrency on retryable transport errors instead of failing the whole upload immediately.
73
- Set `showLogs: true` on the client or per async call to let the SDK print upload URL receipt, upload progress, and the final `/upload-completed` response automatically. Pass a custom `logger` object if you want those messages redirected somewhere other than `console`.
74
-
75
- Use `@transcribe-api/sdk/worker` when you need a runtime-safe build for Cloudflare Workers. The Worker entrypoint supports remote URLs, `Blob`, `File`, and byte inputs, but does not support local file path strings or Node.js filesystem resume state.
375
+
376
+ ## Uploading a request file in a Worker
377
+
378
+ ```js
379
+ import { TranscribeAPI } from "@transcribe-api/sdk/worker";
380
+
381
+ export default {
382
+ async fetch(request, env) {
383
+ const form = await request.formData();
384
+ const audio = form.get("file");
385
+
386
+ if (!(audio instanceof File)) {
387
+ return Response.json({ error: "Missing file" }, { status: 400 });
388
+ }
389
+
390
+ const client = new TranscribeAPI({
391
+ apiKey: env.TRANSCRIBE_API_KEY,
392
+ polling: {
393
+ interval: 10,
394
+ timeout: 15 * 60,
395
+ },
396
+ });
397
+
398
+ const result = await client.transcribe({
399
+ language: "en",
400
+ files: [
401
+ { reference_id: "upload_001", file: audio },
402
+ ],
403
+ });
404
+
405
+ return Response.json(result);
406
+ },
407
+ };
408
+ ```
409
+
410
+ Remote URL transcription is usually the best fit for Workers when audio is already stored in R2, S3, or another storage service.