Skip to content

Commit 479dc60

Browse files
authored
Update readme, add uuid, update waitFor, fix minor issues (#7)
1 parent c71802f commit 479dc60

File tree

5 files changed

+109
-35
lines changed

5 files changed

+109
-35
lines changed

README.md

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,17 @@ Welcome to the SaladCloud Transcription SDK documentation. This guide will help
1010

1111
The Transcription REST API. Please refer to the [Transcription API Documentation](https://docs.salad.com/reference/transcribe/inference_endpoints/create-an-inference-endpoint-job) for more details.
1212

13-
## Installation
14-
15-
To get started with the SDK, we recommend installing using `npm` or `yarn`:
16-
17-
```bash
18-
npm install @saladtechnologies-oss/salad-cloud-transcription-sdk
19-
```
20-
21-
```bash
22-
yarn add @saladtechnologies-oss/salad-cloud-transcription-sdk
23-
```
24-
2513
## Table of Contents
2614

15+
- [Getting Started](#getting-started)
16+
- [Installation](#installation)
2717
- [Authentication](#authentication)
28-
- [Setting the API key](#transcribe)
29-
- [Setting a Custom Timeout](#get)
18+
- [Setting the API key](#setting-the-api-key)
19+
- [Setting a Custom Timeout](#setting-a-custom-timeout)
20+
- [Environment Support](#environment-support)
3021
- [Sample Usage](#sample-usage)
22+
- [Node.js Usage Example](#nodejs-usage-example)
23+
- [Browser Usage Example](#browser-usage-example)
3124
- [Features and Methods](#features-and-methods)
3225
- [Transcribe](#transcribe)
3326
- [Transcribe and Get Updates via a Webhook](#transcribe-and-get-updates-via-a-webhook)
@@ -38,6 +31,26 @@ yarn add @saladtechnologies-oss/salad-cloud-transcription-sdk
3831
- [Error Handling](#error-handling)
3932
- [License](#license)
4033

34+
## Getting Started
35+
36+
To quickly integrate the SDK, follow these steps:
37+
38+
1. Install the SDK (see above).
39+
2. Initialize the SDK with your API key.
40+
3. Transcribe a File using a basic example provided below.
41+
42+
## Installation
43+
44+
To get started with the SDK, we recommend installing using `npm` or `yarn`:
45+
46+
```bash
47+
npm install @saladtechnologies-oss/salad-cloud-transcription-sdk
48+
```
49+
50+
```bash
51+
yarn add @saladtechnologies-oss/salad-cloud-transcription-sdk
52+
```
53+
4154
## Authentication
4255

4356
### API Key Authentication
@@ -60,15 +73,51 @@ You can set a custom timeout for the SDK's HTTP requests as follows:
6073
const sdk = new SaladCloudTranscriptionSdk({ timeout: 10000 })
6174
```
6275

76+
## Environment Support
77+
78+
The SaladCloud Transcription SDK is built to work seamlessly in both Node.js and browser environments.
79+
80+
- Node.js:
81+
Full support for local file operations and heavy file I/O makes the SDK ideal for server-side applications and CLI tools.
82+
83+
- Browser Limitations:
84+
Browsers do not have access to the local file system like Node.js does. Therefore, any attempt to perform local file I/O in the browser will be explicitly rejected.
85+
6386
## Sample Usage
6487

6588
Below is a comprehensive example demonstrating how to authenticate and transcribe:
6689

90+
### Node.js Usage Example
91+
92+
```ts
93+
const { SaladCloudTranscriptionSdk } = require('@saladtechnologies-oss/salad-cloud-transcription-sdk')
94+
95+
const organizationName = 'organization_name'
96+
const file = 'file:///path/to/file.mp4'
97+
98+
const sdk = new SaladCloudTranscriptionSdk({ apiKey: 'YOUR_API_KEY' })
99+
100+
const transcribe = async (): Promise<string> => {
101+
const { id } = await sdk.transcribe(organizationName, file)
102+
return id
103+
}
104+
105+
;(async () => {
106+
try {
107+
await transcribe()
108+
} catch (error) {
109+
console.error(error)
110+
}
111+
})()
112+
```
113+
114+
### Browser Usage Example
115+
67116
```ts
68117
import { SaladCloudTranscriptionSdk } from '@saladtechnologies-oss/salad-cloud-transcription-sdk'
69118

70119
const organizationName = 'organization_name'
71-
const file = 'file_to_path_or_url'
120+
const file = 'https://example.com/video.mp4'
72121

73122
const sdk = new SaladCloudTranscriptionSdk({ apiKey: 'YOUR_API_KEY' })
74123

@@ -92,7 +141,8 @@ The SDK exposes several key methods:
92141

93142
### Transcribe
94143

95-
Transcribes a file or remote source. If a local file is provided, it is uploaded before transcription.
144+
Transcribes either a local file or a remote source.
145+
If you provide a local file, it’s uploaded before transcription. Files larger than 100 MB are uploaded in chunks
96146

97147
```ts
98148
import { SaladCloudTranscriptionSdk } from '@saladtechnologies-oss/salad-cloud-transcription-sdk'
@@ -185,7 +235,14 @@ const sdk = new SaladCloudTranscriptionSdk({
185235
apiKey: 'YOUR_API_KEY',
186236
})
187237

188-
const transcription = await sdk.get('organization_name', 'transcription_job_id')
238+
const controller = new AbortController()
239+
const signal = controller.signal
240+
241+
const transcription = await sdk.get(
242+
'organization_name', // organization name
243+
'transcription_job_id', // transcription job ID
244+
signal, // optional AbortSignal to cancel the operation
245+
)
189246
```
190247

191248
### Stop
@@ -199,7 +256,10 @@ const sdk = new SaladCloudTranscriptionSdk({
199256
apiKey: 'YOUR_API_KEY',
200257
})
201258

202-
await sdk.stop('organization_name', 'transcription_job_id')
259+
await sdk.stop(
260+
'organization_name', // organization name
261+
'transcription_job_id', // transcription job ID
262+
)
203263
```
204264

205265
### List
@@ -213,12 +273,14 @@ const sdk = new SaladCloudTranscriptionSdk({
213273
apiKey: 'YOUR_API_KEY',
214274
})
215275

216-
const transcriptionsList = await sdk.list('organization_name')
276+
const transcriptionsList = await sdk.list(
277+
'organization_name', // organization name
278+
)
217279
```
218280

219281
### WaitFor
220282

221-
Polls the transcription status until the job reaches a final state ("succeeded" or "failed"), a timeout is reached, or the operation is aborted.
283+
Polls the transcription status every 5 seconds until one of the following occurs: the job reaches a final state (either "succeeded" or "failed"), it times out after 3 minutes, or the operation is aborted.
222284

223285
```ts
224286
import { SaladCloudTranscriptionSdk } from '@saladtechnologies-oss/salad-cloud-transcription-sdk'
@@ -228,7 +290,14 @@ const sdk = new SaladCloudTranscriptionSdk({
228290
})
229291

230292
try {
231-
const finalResult = await sdk.waitFor('organization_name', 'transcription_job_id')
293+
const controller = new AbortController()
294+
const signal = controller.signal
295+
296+
const finalResult = await sdk.get(
297+
'organization_name', // organization name
298+
'transcription_job_id', // transcription job ID
299+
signal, // optional AbortSignal to cancel the operation
300+
)
232301
} catch (error) {
233302
console.error('Error or timeout while waiting:', error)
234303
}

src/transcription/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ export const transcribeInferenceEndpointName = 'transcribe'
22

33
export const oneSecondInMs = 1000
44
export const oneMinuteInMs = 60000
5+
export const oneDayInSeconds = 86400
56

67
export const oneMbInBytes = 1024 * 1024
78
export const maxFileSizeBytesForStorage = oneMbInBytes * 100
8-
export const filePartSizeBytesForStorage = oneMbInBytes * 20
9+
export const filePartSizeBytesForStorage = oneMbInBytes * 80

src/transcription/node/utils.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { AxiosInstance } from 'axios'
2+
import { randomUUID } from 'crypto'
23
import FormData from 'form-data'
34
import fs from 'fs/promises'
45
import { createReadStream, existsSync } from 'node:fs'
56
import path from 'node:path'
67
import { fileURLToPath } from 'node:url'
7-
import { filePartSizeBytesForStorage, maxFileSizeBytesForStorage } from '../constants'
8+
import { filePartSizeBytesForStorage, maxFileSizeBytesForStorage, oneDayInSeconds } from '../constants'
89
import { SignFileError, UploadError } from '../errors'
910
import { Semaphore } from './semaphore'
1011

@@ -64,7 +65,6 @@ export const normalizeFilePath = (filePath: string): string => {
6465
* @returns A FormData instance containing the file.
6566
*/
6667
export const createFormData = async (fileSource: string): Promise<FormData> => {
67-
console.log(!existsSync(fileSource))
6868
if (!existsSync(fileSource)) {
6969
throw new UploadError(fileSource, 'File not found')
7070
}
@@ -125,7 +125,7 @@ export const signFile = async (
125125
): Promise<UploadFileResponse> => {
126126
const requestBody = {
127127
method: 'GET',
128-
exp: '3600',
128+
exp: oneDayInSeconds,
129129
}
130130

131131
try {
@@ -260,7 +260,7 @@ export const readFileInChunks = async (
260260
* 3. Completes the upload once all parts are processed.
261261
*
262262
* @param axiosInstance - The Axios instance for making HTTP requests.
263-
* @param fileName - The name of the file being uploaded.
263+
* @param uniqueFileName - The name and uid of the file being uploaded.
264264
* @param filePath - The path of the file on the local filesystem.
265265
* @param fileSize - The total size of the file in bytes.
266266
* @param organizationName - The name of the organization (used in URL paths).
@@ -269,15 +269,15 @@ export const readFileInChunks = async (
269269
*/
270270
export const uploadFileInParts = async (
271271
axiosInstance: AxiosInstance,
272-
fileName: string,
272+
uniqueFileName: string,
273273
filePath: string,
274274
fileSize: number,
275275
organizationName: string,
276276
partSizeBytes: number,
277277
signal?: AbortSignal,
278278
): Promise<void> => {
279-
const filesUploadUrl = `/organizations/${organizationName}/files/${fileName}`
280-
const filePartsUploadUrl = `/organizations/${organizationName}/file_parts/${fileName}`
279+
const filesUploadUrl = `/organizations/${organizationName}/files/${uniqueFileName}`
280+
const filePartsUploadUrl = `/organizations/${organizationName}/file_parts/${uniqueFileName}`
281281

282282
const createUploadUrl = `${filesUploadUrl}?action=mpu-create`
283283

@@ -322,11 +322,14 @@ export const getTranscriptionLocalFileSource = async (
322322
organizationName: string,
323323
signal?: AbortSignal,
324324
): Promise<string> => {
325+
const uniqueId = randomUUID()
325326
const normalizedFilePath = normalizeFilePath(source)
326327
const fileName = path.basename(normalizedFilePath)
327328

328-
const uploadFileRequestUrl = `/organizations/${organizationName}/files/${fileName}`
329-
const signFileRequestUrl = `/organizations/${organizationName}/file_tokens/${fileName}`
329+
const uniqueFileName = `${uniqueId}-${fileName}`
330+
331+
const uploadFileRequestUrl = `/organizations/${organizationName}/files/${uniqueFileName}`
332+
const signFileRequestUrl = `/organizations/${organizationName}/file_tokens/${uniqueFileName}`
330333

331334
try {
332335
const stats = await fs.stat(normalizedFilePath)
@@ -335,7 +338,7 @@ export const getTranscriptionLocalFileSource = async (
335338
if (fileSize > maxFileSizeBytesForStorage) {
336339
await uploadFileInParts(
337340
axiosInstance,
338-
fileName,
341+
uniqueFileName,
339342
normalizedFilePath,
340343
fileSize,
341344
organizationName,

src/transcription/transcription.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export class SaladCloudTranscriptionSdk {
258258
if (signal?.aborted) {
259259
throw new Error('Operation aborted')
260260
}
261-
if (Date.now() - startTime > oneMinuteInMs * 2) {
261+
if (Date.now() - startTime > oneMinuteInMs * 3) {
262262
throw new Error('Timeout waiting for transcription')
263263
}
264264

@@ -282,7 +282,7 @@ export class SaladCloudTranscriptionSdk {
282282
}
283283

284284
// Otherwise, wait and poll again.
285-
await new Promise((resolve) => setTimeout(resolve, oneSecondInMs * 3))
285+
await new Promise((resolve) => setTimeout(resolve, oneSecondInMs * 5))
286286
return poll()
287287
}
288288

tests/nodeUtils.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import fsPromises from 'fs/promises'
33
import path from 'node:path'
44
import { Readable } from 'node:stream'
55
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
6+
import { oneDayInSeconds } from '../src/transcription/constants'
67
import * as utils from '../src/transcription/node'
78
import {
89
completeUpload,
@@ -110,7 +111,7 @@ describe('signFile', () => {
110111
const axiosInstance: any = createAxiosInstance('post', signResponse)
111112
const result = await signFile(axiosInstance as any, testUrl, testFileName)
112113
expect(result).toEqual(signResponse)
113-
expect(axiosInstance.post).toHaveBeenCalledWith(testUrl, { method: 'GET', exp: '3600' })
114+
expect(axiosInstance.post).toHaveBeenCalledWith(testUrl, { method: 'GET', exp: oneDayInSeconds })
114115
})
115116

116117
it('should throw an error on failure', async () => {

0 commit comments

Comments
 (0)