tryspeakeasy 1.0.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/LICENSE +21 -0
- package/README.md +198 -0
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +108 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SpeakEasy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# SpeakEasy Node.js SDK
|
|
2
|
+
|
|
3
|
+
Official Node.js/TypeScript client for the [SpeakEasy](https://www.tryspeakeasy.io) API — affordable speech-to-text and text-to-speech for developers.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/tryspeakeasy)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install tryspeakeasy
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { SpeakEasy } from 'tryspeakeasy'
|
|
18
|
+
|
|
19
|
+
const se = new SpeakEasy('sk-se-your_api_key')
|
|
20
|
+
|
|
21
|
+
// Transcribe audio
|
|
22
|
+
const { text } = await se.transcribe({
|
|
23
|
+
url: 'https://example.com/audio.mp3',
|
|
24
|
+
})
|
|
25
|
+
console.log(text)
|
|
26
|
+
|
|
27
|
+
// Generate speech
|
|
28
|
+
const audio = await se.speech({
|
|
29
|
+
input: 'Hello world!',
|
|
30
|
+
voice: 'nova',
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
> Get your API key from the [SpeakEasy dashboard](https://app.tryspeakeasy.io).
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Speech-to-Text
|
|
39
|
+
|
|
40
|
+
Transcribe audio files or URLs. Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, and webm (max 100 MB).
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// From URL
|
|
44
|
+
const result = await se.transcribe({
|
|
45
|
+
url: 'https://example.com/podcast.mp3',
|
|
46
|
+
})
|
|
47
|
+
console.log(result.text)
|
|
48
|
+
|
|
49
|
+
// From file (Node.js)
|
|
50
|
+
import { readFileSync } from 'fs'
|
|
51
|
+
const file = new Blob([readFileSync('recording.mp3')])
|
|
52
|
+
const result = await se.transcribe({ file })
|
|
53
|
+
|
|
54
|
+
// With options
|
|
55
|
+
const result = await se.transcribe({
|
|
56
|
+
url: 'https://example.com/audio.mp3',
|
|
57
|
+
language: 'en',
|
|
58
|
+
speakerLabels: true,
|
|
59
|
+
wordTimestamps: true,
|
|
60
|
+
responseFormat: 'verbose_json',
|
|
61
|
+
})
|
|
62
|
+
console.log(result.segments) // timestamped segments
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### Response Formats
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// JSON (default) — { text: string }
|
|
69
|
+
const json = await se.transcribe({ url, responseFormat: 'json' })
|
|
70
|
+
|
|
71
|
+
// Verbose JSON — includes segments with timestamps
|
|
72
|
+
const verbose = await se.transcribe({ url, responseFormat: 'verbose_json' })
|
|
73
|
+
|
|
74
|
+
// Plain text
|
|
75
|
+
const text = await se.transcribe({ url, responseFormat: 'text' })
|
|
76
|
+
|
|
77
|
+
// Subtitles
|
|
78
|
+
const srt = await se.transcribe({ url, responseFormat: 'srt' })
|
|
79
|
+
const vtt = await se.transcribe({ url, responseFormat: 'vtt' })
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Async with Webhook
|
|
83
|
+
|
|
84
|
+
For long audio files, provide a `callbackUrl` to get results asynchronously:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
await se.transcribe({
|
|
88
|
+
url: 'https://example.com/long-podcast.mp3',
|
|
89
|
+
callbackUrl: 'https://your-server.com/webhook',
|
|
90
|
+
})
|
|
91
|
+
// Your server receives the result via POST when done
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Text-to-Speech
|
|
95
|
+
|
|
96
|
+
Convert text to audio with 40+ voices across 10 languages.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// Generate speech (returns ArrayBuffer)
|
|
100
|
+
const audio = await se.speech({
|
|
101
|
+
input: 'Welcome to SpeakEasy!',
|
|
102
|
+
voice: 'nova',
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Save to file (Node.js)
|
|
106
|
+
import { writeFileSync } from 'fs'
|
|
107
|
+
writeFileSync('output.mp3', Buffer.from(audio))
|
|
108
|
+
|
|
109
|
+
// With options
|
|
110
|
+
const audio = await se.speech({
|
|
111
|
+
input: 'Bonjour le monde!',
|
|
112
|
+
voice: 'amelie',
|
|
113
|
+
language: 'fr',
|
|
114
|
+
responseFormat: 'wav',
|
|
115
|
+
speed: 1.2,
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// With word timestamps (returns JSON instead of audio)
|
|
119
|
+
const result = await se.speech({
|
|
120
|
+
input: 'Hello world',
|
|
121
|
+
wordTimestamps: true,
|
|
122
|
+
})
|
|
123
|
+
console.log(result.word_timestamps)
|
|
124
|
+
// [{ word: 'Hello', start: 0.0, end: 0.4 }, { word: 'world', start: 0.5, end: 0.9 }]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Available Voices
|
|
128
|
+
|
|
129
|
+
| Language | Voices |
|
|
130
|
+
|----------|--------|
|
|
131
|
+
| English (US) | heart, bella, michael, alloy, aoede, kore, jessica, nicole, nova, river, sarah, sky, echo, eric, fenrir, liam, onyx, puck, adam, santa |
|
|
132
|
+
| English (UK) | alice, emma, isabella, lily, daniel, fable, george, lewis |
|
|
133
|
+
| Japanese | haruto, yuki |
|
|
134
|
+
| Chinese | xiaobei, yunjian |
|
|
135
|
+
| Spanish | carlos, maria |
|
|
136
|
+
| French | pierre, amelie |
|
|
137
|
+
| Hindi | arjun, priya |
|
|
138
|
+
| Italian | luca, giulia |
|
|
139
|
+
| Portuguese (BR) | pedro, ana |
|
|
140
|
+
|
|
141
|
+
## Error Handling
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { SpeakEasy, SpeakEasyError } from 'tryspeakeasy'
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
await se.transcribe({ url: 'https://example.com/audio.mp3' })
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (err instanceof SpeakEasyError) {
|
|
150
|
+
console.log(err.status) // 402, 429, etc.
|
|
151
|
+
console.log(err.message) // 'No active subscription'
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
| Status | Meaning |
|
|
157
|
+
|--------|---------|
|
|
158
|
+
| 401 | Missing or invalid API key |
|
|
159
|
+
| 403 | No active subscription |
|
|
160
|
+
| 429 | Too many concurrent requests (max 10) |
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const se = new SpeakEasy('sk-se-your_api_key', {
|
|
166
|
+
// Override the base URL
|
|
167
|
+
baseUrl: 'https://staging.tryspeakeasy.io',
|
|
168
|
+
// Provide a custom fetch implementation
|
|
169
|
+
fetch: myCustomFetch,
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## API Reference
|
|
174
|
+
|
|
175
|
+
| Method | Description |
|
|
176
|
+
|--------|-------------|
|
|
177
|
+
| `transcribe(options)` | Speech-to-text — transcribe audio files or URLs |
|
|
178
|
+
| `speech(options)` | Text-to-speech — generate audio from text |
|
|
179
|
+
|
|
180
|
+
## Requirements
|
|
181
|
+
|
|
182
|
+
- Node.js 18+ (uses native `fetch`)
|
|
183
|
+
- A [SpeakEasy](https://www.tryspeakeasy.io) account with an active subscription
|
|
184
|
+
|
|
185
|
+
## Links
|
|
186
|
+
|
|
187
|
+
- [SpeakEasy](https://www.tryspeakeasy.io) — Affordable Speech-to-Text & Text-to-Speech API
|
|
188
|
+
- [Dashboard](https://app.tryspeakeasy.io) — API key management and usage monitoring
|
|
189
|
+
- [Documentation](https://www.tryspeakeasy.io/docs) — Full API reference
|
|
190
|
+
- [Pricing](https://www.tryspeakeasy.io/pricing) — Usage-based pricing starting at $9/month
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
[MIT](LICENSE)
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
Built by [SIÁN Agency](https://www.sian-agency.online)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
type ResponseFormat = 'json' | 'text' | 'verbose_json' | 'srt' | 'vtt';
|
|
2
|
+
interface TranscribeOptions {
|
|
3
|
+
/** Audio file to transcribe (provide either `file` or `url`). */
|
|
4
|
+
file?: Blob | File;
|
|
5
|
+
/** URL of the audio to transcribe (provide either `file` or `url`). */
|
|
6
|
+
url?: string;
|
|
7
|
+
/** Model to use. Default: "default". */
|
|
8
|
+
model?: string;
|
|
9
|
+
/** Target language. */
|
|
10
|
+
language?: string;
|
|
11
|
+
/** Transcription hint / prompt. */
|
|
12
|
+
prompt?: string;
|
|
13
|
+
/** Enable speaker identification. */
|
|
14
|
+
speakerLabels?: boolean;
|
|
15
|
+
/** Translate audio to English. */
|
|
16
|
+
translate?: boolean;
|
|
17
|
+
/** Include word-level timestamps. */
|
|
18
|
+
wordTimestamps?: boolean;
|
|
19
|
+
/** Response format. Default: "json". */
|
|
20
|
+
responseFormat?: ResponseFormat;
|
|
21
|
+
/** Async webhook URL — receives result when done. */
|
|
22
|
+
callbackUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
interface TranscriptionResult {
|
|
25
|
+
text: string;
|
|
26
|
+
}
|
|
27
|
+
interface VerboseTranscriptionResult {
|
|
28
|
+
text: string;
|
|
29
|
+
segments: {
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
text: string;
|
|
33
|
+
words?: {
|
|
34
|
+
word: string;
|
|
35
|
+
start: number;
|
|
36
|
+
end: number;
|
|
37
|
+
}[];
|
|
38
|
+
}[];
|
|
39
|
+
}
|
|
40
|
+
type AudioFormat = 'mp3' | 'wav' | 'aac' | 'flac' | 'opus' | 'aiff' | 'pcm';
|
|
41
|
+
type Voice = 'heart' | 'bella' | 'michael' | 'alloy' | 'aoede' | 'kore' | 'jessica' | 'nicole' | 'nova' | 'river' | 'sarah' | 'sky' | 'echo' | 'eric' | 'fenrir' | 'liam' | 'onyx' | 'puck' | 'adam' | 'santa' | 'alice' | 'emma' | 'isabella' | 'lily' | 'daniel' | 'fable' | 'george' | 'lewis' | 'haruto' | 'yuki' | 'xiaobei' | 'yunjian' | 'carlos' | 'maria' | 'pierre' | 'amelie' | 'arjun' | 'priya' | 'luca' | 'giulia' | 'pedro' | 'ana' | (string & {});
|
|
42
|
+
interface SpeechOptions {
|
|
43
|
+
/** Text to synthesize (max 4096 characters). */
|
|
44
|
+
input: string;
|
|
45
|
+
/** Model to use. Default: "tts-1". */
|
|
46
|
+
model?: string;
|
|
47
|
+
/** Voice name. Default: "alloy". */
|
|
48
|
+
voice?: Voice;
|
|
49
|
+
/** Target language. */
|
|
50
|
+
language?: string;
|
|
51
|
+
/** Audio format. Default: "mp3". */
|
|
52
|
+
responseFormat?: AudioFormat;
|
|
53
|
+
/** Playback speed. Default: 1.0. */
|
|
54
|
+
speed?: number;
|
|
55
|
+
/** Include word-level timestamps (returns JSON instead of audio). */
|
|
56
|
+
wordTimestamps?: boolean;
|
|
57
|
+
}
|
|
58
|
+
interface SpeechWithTimestamps {
|
|
59
|
+
audio: string;
|
|
60
|
+
word_timestamps: {
|
|
61
|
+
word: string;
|
|
62
|
+
start: number;
|
|
63
|
+
end: number;
|
|
64
|
+
}[];
|
|
65
|
+
}
|
|
66
|
+
interface ApiErrorBody {
|
|
67
|
+
message: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
}
|
|
70
|
+
interface SpeakEasyOptions {
|
|
71
|
+
/** Override the base URL (default: `https://www.tryspeakeasy.io`). */
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
/** Override the global `fetch` implementation. */
|
|
74
|
+
fetch?: typeof globalThis.fetch;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* SpeakEasy API client.
|
|
79
|
+
*
|
|
80
|
+
* Affordable speech-to-text and text-to-speech for developers.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const se = new SpeakEasy('sk-se-your_api_key')
|
|
85
|
+
*
|
|
86
|
+
* // Transcribe audio
|
|
87
|
+
* const { text } = await se.transcribe({ url: 'https://example.com/audio.mp3' })
|
|
88
|
+
*
|
|
89
|
+
* // Generate speech
|
|
90
|
+
* const audio = await se.speech({ input: 'Hello world', voice: 'nova' })
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see https://www.tryspeakeasy.io — Affordable Speech-to-Text & Text-to-Speech API
|
|
94
|
+
*/
|
|
95
|
+
declare class SpeakEasy {
|
|
96
|
+
private readonly apiKey;
|
|
97
|
+
private readonly baseUrl;
|
|
98
|
+
private readonly _fetch;
|
|
99
|
+
constructor(apiKey: string, options?: SpeakEasyOptions);
|
|
100
|
+
private authHeaders;
|
|
101
|
+
private handleError;
|
|
102
|
+
/**
|
|
103
|
+
* Transcribe audio to text.
|
|
104
|
+
*
|
|
105
|
+
* Provide either a `file` (Blob/File) or a `url` pointing to the audio.
|
|
106
|
+
* Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).
|
|
107
|
+
*
|
|
108
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
109
|
+
*/
|
|
110
|
+
transcribe(options: TranscribeOptions): Promise<TranscriptionResult | VerboseTranscriptionResult | string>;
|
|
111
|
+
/**
|
|
112
|
+
* Convert text to speech audio.
|
|
113
|
+
*
|
|
114
|
+
* Returns an `ArrayBuffer` of the audio data, or a JSON object with
|
|
115
|
+
* timestamps if `wordTimestamps` is enabled.
|
|
116
|
+
*
|
|
117
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
118
|
+
*/
|
|
119
|
+
speech(options: SpeechOptions): Promise<ArrayBuffer | SpeechWithTimestamps>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Error thrown when the SpeakEasy API returns a non-2xx response.
|
|
124
|
+
*/
|
|
125
|
+
declare class SpeakEasyError extends Error {
|
|
126
|
+
/** HTTP status code. */
|
|
127
|
+
readonly status: number;
|
|
128
|
+
/** Error type from the API. */
|
|
129
|
+
readonly type: string | undefined;
|
|
130
|
+
constructor(body: ApiErrorBody, status: number);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { type ApiErrorBody, type AudioFormat, type ResponseFormat, SpeakEasy, SpeakEasyError, type SpeakEasyOptions, type SpeechOptions, type SpeechWithTimestamps, type TranscribeOptions, type TranscriptionResult, type VerboseTranscriptionResult, type Voice };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
type ResponseFormat = 'json' | 'text' | 'verbose_json' | 'srt' | 'vtt';
|
|
2
|
+
interface TranscribeOptions {
|
|
3
|
+
/** Audio file to transcribe (provide either `file` or `url`). */
|
|
4
|
+
file?: Blob | File;
|
|
5
|
+
/** URL of the audio to transcribe (provide either `file` or `url`). */
|
|
6
|
+
url?: string;
|
|
7
|
+
/** Model to use. Default: "default". */
|
|
8
|
+
model?: string;
|
|
9
|
+
/** Target language. */
|
|
10
|
+
language?: string;
|
|
11
|
+
/** Transcription hint / prompt. */
|
|
12
|
+
prompt?: string;
|
|
13
|
+
/** Enable speaker identification. */
|
|
14
|
+
speakerLabels?: boolean;
|
|
15
|
+
/** Translate audio to English. */
|
|
16
|
+
translate?: boolean;
|
|
17
|
+
/** Include word-level timestamps. */
|
|
18
|
+
wordTimestamps?: boolean;
|
|
19
|
+
/** Response format. Default: "json". */
|
|
20
|
+
responseFormat?: ResponseFormat;
|
|
21
|
+
/** Async webhook URL — receives result when done. */
|
|
22
|
+
callbackUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
interface TranscriptionResult {
|
|
25
|
+
text: string;
|
|
26
|
+
}
|
|
27
|
+
interface VerboseTranscriptionResult {
|
|
28
|
+
text: string;
|
|
29
|
+
segments: {
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
text: string;
|
|
33
|
+
words?: {
|
|
34
|
+
word: string;
|
|
35
|
+
start: number;
|
|
36
|
+
end: number;
|
|
37
|
+
}[];
|
|
38
|
+
}[];
|
|
39
|
+
}
|
|
40
|
+
type AudioFormat = 'mp3' | 'wav' | 'aac' | 'flac' | 'opus' | 'aiff' | 'pcm';
|
|
41
|
+
type Voice = 'heart' | 'bella' | 'michael' | 'alloy' | 'aoede' | 'kore' | 'jessica' | 'nicole' | 'nova' | 'river' | 'sarah' | 'sky' | 'echo' | 'eric' | 'fenrir' | 'liam' | 'onyx' | 'puck' | 'adam' | 'santa' | 'alice' | 'emma' | 'isabella' | 'lily' | 'daniel' | 'fable' | 'george' | 'lewis' | 'haruto' | 'yuki' | 'xiaobei' | 'yunjian' | 'carlos' | 'maria' | 'pierre' | 'amelie' | 'arjun' | 'priya' | 'luca' | 'giulia' | 'pedro' | 'ana' | (string & {});
|
|
42
|
+
interface SpeechOptions {
|
|
43
|
+
/** Text to synthesize (max 4096 characters). */
|
|
44
|
+
input: string;
|
|
45
|
+
/** Model to use. Default: "tts-1". */
|
|
46
|
+
model?: string;
|
|
47
|
+
/** Voice name. Default: "alloy". */
|
|
48
|
+
voice?: Voice;
|
|
49
|
+
/** Target language. */
|
|
50
|
+
language?: string;
|
|
51
|
+
/** Audio format. Default: "mp3". */
|
|
52
|
+
responseFormat?: AudioFormat;
|
|
53
|
+
/** Playback speed. Default: 1.0. */
|
|
54
|
+
speed?: number;
|
|
55
|
+
/** Include word-level timestamps (returns JSON instead of audio). */
|
|
56
|
+
wordTimestamps?: boolean;
|
|
57
|
+
}
|
|
58
|
+
interface SpeechWithTimestamps {
|
|
59
|
+
audio: string;
|
|
60
|
+
word_timestamps: {
|
|
61
|
+
word: string;
|
|
62
|
+
start: number;
|
|
63
|
+
end: number;
|
|
64
|
+
}[];
|
|
65
|
+
}
|
|
66
|
+
interface ApiErrorBody {
|
|
67
|
+
message: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
}
|
|
70
|
+
interface SpeakEasyOptions {
|
|
71
|
+
/** Override the base URL (default: `https://www.tryspeakeasy.io`). */
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
/** Override the global `fetch` implementation. */
|
|
74
|
+
fetch?: typeof globalThis.fetch;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* SpeakEasy API client.
|
|
79
|
+
*
|
|
80
|
+
* Affordable speech-to-text and text-to-speech for developers.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const se = new SpeakEasy('sk-se-your_api_key')
|
|
85
|
+
*
|
|
86
|
+
* // Transcribe audio
|
|
87
|
+
* const { text } = await se.transcribe({ url: 'https://example.com/audio.mp3' })
|
|
88
|
+
*
|
|
89
|
+
* // Generate speech
|
|
90
|
+
* const audio = await se.speech({ input: 'Hello world', voice: 'nova' })
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see https://www.tryspeakeasy.io — Affordable Speech-to-Text & Text-to-Speech API
|
|
94
|
+
*/
|
|
95
|
+
declare class SpeakEasy {
|
|
96
|
+
private readonly apiKey;
|
|
97
|
+
private readonly baseUrl;
|
|
98
|
+
private readonly _fetch;
|
|
99
|
+
constructor(apiKey: string, options?: SpeakEasyOptions);
|
|
100
|
+
private authHeaders;
|
|
101
|
+
private handleError;
|
|
102
|
+
/**
|
|
103
|
+
* Transcribe audio to text.
|
|
104
|
+
*
|
|
105
|
+
* Provide either a `file` (Blob/File) or a `url` pointing to the audio.
|
|
106
|
+
* Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).
|
|
107
|
+
*
|
|
108
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
109
|
+
*/
|
|
110
|
+
transcribe(options: TranscribeOptions): Promise<TranscriptionResult | VerboseTranscriptionResult | string>;
|
|
111
|
+
/**
|
|
112
|
+
* Convert text to speech audio.
|
|
113
|
+
*
|
|
114
|
+
* Returns an `ArrayBuffer` of the audio data, or a JSON object with
|
|
115
|
+
* timestamps if `wordTimestamps` is enabled.
|
|
116
|
+
*
|
|
117
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
118
|
+
*/
|
|
119
|
+
speech(options: SpeechOptions): Promise<ArrayBuffer | SpeechWithTimestamps>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Error thrown when the SpeakEasy API returns a non-2xx response.
|
|
124
|
+
*/
|
|
125
|
+
declare class SpeakEasyError extends Error {
|
|
126
|
+
/** HTTP status code. */
|
|
127
|
+
readonly status: number;
|
|
128
|
+
/** Error type from the API. */
|
|
129
|
+
readonly type: string | undefined;
|
|
130
|
+
constructor(body: ApiErrorBody, status: number);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { type ApiErrorBody, type AudioFormat, type ResponseFormat, SpeakEasy, SpeakEasyError, type SpeakEasyOptions, type SpeechOptions, type SpeechWithTimestamps, type TranscribeOptions, type TranscriptionResult, type VerboseTranscriptionResult, type Voice };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
SpeakEasy: () => SpeakEasy,
|
|
24
|
+
SpeakEasyError: () => SpeakEasyError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/errors.ts
|
|
29
|
+
var SpeakEasyError = class extends Error {
|
|
30
|
+
constructor(body, status) {
|
|
31
|
+
super(body.message);
|
|
32
|
+
this.name = "SpeakEasyError";
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.type = body.type;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// src/client.ts
|
|
39
|
+
var DEFAULT_BASE_URL = "https://www.tryspeakeasy.io";
|
|
40
|
+
var SpeakEasy = class {
|
|
41
|
+
constructor(apiKey, options) {
|
|
42
|
+
if (!apiKey) throw new Error("An API key is required. Get one at https://app.tryspeakeasy.io");
|
|
43
|
+
this.apiKey = apiKey;
|
|
44
|
+
this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
45
|
+
this._fetch = options?.fetch ?? globalThis.fetch;
|
|
46
|
+
}
|
|
47
|
+
// -------------------------------------------------------------------------
|
|
48
|
+
// Internal helpers
|
|
49
|
+
// -------------------------------------------------------------------------
|
|
50
|
+
authHeaders() {
|
|
51
|
+
return { Authorization: `Bearer ${this.apiKey}` };
|
|
52
|
+
}
|
|
53
|
+
async handleError(res) {
|
|
54
|
+
let body;
|
|
55
|
+
try {
|
|
56
|
+
body = await res.json();
|
|
57
|
+
} catch {
|
|
58
|
+
body = { message: res.statusText };
|
|
59
|
+
}
|
|
60
|
+
throw new SpeakEasyError(body, res.status);
|
|
61
|
+
}
|
|
62
|
+
// -------------------------------------------------------------------------
|
|
63
|
+
// Speech-to-Text
|
|
64
|
+
// -------------------------------------------------------------------------
|
|
65
|
+
/**
|
|
66
|
+
* Transcribe audio to text.
|
|
67
|
+
*
|
|
68
|
+
* Provide either a `file` (Blob/File) or a `url` pointing to the audio.
|
|
69
|
+
* Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).
|
|
70
|
+
*
|
|
71
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
72
|
+
*/
|
|
73
|
+
async transcribe(options) {
|
|
74
|
+
const form = new FormData();
|
|
75
|
+
if (options.file) form.append("file", options.file);
|
|
76
|
+
if (options.url) form.append("url", options.url);
|
|
77
|
+
if (options.model) form.append("model", options.model);
|
|
78
|
+
if (options.language) form.append("language", options.language);
|
|
79
|
+
if (options.prompt) form.append("prompt", options.prompt);
|
|
80
|
+
if (options.speakerLabels) form.append("speaker_labels", "true");
|
|
81
|
+
if (options.translate) form.append("translate", "true");
|
|
82
|
+
if (options.wordTimestamps) form.append("word_timestamps", "true");
|
|
83
|
+
if (options.responseFormat) form.append("response_format", options.responseFormat);
|
|
84
|
+
if (options.callbackUrl) form.append("callback_url", options.callbackUrl);
|
|
85
|
+
const res = await this._fetch(`${this.baseUrl}/api/v1/audio/transcriptions`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: this.authHeaders(),
|
|
88
|
+
body: form
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) return this.handleError(res);
|
|
91
|
+
const format = options.responseFormat ?? "json";
|
|
92
|
+
if (format === "text" || format === "srt" || format === "vtt") {
|
|
93
|
+
return res.text();
|
|
94
|
+
}
|
|
95
|
+
return res.json();
|
|
96
|
+
}
|
|
97
|
+
// -------------------------------------------------------------------------
|
|
98
|
+
// Text-to-Speech
|
|
99
|
+
// -------------------------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* Convert text to speech audio.
|
|
102
|
+
*
|
|
103
|
+
* Returns an `ArrayBuffer` of the audio data, or a JSON object with
|
|
104
|
+
* timestamps if `wordTimestamps` is enabled.
|
|
105
|
+
*
|
|
106
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
107
|
+
*/
|
|
108
|
+
async speech(options) {
|
|
109
|
+
const body = { input: options.input };
|
|
110
|
+
if (options.model) body.model = options.model;
|
|
111
|
+
if (options.voice) body.voice = options.voice;
|
|
112
|
+
if (options.language) body.language = options.language;
|
|
113
|
+
if (options.responseFormat) body.response_format = options.responseFormat;
|
|
114
|
+
if (options.speed) body.speed = options.speed;
|
|
115
|
+
if (options.wordTimestamps) body.word_timestamps = true;
|
|
116
|
+
const res = await this._fetch(`${this.baseUrl}/api/v1/audio/speech`, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: {
|
|
119
|
+
...this.authHeaders(),
|
|
120
|
+
"Content-Type": "application/json"
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify(body)
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok) return this.handleError(res);
|
|
125
|
+
if (options.wordTimestamps) {
|
|
126
|
+
return res.json();
|
|
127
|
+
}
|
|
128
|
+
return res.arrayBuffer();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
132
|
+
0 && (module.exports = {
|
|
133
|
+
SpeakEasy,
|
|
134
|
+
SpeakEasyError
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { SpeakEasy } from './client'\nexport { SpeakEasyError } from './errors'\nexport type {\n ApiErrorBody,\n AudioFormat,\n ResponseFormat,\n SpeakEasyOptions,\n SpeechOptions,\n SpeechWithTimestamps,\n TranscribeOptions,\n TranscriptionResult,\n VerboseTranscriptionResult,\n Voice,\n} from './types'\n","import type { ApiErrorBody } from './types'\n\n/**\n * Error thrown when the SpeakEasy API returns a non-2xx response.\n */\nexport class SpeakEasyError extends Error {\n /** HTTP status code. */\n readonly status: number\n /** Error type from the API. */\n readonly type: string | undefined\n\n constructor(body: ApiErrorBody, status: number) {\n super(body.message)\n this.name = 'SpeakEasyError'\n this.status = status\n this.type = body.type\n }\n}\n","import { SpeakEasyError } from './errors'\nimport type {\n SpeakEasyOptions,\n SpeechOptions,\n SpeechWithTimestamps,\n TranscribeOptions,\n TranscriptionResult,\n VerboseTranscriptionResult,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://www.tryspeakeasy.io'\n\n/**\n * SpeakEasy API client.\n *\n * Affordable speech-to-text and text-to-speech for developers.\n *\n * @example\n * ```ts\n * const se = new SpeakEasy('sk-se-your_api_key')\n *\n * // Transcribe audio\n * const { text } = await se.transcribe({ url: 'https://example.com/audio.mp3' })\n *\n * // Generate speech\n * const audio = await se.speech({ input: 'Hello world', voice: 'nova' })\n * ```\n *\n * @see https://www.tryspeakeasy.io — Affordable Speech-to-Text & Text-to-Speech API\n */\nexport class SpeakEasy {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly _fetch: typeof globalThis.fetch\n\n constructor(apiKey: string, options?: SpeakEasyOptions) {\n if (!apiKey) throw new Error('An API key is required. Get one at https://app.tryspeakeasy.io')\n this.apiKey = apiKey\n this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '')\n this._fetch = options?.fetch ?? globalThis.fetch\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers\n // -------------------------------------------------------------------------\n\n private authHeaders(): Record<string, string> {\n return { Authorization: `Bearer ${this.apiKey}` }\n }\n\n private async handleError(res: Response): Promise<never> {\n let body: { message: string; type?: string }\n try {\n body = await res.json()\n } catch {\n body = { message: res.statusText }\n }\n throw new SpeakEasyError(body, res.status)\n }\n\n // -------------------------------------------------------------------------\n // Speech-to-Text\n // -------------------------------------------------------------------------\n\n /**\n * Transcribe audio to text.\n *\n * Provide either a `file` (Blob/File) or a `url` pointing to the audio.\n * Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).\n *\n * @see https://www.tryspeakeasy.io/docs — API documentation\n */\n async transcribe(options: TranscribeOptions): Promise<TranscriptionResult | VerboseTranscriptionResult | string> {\n const form = new FormData()\n\n if (options.file) form.append('file', options.file)\n if (options.url) form.append('url', options.url)\n if (options.model) form.append('model', options.model)\n if (options.language) form.append('language', options.language)\n if (options.prompt) form.append('prompt', options.prompt)\n if (options.speakerLabels) form.append('speaker_labels', 'true')\n if (options.translate) form.append('translate', 'true')\n if (options.wordTimestamps) form.append('word_timestamps', 'true')\n if (options.responseFormat) form.append('response_format', options.responseFormat)\n if (options.callbackUrl) form.append('callback_url', options.callbackUrl)\n\n const res = await this._fetch(`${this.baseUrl}/api/v1/audio/transcriptions`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: form,\n })\n\n if (!res.ok) return this.handleError(res)\n\n const format = options.responseFormat ?? 'json'\n if (format === 'text' || format === 'srt' || format === 'vtt') {\n return res.text()\n }\n return res.json()\n }\n\n // -------------------------------------------------------------------------\n // Text-to-Speech\n // -------------------------------------------------------------------------\n\n /**\n * Convert text to speech audio.\n *\n * Returns an `ArrayBuffer` of the audio data, or a JSON object with\n * timestamps if `wordTimestamps` is enabled.\n *\n * @see https://www.tryspeakeasy.io/docs — API documentation\n */\n async speech(options: SpeechOptions): Promise<ArrayBuffer | SpeechWithTimestamps> {\n const body: Record<string, unknown> = { input: options.input }\n if (options.model) body.model = options.model\n if (options.voice) body.voice = options.voice\n if (options.language) body.language = options.language\n if (options.responseFormat) body.response_format = options.responseFormat\n if (options.speed) body.speed = options.speed\n if (options.wordTimestamps) body.word_timestamps = true\n\n const res = await this._fetch(`${this.baseUrl}/api/v1/audio/speech`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) return this.handleError(res)\n\n if (options.wordTimestamps) {\n return res.json() as Promise<SpeechWithTimestamps>\n }\n return res.arrayBuffer()\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SpeakEasyError = class extends Error {
|
|
3
|
+
constructor(body, status) {
|
|
4
|
+
super(body.message);
|
|
5
|
+
this.name = "SpeakEasyError";
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.type = body.type;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/client.ts
|
|
12
|
+
var DEFAULT_BASE_URL = "https://www.tryspeakeasy.io";
|
|
13
|
+
var SpeakEasy = class {
|
|
14
|
+
constructor(apiKey, options) {
|
|
15
|
+
if (!apiKey) throw new Error("An API key is required. Get one at https://app.tryspeakeasy.io");
|
|
16
|
+
this.apiKey = apiKey;
|
|
17
|
+
this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
18
|
+
this._fetch = options?.fetch ?? globalThis.fetch;
|
|
19
|
+
}
|
|
20
|
+
// -------------------------------------------------------------------------
|
|
21
|
+
// Internal helpers
|
|
22
|
+
// -------------------------------------------------------------------------
|
|
23
|
+
authHeaders() {
|
|
24
|
+
return { Authorization: `Bearer ${this.apiKey}` };
|
|
25
|
+
}
|
|
26
|
+
async handleError(res) {
|
|
27
|
+
let body;
|
|
28
|
+
try {
|
|
29
|
+
body = await res.json();
|
|
30
|
+
} catch {
|
|
31
|
+
body = { message: res.statusText };
|
|
32
|
+
}
|
|
33
|
+
throw new SpeakEasyError(body, res.status);
|
|
34
|
+
}
|
|
35
|
+
// -------------------------------------------------------------------------
|
|
36
|
+
// Speech-to-Text
|
|
37
|
+
// -------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Transcribe audio to text.
|
|
40
|
+
*
|
|
41
|
+
* Provide either a `file` (Blob/File) or a `url` pointing to the audio.
|
|
42
|
+
* Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).
|
|
43
|
+
*
|
|
44
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
45
|
+
*/
|
|
46
|
+
async transcribe(options) {
|
|
47
|
+
const form = new FormData();
|
|
48
|
+
if (options.file) form.append("file", options.file);
|
|
49
|
+
if (options.url) form.append("url", options.url);
|
|
50
|
+
if (options.model) form.append("model", options.model);
|
|
51
|
+
if (options.language) form.append("language", options.language);
|
|
52
|
+
if (options.prompt) form.append("prompt", options.prompt);
|
|
53
|
+
if (options.speakerLabels) form.append("speaker_labels", "true");
|
|
54
|
+
if (options.translate) form.append("translate", "true");
|
|
55
|
+
if (options.wordTimestamps) form.append("word_timestamps", "true");
|
|
56
|
+
if (options.responseFormat) form.append("response_format", options.responseFormat);
|
|
57
|
+
if (options.callbackUrl) form.append("callback_url", options.callbackUrl);
|
|
58
|
+
const res = await this._fetch(`${this.baseUrl}/api/v1/audio/transcriptions`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: this.authHeaders(),
|
|
61
|
+
body: form
|
|
62
|
+
});
|
|
63
|
+
if (!res.ok) return this.handleError(res);
|
|
64
|
+
const format = options.responseFormat ?? "json";
|
|
65
|
+
if (format === "text" || format === "srt" || format === "vtt") {
|
|
66
|
+
return res.text();
|
|
67
|
+
}
|
|
68
|
+
return res.json();
|
|
69
|
+
}
|
|
70
|
+
// -------------------------------------------------------------------------
|
|
71
|
+
// Text-to-Speech
|
|
72
|
+
// -------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Convert text to speech audio.
|
|
75
|
+
*
|
|
76
|
+
* Returns an `ArrayBuffer` of the audio data, or a JSON object with
|
|
77
|
+
* timestamps if `wordTimestamps` is enabled.
|
|
78
|
+
*
|
|
79
|
+
* @see https://www.tryspeakeasy.io/docs — API documentation
|
|
80
|
+
*/
|
|
81
|
+
async speech(options) {
|
|
82
|
+
const body = { input: options.input };
|
|
83
|
+
if (options.model) body.model = options.model;
|
|
84
|
+
if (options.voice) body.voice = options.voice;
|
|
85
|
+
if (options.language) body.language = options.language;
|
|
86
|
+
if (options.responseFormat) body.response_format = options.responseFormat;
|
|
87
|
+
if (options.speed) body.speed = options.speed;
|
|
88
|
+
if (options.wordTimestamps) body.word_timestamps = true;
|
|
89
|
+
const res = await this._fetch(`${this.baseUrl}/api/v1/audio/speech`, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: {
|
|
92
|
+
...this.authHeaders(),
|
|
93
|
+
"Content-Type": "application/json"
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(body)
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) return this.handleError(res);
|
|
98
|
+
if (options.wordTimestamps) {
|
|
99
|
+
return res.json();
|
|
100
|
+
}
|
|
101
|
+
return res.arrayBuffer();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
SpeakEasy,
|
|
106
|
+
SpeakEasyError
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["import type { ApiErrorBody } from './types'\n\n/**\n * Error thrown when the SpeakEasy API returns a non-2xx response.\n */\nexport class SpeakEasyError extends Error {\n /** HTTP status code. */\n readonly status: number\n /** Error type from the API. */\n readonly type: string | undefined\n\n constructor(body: ApiErrorBody, status: number) {\n super(body.message)\n this.name = 'SpeakEasyError'\n this.status = status\n this.type = body.type\n }\n}\n","import { SpeakEasyError } from './errors'\nimport type {\n SpeakEasyOptions,\n SpeechOptions,\n SpeechWithTimestamps,\n TranscribeOptions,\n TranscriptionResult,\n VerboseTranscriptionResult,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://www.tryspeakeasy.io'\n\n/**\n * SpeakEasy API client.\n *\n * Affordable speech-to-text and text-to-speech for developers.\n *\n * @example\n * ```ts\n * const se = new SpeakEasy('sk-se-your_api_key')\n *\n * // Transcribe audio\n * const { text } = await se.transcribe({ url: 'https://example.com/audio.mp3' })\n *\n * // Generate speech\n * const audio = await se.speech({ input: 'Hello world', voice: 'nova' })\n * ```\n *\n * @see https://www.tryspeakeasy.io — Affordable Speech-to-Text & Text-to-Speech API\n */\nexport class SpeakEasy {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly _fetch: typeof globalThis.fetch\n\n constructor(apiKey: string, options?: SpeakEasyOptions) {\n if (!apiKey) throw new Error('An API key is required. Get one at https://app.tryspeakeasy.io')\n this.apiKey = apiKey\n this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '')\n this._fetch = options?.fetch ?? globalThis.fetch\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers\n // -------------------------------------------------------------------------\n\n private authHeaders(): Record<string, string> {\n return { Authorization: `Bearer ${this.apiKey}` }\n }\n\n private async handleError(res: Response): Promise<never> {\n let body: { message: string; type?: string }\n try {\n body = await res.json()\n } catch {\n body = { message: res.statusText }\n }\n throw new SpeakEasyError(body, res.status)\n }\n\n // -------------------------------------------------------------------------\n // Speech-to-Text\n // -------------------------------------------------------------------------\n\n /**\n * Transcribe audio to text.\n *\n * Provide either a `file` (Blob/File) or a `url` pointing to the audio.\n * Supports mp3, wav, flac, aac, opus, ogg, m4a, mp4, webm (max 100 MB).\n *\n * @see https://www.tryspeakeasy.io/docs — API documentation\n */\n async transcribe(options: TranscribeOptions): Promise<TranscriptionResult | VerboseTranscriptionResult | string> {\n const form = new FormData()\n\n if (options.file) form.append('file', options.file)\n if (options.url) form.append('url', options.url)\n if (options.model) form.append('model', options.model)\n if (options.language) form.append('language', options.language)\n if (options.prompt) form.append('prompt', options.prompt)\n if (options.speakerLabels) form.append('speaker_labels', 'true')\n if (options.translate) form.append('translate', 'true')\n if (options.wordTimestamps) form.append('word_timestamps', 'true')\n if (options.responseFormat) form.append('response_format', options.responseFormat)\n if (options.callbackUrl) form.append('callback_url', options.callbackUrl)\n\n const res = await this._fetch(`${this.baseUrl}/api/v1/audio/transcriptions`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: form,\n })\n\n if (!res.ok) return this.handleError(res)\n\n const format = options.responseFormat ?? 'json'\n if (format === 'text' || format === 'srt' || format === 'vtt') {\n return res.text()\n }\n return res.json()\n }\n\n // -------------------------------------------------------------------------\n // Text-to-Speech\n // -------------------------------------------------------------------------\n\n /**\n * Convert text to speech audio.\n *\n * Returns an `ArrayBuffer` of the audio data, or a JSON object with\n * timestamps if `wordTimestamps` is enabled.\n *\n * @see https://www.tryspeakeasy.io/docs — API documentation\n */\n async speech(options: SpeechOptions): Promise<ArrayBuffer | SpeechWithTimestamps> {\n const body: Record<string, unknown> = { input: options.input }\n if (options.model) body.model = options.model\n if (options.voice) body.voice = options.voice\n if (options.language) body.language = options.language\n if (options.responseFormat) body.response_format = options.responseFormat\n if (options.speed) body.speed = options.speed\n if (options.wordTimestamps) body.word_timestamps = true\n\n const res = await this._fetch(`${this.baseUrl}/api/v1/audio/speech`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) return this.handleError(res)\n\n if (options.wordTimestamps) {\n return res.json() as Promise<SpeechWithTimestamps>\n }\n return res.arrayBuffer()\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tryspeakeasy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Node.js/TypeScript SDK for the SpeakEasy API — affordable speech-to-text and text-to-speech for developers.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"speakeasy",
|
|
24
|
+
"speech-to-text",
|
|
25
|
+
"text-to-speech",
|
|
26
|
+
"transcription",
|
|
27
|
+
"tts",
|
|
28
|
+
"stt",
|
|
29
|
+
"audio",
|
|
30
|
+
"voice",
|
|
31
|
+
"api",
|
|
32
|
+
"sdk"
|
|
33
|
+
],
|
|
34
|
+
"author": "SIÁN Agency (https://www.sian-agency.online)",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"homepage": "https://www.tryspeakeasy.io",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/rara-cyber/speakeasy-js.git"
|
|
40
|
+
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/rara-cyber/speakeasy-js/issues"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"tsup": "^8.0.0",
|
|
49
|
+
"typescript": "^5.4.0"
|
|
50
|
+
}
|
|
51
|
+
}
|