@vocalstack/js-sdk 2.0.0-alpha.2 → 2.0.0-alpha.4
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 +2 -4
- package/SKILL.md +1 -27
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/realtime.d.ts +5 -0
- package/dist/realtime.js +8 -3
- package/dist/resources.d.ts +23 -48
- package/dist/resources.js +35 -94
- package/package.json +2 -2
- package/skills/vocalstack/SKILL.md +1 -27
package/README.md
CHANGED
|
@@ -32,7 +32,6 @@ npm install @vocalstack/js-sdk
|
|
|
32
32
|
- [Quickstart](https://github.com/vocalstack/js-sdk/blob/main/docs/quickstart.md): An API key, the SDK, and your first transcript in a dozen lines.
|
|
33
33
|
- [Transcribe a file](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-file.md): Upload a file, wait for its job, read the transcript and export it. Asynchronous; nothing to keep open.
|
|
34
34
|
- [Transcribe a link](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-link.md): The server fetches a public URL, a YouTube video or a recording on a video or audio site, then transcribes it like a file. Asynchronous, with a fetch phase first.
|
|
35
|
-
- [Transcribe a batch of files](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-batch.md): Send many files or links as one batch, start it once, and read every transcript when it is done. Cheaper than one transcription per file.
|
|
36
35
|
- [Search your transcriptions](https://github.com/vocalstack/js-sdk/blob/main/docs/search-transcriptions.md): Find transcriptions by words in their name or link, site, language, kind, tag and date, keep the shared ones, and play each with its share code.
|
|
37
36
|
- [Stream a microphone](https://github.com/vocalstack/js-sdk/blob/main/docs/stream-a-microphone.md): Live audio in, transcript events out, over one WebSocket. Drafts replace the live tail; commits append.
|
|
38
37
|
- [Stream a file at full speed](https://github.com/vocalstack/js-sdk/blob/main/docs/stream-a-file.md): Send a file's bytes through a realtime session and read the transcript as fast as the server makes it. Nothing is stored.
|
|
@@ -53,9 +52,8 @@ npm install @vocalstack/js-sdk
|
|
|
53
52
|
| transcription | a file, link, microphone or stream, transcribed and stored (`live: true` for a microphone or stream) | `vs.transcriptions` |
|
|
54
53
|
| recording | one take inside a broadcast or a transcription | `vs.recordings` |
|
|
55
54
|
| job | a file or link recording's transcription work | `vs.jobs` |
|
|
56
|
-
| batch | many files transcribed together, for less than one transcription each | `vs.batches` |
|
|
57
55
|
|
|
58
|
-
The other groups: `vs.corrections`, `vs.shareLinks`, `vs.voices`,
|
|
56
|
+
The other groups: `vs.corrections`, `vs.shareLinks`, `vs.speakers`, `vs.voices`,
|
|
59
57
|
`vs.search`, `vs.me`, `vs.languages`, `vs.rtmp`, `vs.events`, `vs.meta`.
|
|
60
58
|
Method names follow the document's `operationId`s (`broadcasts.startRecording`
|
|
61
59
|
is `POST /v1/broadcasts/{id}/recordings`); lists return arrays.
|
|
@@ -129,7 +127,7 @@ Browser microphone capture ships as `@vocalstack/js-sdk/mic`
|
|
|
129
127
|
## Binary answers
|
|
130
128
|
|
|
131
129
|
`recordings.export`, `recordings.clip`, `recordings.voiceClip`, `jobs.preview`,
|
|
132
|
-
`voices.preview`, `
|
|
130
|
+
`voices.preview`, `speakers.voicePreview` and `speakers.sample` return the
|
|
133
131
|
`Response` itself: `.text()`, `.arrayBuffer()` or stream it.
|
|
134
132
|
`recordings.audioUrl` returns the signed media URL.
|
|
135
133
|
|
package/SKILL.md
CHANGED
|
@@ -19,9 +19,6 @@ one group per resource: `vs.transcriptions`, `vs.jobs`, `vs.recordings`,
|
|
|
19
19
|
- A **job** is a file or link recording's transcription work:
|
|
20
20
|
`vs.jobs.wait(recordingId)` polls it until it is `done` or `failed`
|
|
21
21
|
(`{ onProgress: (job) => … }` sees each read: `job.state`, `job.progress.pct`).
|
|
22
|
-
- A **batch** is many files transcribed together for less than one
|
|
23
|
-
transcription each: `vs.batches.create()`, `addFile`/`addUrl` per file,
|
|
24
|
-
`start`, then `wait` (section 6).
|
|
25
22
|
- A **broadcast** is a link listeners open to follow a live recording.
|
|
26
23
|
- A **realtime session** (`vs.realtime`) is a socket you stream audio into and
|
|
27
24
|
read the transcript from. Nothing is stored. "Session" means only this.
|
|
@@ -189,28 +186,6 @@ const { hits: found } = await vs.search.vector('how much does housing cost');
|
|
|
189
186
|
for (const h of found) console.log(h.similarity.toFixed(2), h.passage.mediaStart, h.passage.text);
|
|
190
187
|
```
|
|
191
188
|
|
|
192
|
-
## 6. A batch of files
|
|
193
|
-
|
|
194
|
-
Many files at once cost less as a batch: one create, one minimum charge for
|
|
195
|
-
the whole batch. Its files get transcripts, exports and speaker labels (when
|
|
196
|
-
`settings.speakerLabels` asks), never a summary, title, share link or voices.
|
|
197
|
-
|
|
198
|
-
```js
|
|
199
|
-
import { VocalStack } from '@vocalstack/js-sdk';
|
|
200
|
-
const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
|
|
201
|
-
|
|
202
|
-
const batch = await vs.batches.create({ name: 'Interviews', settings: { spokenLanguage: 'en' } });
|
|
203
|
-
for (const path of process.argv.slice(2)) await vs.batches.addFile(batch.id, { file: path }); // or addUrl(batch.id, url)
|
|
204
|
-
await vs.batches.start(batch.id);
|
|
205
|
-
const done = await vs.batches.wait(batch.id); // done (or stopped); check done.counts.failed
|
|
206
|
-
for (const tx of done.files ?? []) {
|
|
207
|
-
if (tx.job?.state !== 'done') continue;
|
|
208
|
-
const { sentences } = await vs.recordings.transcript(tx.job.recordingId);
|
|
209
|
-
console.log(tx.name, sentences.map((s) => s.text).join(' '));
|
|
210
|
-
}
|
|
211
|
-
// vs.batches.export(batch.id, 'srt') is every finished transcript in one zip.
|
|
212
|
-
```
|
|
213
|
-
|
|
214
189
|
## Errors
|
|
215
190
|
|
|
216
191
|
A failed call throws `VocalStackError` with `code`, `message`, `status`,
|
|
@@ -248,8 +223,7 @@ try {
|
|
|
248
223
|
- The other groups: `vs.transcriptions` (`list`, `get`, `update`, `archive`,
|
|
249
224
|
`restore`, `purge`, `listShareLinks`, `createShareLink`), `vs.recordings`
|
|
250
225
|
(`get`, `summarize`, `summary`, `translation`, `audioUrl`, `subscribe` for a
|
|
251
|
-
live transcript feed), `vs.
|
|
252
|
-
`wait`, `get`, `list`, `export`, `stop`, `delete`), `vs.corrections`, `vs.shareLinks`, `vs.voices`,
|
|
226
|
+
live transcript feed), `vs.corrections`, `vs.shareLinks`, `vs.speakers`, `vs.voices`,
|
|
253
227
|
`vs.broadcasts`, `vs.me` (`get`, `usage`), `vs.languages`,
|
|
254
228
|
`vs.rtmp`, `vs.events`, `vs.meta`. Each method is named after its operation
|
|
255
229
|
in the OpenAPI document (`transcriptions.create` is `POST /v1/transcriptions`).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { type ClientOptions } from './http.js';
|
|
2
2
|
import { Realtime } from './realtime.js';
|
|
3
|
-
import {
|
|
3
|
+
import { Billing, Broadcasts, Connect, Corrections, Events, Jobs, Languages, MeApi, Meta, Recordings, Rtmp, Search, ShareLinks, Speakers, Tags, Transcriptions, Voices } from './resources.js';
|
|
4
4
|
export type { ClientOptions, CallOptions, ReadAs, Query } from './http.js';
|
|
5
5
|
export { DEFAULT_BASE_URL } from './http.js';
|
|
6
6
|
export { VocalStackError } from './errors.js';
|
|
7
7
|
export type { ConnectTokenErrorCode, VocalStackErrorOptions } from './errors.js';
|
|
8
8
|
export { RealtimeSession } from './realtime.js';
|
|
9
|
-
export type { ConnectParams, SessionEvent } from './realtime.js';
|
|
9
|
+
export type { ConnectParams, QueuedInfo, SessionEvent } from './realtime.js';
|
|
10
10
|
export type { FileInput } from './file.js';
|
|
11
11
|
export { Realtime, applySentence } from './realtime.js';
|
|
12
12
|
export type { ConnectOptions, TranscribeOptions, RealtimeTranscript } from './realtime.js';
|
|
13
13
|
export { Subscription } from './subscription.js';
|
|
14
14
|
export type { SubscribeOptions, SubscriptionEvent } from './subscription.js';
|
|
15
15
|
export type { WsLike } from './ws.js';
|
|
16
|
-
export {
|
|
16
|
+
export { Broadcasts, Connect, Corrections, Events, Jobs, Languages, MeApi, Meta, Recordings, Rtmp, Search, ShareLinks, Speakers, Tags, Transcriptions, Voices, playableFormat, } from './resources.js';
|
|
17
17
|
export type { AudioKind, MediaAuth, MediaFormat, RenderVoice, VoicesChoice } from './resources.js';
|
|
18
|
-
export type {
|
|
18
|
+
export type { ConnectToken, ConnectTokenInput, CreateTranscriptionInput, LifecycleFilter, Me, PageOptions, RecordingPageOptions, SearchOptions, TranscriptionFilters, Upload, UsageChargesOptions, UsageOptions } from './resources.js';
|
|
19
19
|
export type * from '@vocalstack/contract';
|
|
20
20
|
export type VocalStackOptions = ClientOptions;
|
|
21
21
|
export declare class VocalStack {
|
|
@@ -23,12 +23,12 @@ export declare class VocalStack {
|
|
|
23
23
|
readonly realtime: Realtime;
|
|
24
24
|
readonly broadcasts: Broadcasts;
|
|
25
25
|
readonly transcriptions: Transcriptions;
|
|
26
|
-
readonly batches: Batches;
|
|
27
26
|
readonly recordings: Recordings;
|
|
28
27
|
readonly jobs: Jobs;
|
|
29
28
|
readonly corrections: Corrections;
|
|
30
29
|
readonly shareLinks: ShareLinks;
|
|
31
30
|
readonly tags: Tags;
|
|
31
|
+
readonly speakers: Speakers;
|
|
32
32
|
readonly voices: Voices;
|
|
33
33
|
readonly search: Search;
|
|
34
34
|
readonly me: MeApi;
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { Transport } from './http.js';
|
|
2
2
|
import { Realtime } from './realtime.js';
|
|
3
|
-
import {
|
|
3
|
+
import { Billing, Broadcasts, Connect, Corrections, Events, Jobs, Languages, MeApi, Meta, Recordings, Rtmp, Search, ShareLinks, Speakers, Tags, Transcriptions, Voices, } from './resources.js';
|
|
4
4
|
export { DEFAULT_BASE_URL } from './http.js';
|
|
5
5
|
export { VocalStackError } from './errors.js';
|
|
6
6
|
export { RealtimeSession } from './realtime.js';
|
|
7
7
|
export { Realtime, applySentence } from './realtime.js';
|
|
8
8
|
export { Subscription } from './subscription.js';
|
|
9
|
-
export {
|
|
9
|
+
export { Broadcasts, Connect, Corrections, Events, Jobs, Languages, MeApi, Meta, Recordings, Rtmp, Search, ShareLinks, Speakers, Tags, Transcriptions, Voices, playableFormat, } from './resources.js';
|
|
10
10
|
export class VocalStack {
|
|
11
11
|
baseUrl;
|
|
12
12
|
realtime;
|
|
13
13
|
broadcasts;
|
|
14
14
|
transcriptions;
|
|
15
|
-
batches;
|
|
16
15
|
recordings;
|
|
17
16
|
jobs;
|
|
18
17
|
corrections;
|
|
19
18
|
shareLinks;
|
|
20
19
|
tags;
|
|
20
|
+
speakers;
|
|
21
21
|
voices;
|
|
22
22
|
search;
|
|
23
23
|
me;
|
|
@@ -33,12 +33,12 @@ export class VocalStack {
|
|
|
33
33
|
this.realtime = new Realtime(t);
|
|
34
34
|
this.broadcasts = new Broadcasts(t);
|
|
35
35
|
this.transcriptions = new Transcriptions(t);
|
|
36
|
-
this.batches = new Batches(t);
|
|
37
36
|
this.recordings = new Recordings(t);
|
|
38
37
|
this.jobs = new Jobs(t);
|
|
39
38
|
this.corrections = new Corrections(t);
|
|
40
39
|
this.shareLinks = new ShareLinks(t);
|
|
41
40
|
this.tags = new Tags(t);
|
|
41
|
+
this.speakers = new Speakers(t);
|
|
42
42
|
this.voices = new Voices(t);
|
|
43
43
|
this.search = new Search(t);
|
|
44
44
|
this.me = new MeApi(t);
|
package/dist/realtime.d.ts
CHANGED
|
@@ -11,8 +11,12 @@ export interface ConnectParams {
|
|
|
11
11
|
options?: SessionOptions;
|
|
12
12
|
readyDeadlineMs?: number;
|
|
13
13
|
onLoading?(stage: 'download' | 'model'): void;
|
|
14
|
+
onQueued?(queued: QueuedInfo): void;
|
|
14
15
|
onFrame?(frame: ServerFrame): void;
|
|
15
16
|
}
|
|
17
|
+
export type QueuedInfo = Omit<Extract<ServerFrame, {
|
|
18
|
+
type: 'session.queued';
|
|
19
|
+
}>, 'type'>;
|
|
16
20
|
export declare function engineLost(closeCode?: number): VocalStackError;
|
|
17
21
|
export declare function upgradeRefused(status: number | undefined, body: string): VocalStackError;
|
|
18
22
|
export declare const RESTART_CLOSE = 1012;
|
|
@@ -41,6 +45,7 @@ export declare class RealtimeSession implements AsyncIterable<SessionEvent> {
|
|
|
41
45
|
}
|
|
42
46
|
export interface ConnectOptions {
|
|
43
47
|
onLoading?(stage: 'download' | 'model'): void;
|
|
48
|
+
onQueued?(queued: QueuedInfo): void;
|
|
44
49
|
onFrame?(frame: ServerFrame): void;
|
|
45
50
|
readyDeadlineMs?: number;
|
|
46
51
|
}
|
package/dist/realtime.js
CHANGED
|
@@ -29,7 +29,7 @@ export function upgradeRefused(status, body) {
|
|
|
29
29
|
export const RESTART_CLOSE = 1012;
|
|
30
30
|
const RESTART_TRIES = 3;
|
|
31
31
|
const MAX_PENDING_BYTES = 4 * 1024 * 1024;
|
|
32
|
-
async function openReady(url, deadlineMs, onLoading, onFrame, attach) {
|
|
32
|
+
async function openReady(url, deadlineMs, onLoading, onQueued, onFrame, attach) {
|
|
33
33
|
const ws = await openWebSocket(url);
|
|
34
34
|
ws.binaryType = 'arraybuffer';
|
|
35
35
|
await new Promise((resolve, reject) => {
|
|
@@ -77,6 +77,10 @@ async function openReady(url, deadlineMs, onLoading, onFrame, attach) {
|
|
|
77
77
|
if (frame.type === 'session.loading') {
|
|
78
78
|
onLoading?.(frame.stage);
|
|
79
79
|
}
|
|
80
|
+
else if (frame.type === 'session.queued') {
|
|
81
|
+
const { type: _type, ...queued } = frame;
|
|
82
|
+
onQueued?.(queued);
|
|
83
|
+
}
|
|
80
84
|
else if (frame.type === 'session.ready') {
|
|
81
85
|
if (!settled) {
|
|
82
86
|
settled = true;
|
|
@@ -142,7 +146,7 @@ export class RealtimeSession {
|
|
|
142
146
|
const deadlineMs = params.readyDeadlineMs ?? DEFAULT_READY_DEADLINE_MS;
|
|
143
147
|
const early = [];
|
|
144
148
|
let session;
|
|
145
|
-
await openReady(params.streamUrl, deadlineMs, params.onLoading, (f) => early.push(f), (ws) => {
|
|
149
|
+
await openReady(params.streamUrl, deadlineMs, params.onLoading, params.onQueued, (f) => early.push(f), (ws) => {
|
|
146
150
|
const s = new RealtimeSession(params.sessionId, ws, params);
|
|
147
151
|
for (const f of early)
|
|
148
152
|
s.#frame(f);
|
|
@@ -160,7 +164,7 @@ export class RealtimeSession {
|
|
|
160
164
|
if (this.#closedByUs)
|
|
161
165
|
break;
|
|
162
166
|
try {
|
|
163
|
-
await openReady(this.#params.streamUrl, deadlineMs, this.#params.onLoading, (f) => this.#frame(f), (ws) => {
|
|
167
|
+
await openReady(this.#params.streamUrl, deadlineMs, this.#params.onLoading, this.#params.onQueued, (f) => this.#frame(f), (ws) => {
|
|
164
168
|
this.#ws = ws;
|
|
165
169
|
this.#reconnecting = false;
|
|
166
170
|
this.#listen();
|
|
@@ -389,6 +393,7 @@ export class Realtime {
|
|
|
389
393
|
options,
|
|
390
394
|
readyDeadlineMs: connect.readyDeadlineMs ?? this.#t.opts.readyDeadlineMs,
|
|
391
395
|
onLoading: connect.onLoading,
|
|
396
|
+
onQueued: connect.onQueued,
|
|
392
397
|
onFrame: connect.onFrame,
|
|
393
398
|
});
|
|
394
399
|
}
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppStreamKey, AudioSourceCheck,
|
|
1
|
+
import type { AppStreamKey, AudioSourceCheck, AutoTopUpSettings, AutoTopUpView, BillingDetails, BillingView, CheckPromoCode, CheckoutView, CreateCheckout, LowBalanceAlertSettings, LowBalanceAlertView, PaymentDocument, PaymentMethodList, PaymentPage, PortalLink, PromoCodeView, SetInterval, SubscriptionView, YearlyOptIn, UsageChargePage, UsageReport, Broadcast, Correction, CorrectionBatch, CorrectionPage, CreateAppStreamKey, CreateAudioSource, CreateLiveTranscription, CreateBroadcast, CreateShareLink, CreateTag, CreateTranscription, CreateSpeaker, CreateSpeakerFromAppearance, CreatedAppStreamKey, ChargePage, ExportFormat, ClientApp, ClientPolicy, Health, LanguageLists, LedgerPage, LinkProbe, PatchSpeaker, PlanList, PublishGrant, Recording, RecordingEvent, RecordingEvents, RecordingPage, RetranscribeLine, RtmpStatus, SearchResults, VectorResults, SettingsPatch, ShareLink, SharedTranscript, StartRecording, StartJob, SummaryStatus, Tag, TagTranscriptions, Transcription, TranscriptionJob, TranscriptionPage, TranscriptSnapshot, UpdateBroadcast, UpdateTag, UpdateTranscription, UpdateShareLink, UploadRecording, Speaker, VoiceCatalogue, VoiceTrack, ManyResult } from '@vocalstack/contract';
|
|
2
2
|
import { Transport, type CallOptions, type ReadAs } from './http.js';
|
|
3
3
|
import { RealtimeSession, type ConnectOptions } from './realtime.js';
|
|
4
4
|
import { Subscription, type SubscribeOptions } from './subscription.js';
|
|
@@ -72,30 +72,7 @@ export declare class Transcriptions extends ParentResource<Transcription, Update
|
|
|
72
72
|
probe(url: string): Promise<LinkProbe>;
|
|
73
73
|
attachBroadcast(id: string, broadcastId: string): Promise<Transcription>;
|
|
74
74
|
detachBroadcast(id: string, broadcastId: string): Promise<Transcription>;
|
|
75
|
-
|
|
76
|
-
export type AddBatchFileInput = Pick<CreateTranscription, 'url' | 'name' | 'startS' | 'endS' | 'durationS'> & {
|
|
77
|
-
file?: Upload;
|
|
78
|
-
fileName?: string;
|
|
79
|
-
};
|
|
80
|
-
export declare class Batches {
|
|
81
|
-
#private;
|
|
82
|
-
constructor(t: Transport);
|
|
83
|
-
create(req?: CreateBatch, call?: CallOptions): Promise<Batch>;
|
|
84
|
-
list(): Promise<Batch[]>;
|
|
85
|
-
listPage(opts?: PageOptions): Promise<BatchPage>;
|
|
86
|
-
get(id: string): Promise<Batch>;
|
|
87
|
-
delete(id: string): Promise<void>;
|
|
88
|
-
addFile(id: string, req: AddBatchFileInput, call?: CallOptions): Promise<Transcription>;
|
|
89
|
-
addUrl(id: string, url: string, opts?: Omit<AddBatchFileInput, 'url' | 'file' | 'fileName'>, call?: CallOptions): Promise<Transcription>;
|
|
90
|
-
start(id: string, call?: CallOptions): Promise<Batch>;
|
|
91
|
-
export(id: string, format: ExportFormat): Promise<Response>;
|
|
92
|
-
stop(id: string): Promise<Batch>;
|
|
93
|
-
wait(id: string, opts?: {
|
|
94
|
-
intervalMs?: number;
|
|
95
|
-
timeoutMs?: number;
|
|
96
|
-
signal?: AbortSignal;
|
|
97
|
-
onProgress?(batch: Batch): void;
|
|
98
|
-
}): Promise<Batch>;
|
|
75
|
+
nameAppearance(id: string, appearance: number, name: string | null): Promise<void>;
|
|
99
76
|
}
|
|
100
77
|
export declare class Recordings {
|
|
101
78
|
#private;
|
|
@@ -170,7 +147,6 @@ export declare class Recordings {
|
|
|
170
147
|
token: string;
|
|
171
148
|
expiresAt: string;
|
|
172
149
|
}>;
|
|
173
|
-
nameSpeaker(id: string, speaker: number, name: string | null): Promise<void>;
|
|
174
150
|
events(id: string, opts?: {
|
|
175
151
|
after?: number;
|
|
176
152
|
limit?: number;
|
|
@@ -237,33 +213,39 @@ export declare class Tags {
|
|
|
237
213
|
delete(id: string): Promise<void>;
|
|
238
214
|
tagTranscriptions(id: string, req: TagTranscriptions): Promise<Tag>;
|
|
239
215
|
}
|
|
240
|
-
export declare class
|
|
216
|
+
export declare class Speakers {
|
|
241
217
|
#private;
|
|
242
218
|
constructor(t: Transport);
|
|
243
219
|
list(opts?: {
|
|
244
220
|
lifecycle?: 'active' | 'archived';
|
|
245
|
-
}): Promise<
|
|
246
|
-
get(id: string): Promise<
|
|
247
|
-
archive(id: string): Promise<
|
|
248
|
-
restore(id: string): Promise<
|
|
221
|
+
}): Promise<Speaker[]>;
|
|
222
|
+
get(id: string): Promise<Speaker>;
|
|
223
|
+
archive(id: string): Promise<Speaker>;
|
|
224
|
+
restore(id: string): Promise<Speaker>;
|
|
249
225
|
archiveMany(ids: string[]): Promise<ManyResult>;
|
|
250
226
|
restoreMany(ids: string[]): Promise<ManyResult>;
|
|
251
227
|
deleteMany(ids: string[]): Promise<ManyResult>;
|
|
252
|
-
create(req: {
|
|
253
|
-
name: string;
|
|
228
|
+
create(req: CreateSpeaker & {
|
|
254
229
|
sample?: Upload;
|
|
255
|
-
sampleUrl?: string;
|
|
256
230
|
fileName?: string;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
draft?: boolean;
|
|
260
|
-
}, call?: CallOptions): Promise<Voice>;
|
|
261
|
-
createFromSpeaker(req: Omit<CreateVoiceFromSpeaker, 'consent'>, call?: CallOptions): Promise<Voice>;
|
|
231
|
+
}, call?: CallOptions): Promise<Speaker>;
|
|
232
|
+
createFromAppearance(req: CreateSpeakerFromAppearance, call?: CallOptions): Promise<Speaker>;
|
|
262
233
|
setConsent(id: string, consent: 'granted' | 'refused', opts?: {
|
|
263
234
|
name?: string;
|
|
264
|
-
}): Promise<
|
|
265
|
-
update(id: string, patch:
|
|
235
|
+
}): Promise<Speaker>;
|
|
236
|
+
update(id: string, patch: PatchSpeaker): Promise<Speaker>;
|
|
266
237
|
delete(id: string): Promise<void>;
|
|
238
|
+
voicePreview(id: string, opts?: {
|
|
239
|
+
lang?: string;
|
|
240
|
+
format?: 'ogg' | 'caf';
|
|
241
|
+
recording?: string;
|
|
242
|
+
asOwner?: boolean;
|
|
243
|
+
} & ReadAs): Promise<Response>;
|
|
244
|
+
sample(id: string): Promise<Response>;
|
|
245
|
+
}
|
|
246
|
+
export declare class Voices {
|
|
247
|
+
#private;
|
|
248
|
+
constructor(t: Transport);
|
|
267
249
|
available(lang: string, opts?: {
|
|
268
250
|
recording?: string;
|
|
269
251
|
asOwner?: boolean;
|
|
@@ -271,13 +253,6 @@ export declare class Voices {
|
|
|
271
253
|
preview(voice: string, lang: string, opts?: {
|
|
272
254
|
format?: 'ogg' | 'caf';
|
|
273
255
|
}): Promise<Response>;
|
|
274
|
-
clonePreview(id: string, opts?: {
|
|
275
|
-
lang?: string;
|
|
276
|
-
format?: 'ogg' | 'caf';
|
|
277
|
-
recording?: string;
|
|
278
|
-
asOwner?: boolean;
|
|
279
|
-
} & ReadAs): Promise<Response>;
|
|
280
|
-
sample(id: string): Promise<Response>;
|
|
281
256
|
}
|
|
282
257
|
export interface SearchOptions extends Omit<TranscriptionFilters, 'lifecycle' | 'q' | 'broadcast'> {
|
|
283
258
|
broadcasts?: string[];
|
package/dist/resources.js
CHANGED
|
@@ -152,71 +152,8 @@ export class Transcriptions extends ParentResource {
|
|
|
152
152
|
detachBroadcast(id, broadcastId) {
|
|
153
153
|
return this.t.json('DELETE', this.p(id, `/broadcasts/${seg(broadcastId)}`));
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
#t;
|
|
158
|
-
constructor(t) {
|
|
159
|
-
this.#t = t;
|
|
160
|
-
}
|
|
161
|
-
#p(id, rest = '') {
|
|
162
|
-
return `/v1/batches/${seg(id)}${rest}`;
|
|
163
|
-
}
|
|
164
|
-
create(req = {}, call = {}) {
|
|
165
|
-
return this.#t.json('POST', '/v1/batches', { body: req, ...call });
|
|
166
|
-
}
|
|
167
|
-
list() {
|
|
168
|
-
return allPages(async (cursor) => {
|
|
169
|
-
const r = await this.listPage({ cursor });
|
|
170
|
-
return { items: r.batches, nextCursor: r.nextCursor };
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
listPage(opts = {}) {
|
|
174
|
-
return this.#t.json('GET', '/v1/batches', { query: { cursor: opts.cursor, limit: opts.limit } });
|
|
175
|
-
}
|
|
176
|
-
get(id) {
|
|
177
|
-
return this.#t.json('GET', this.#p(id));
|
|
178
|
-
}
|
|
179
|
-
async delete(id) {
|
|
180
|
-
await this.#t.json('DELETE', this.#p(id));
|
|
181
|
-
}
|
|
182
|
-
async addFile(id, req, call = {}) {
|
|
183
|
-
const { file, fileName, ...options } = req;
|
|
184
|
-
if (file === undefined)
|
|
185
|
-
return this.#t.json('POST', this.#p(id, '/files'), { body: options, ...call });
|
|
186
|
-
const { blob, name } = await toBlob(file);
|
|
187
|
-
const fd = new FormData();
|
|
188
|
-
fd.append('options', JSON.stringify(options));
|
|
189
|
-
fd.append('file', blob, fileName ?? name ?? 'upload');
|
|
190
|
-
return this.#t.json('POST', this.#p(id, '/files'), { body: fd, ...call });
|
|
191
|
-
}
|
|
192
|
-
addUrl(id, url, opts = {}, call = {}) {
|
|
193
|
-
return this.addFile(id, { ...opts, url }, call);
|
|
194
|
-
}
|
|
195
|
-
start(id, call = {}) {
|
|
196
|
-
return this.#t.json('POST', this.#p(id, '/start'), call);
|
|
197
|
-
}
|
|
198
|
-
export(id, format) {
|
|
199
|
-
return this.#t.raw('GET', this.#p(id, '/export'), { headers: { accept: '*/*' }, query: { format } });
|
|
200
|
-
}
|
|
201
|
-
stop(id) {
|
|
202
|
-
return this.#t.json('POST', this.#p(id, '/stop'));
|
|
203
|
-
}
|
|
204
|
-
async wait(id, opts = {}) {
|
|
205
|
-
const interval = opts.intervalMs ?? 5000;
|
|
206
|
-
const deadline = opts.timeoutMs ? Date.now() + opts.timeoutMs : Infinity;
|
|
207
|
-
for (;;) {
|
|
208
|
-
const batch = await this.get(id);
|
|
209
|
-
opts.onProgress?.(batch);
|
|
210
|
-
if ((batch.state === 'done' || batch.state === 'stopped') && batch.finishedAt)
|
|
211
|
-
return batch;
|
|
212
|
-
if (batch.state === 'open')
|
|
213
|
-
throw new VocalStackError('invalid_state', 'the batch is open: start it before waiting for it');
|
|
214
|
-
if (Date.now() + interval > deadline)
|
|
215
|
-
throw new VocalStackError('timeout', `batch still ${batch.state} after ${opts.timeoutMs} ms`, { retryable: true });
|
|
216
|
-
if (opts.signal?.aborted)
|
|
217
|
-
throw opts.signal.reason ?? new Error('aborted');
|
|
218
|
-
await new Promise((r) => setTimeout(r, interval));
|
|
219
|
-
}
|
|
155
|
+
async nameAppearance(id, appearance, name) {
|
|
156
|
+
await this.t.json('PUT', this.p(id, `/appearances/${seg(appearance)}`), { body: { name } });
|
|
220
157
|
}
|
|
221
158
|
}
|
|
222
159
|
export class Recordings {
|
|
@@ -253,6 +190,7 @@ export class Recordings {
|
|
|
253
190
|
streamUrl: grant.streamUrl,
|
|
254
191
|
readyDeadlineMs: opts.readyDeadlineMs ?? this.#t.opts.readyDeadlineMs,
|
|
255
192
|
onLoading: opts.onLoading,
|
|
193
|
+
onQueued: opts.onQueued,
|
|
256
194
|
onFrame: opts.onFrame,
|
|
257
195
|
});
|
|
258
196
|
}
|
|
@@ -343,9 +281,6 @@ export class Recordings {
|
|
|
343
281
|
mediaToken(id) {
|
|
344
282
|
return this.#t.json('GET', this.#p(id, '/media-token'));
|
|
345
283
|
}
|
|
346
|
-
async nameSpeaker(id, speaker, name) {
|
|
347
|
-
await this.#t.json('PUT', this.#p(id, `/speakers/${seg(speaker)}`), { body: { name } });
|
|
348
|
-
}
|
|
349
284
|
events(id, opts = {}) {
|
|
350
285
|
return allPages(async (cursor) => {
|
|
351
286
|
const r = await this.eventsPage(id, cursor ? { cursor, limit: opts.limit } : { after: opts.after, limit: opts.limit });
|
|
@@ -482,54 +417,70 @@ export class Tags {
|
|
|
482
417
|
return this.#t.json('POST', `/v1/tags/${seg(id)}/transcriptions`, { body: req });
|
|
483
418
|
}
|
|
484
419
|
}
|
|
485
|
-
export class
|
|
420
|
+
export class Speakers {
|
|
486
421
|
#t;
|
|
487
422
|
constructor(t) {
|
|
488
423
|
this.#t = t;
|
|
489
424
|
}
|
|
490
425
|
async list(opts = {}) {
|
|
491
|
-
const r = await this.#t.json('GET', '/v1/
|
|
492
|
-
return r.
|
|
426
|
+
const r = await this.#t.json('GET', '/v1/speakers', { query: { lifecycle: opts.lifecycle } });
|
|
427
|
+
return r.speakers ?? [];
|
|
493
428
|
}
|
|
494
429
|
get(id) {
|
|
495
|
-
return this.#t.json('GET', `/v1/
|
|
430
|
+
return this.#t.json('GET', `/v1/speakers/${seg(id)}`);
|
|
496
431
|
}
|
|
497
432
|
archive(id) {
|
|
498
|
-
return this.#t.json('POST', `/v1/
|
|
433
|
+
return this.#t.json('POST', `/v1/speakers/${seg(id)}/archive`);
|
|
499
434
|
}
|
|
500
435
|
restore(id) {
|
|
501
|
-
return this.#t.json('POST', `/v1/
|
|
436
|
+
return this.#t.json('POST', `/v1/speakers/${seg(id)}/restore`);
|
|
502
437
|
}
|
|
503
438
|
archiveMany(ids) {
|
|
504
|
-
return this.#t.json('POST', '/v1/
|
|
439
|
+
return this.#t.json('POST', '/v1/speakers/archive', { body: { ids } });
|
|
505
440
|
}
|
|
506
441
|
restoreMany(ids) {
|
|
507
|
-
return this.#t.json('POST', '/v1/
|
|
442
|
+
return this.#t.json('POST', '/v1/speakers/restore', { body: { ids } });
|
|
508
443
|
}
|
|
509
444
|
deleteMany(ids) {
|
|
510
|
-
return this.#t.json('POST', '/v1/
|
|
445
|
+
return this.#t.json('POST', '/v1/speakers/delete', { body: { ids } });
|
|
511
446
|
}
|
|
512
447
|
async create(req, call = {}) {
|
|
513
448
|
const { sample, fileName, ...meta } = req;
|
|
514
449
|
const form = new FormData();
|
|
515
|
-
form.append('meta', JSON.stringify(
|
|
450
|
+
form.append('meta', JSON.stringify(meta));
|
|
516
451
|
if (sample !== undefined) {
|
|
517
452
|
const { blob, name } = await toBlob(sample);
|
|
518
453
|
form.append('sample', blob, fileName ?? name ?? 'sample.webm');
|
|
519
454
|
}
|
|
520
|
-
return this.#t.json('POST', '/v1/
|
|
455
|
+
return this.#t.json('POST', '/v1/speakers', { body: form, ...call });
|
|
521
456
|
}
|
|
522
|
-
|
|
523
|
-
return this.#t.json('POST', '/v1/
|
|
457
|
+
createFromAppearance(req, call = {}) {
|
|
458
|
+
return this.#t.json('POST', '/v1/speakers/from-appearance', { body: req, ...call });
|
|
524
459
|
}
|
|
525
460
|
setConsent(id, consent, opts = {}) {
|
|
526
|
-
return this.#t.json('POST', `/v1/
|
|
461
|
+
return this.#t.json('POST', `/v1/speakers/${seg(id)}/consent`, { body: { consent, ...opts } });
|
|
527
462
|
}
|
|
528
463
|
update(id, patch) {
|
|
529
|
-
return this.#t.json('PATCH', `/v1/
|
|
464
|
+
return this.#t.json('PATCH', `/v1/speakers/${seg(id)}`, { body: patch });
|
|
530
465
|
}
|
|
531
466
|
async delete(id) {
|
|
532
|
-
await this.#t.json('DELETE', `/v1/
|
|
467
|
+
await this.#t.json('DELETE', `/v1/speakers/${seg(id)}`);
|
|
468
|
+
}
|
|
469
|
+
voicePreview(id, opts = {}) {
|
|
470
|
+
return this.#t.raw('GET', `/v1/speakers/${seg(id)}/preview`, {
|
|
471
|
+
headers: { accept: '*/*' },
|
|
472
|
+
query: { ...listenerQuery(opts), lang: opts.lang, format: opts.format, recording: opts.recording },
|
|
473
|
+
anonymous: opts.asOwner === false,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
sample(id) {
|
|
477
|
+
return this.#t.raw('GET', `/v1/speakers/${seg(id)}/sample`, { headers: { accept: '*/*' } });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
export class Voices {
|
|
481
|
+
#t;
|
|
482
|
+
constructor(t) {
|
|
483
|
+
this.#t = t;
|
|
533
484
|
}
|
|
534
485
|
available(lang, opts = {}) {
|
|
535
486
|
return this.#t.json('GET', '/v1/voices/available', {
|
|
@@ -540,16 +491,6 @@ export class Voices {
|
|
|
540
491
|
preview(voice, lang, opts = {}) {
|
|
541
492
|
return this.#t.raw('GET', '/v1/voices/preview', { headers: { accept: '*/*' }, query: { voice, lang, format: opts.format } });
|
|
542
493
|
}
|
|
543
|
-
clonePreview(id, opts = {}) {
|
|
544
|
-
return this.#t.raw('GET', `/v1/voices/${seg(id)}/preview`, {
|
|
545
|
-
headers: { accept: '*/*' },
|
|
546
|
-
query: { ...listenerQuery(opts), lang: opts.lang, format: opts.format, recording: opts.recording },
|
|
547
|
-
anonymous: opts.asOwner === false,
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
sample(id) {
|
|
551
|
-
return this.#t.raw('GET', `/v1/voices/${seg(id)}/sample`, { headers: { accept: '*/*' } });
|
|
552
|
-
}
|
|
553
494
|
}
|
|
554
495
|
export class Search {
|
|
555
496
|
#t;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vocalstack/js-sdk",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.4",
|
|
4
4
|
"description": "VocalStack speech API SDK for Node and browsers: one client (VocalStack) grouped by resource, typed from the generated contract, with realtime WebSocket streaming.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test": "node --test test/*.test.mjs"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@vocalstack/contract": "1.0.0-alpha.
|
|
32
|
+
"@vocalstack/contract": "1.0.0-alpha.4",
|
|
33
33
|
"ws": "^8.18.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
@@ -19,9 +19,6 @@ one group per resource: `vs.transcriptions`, `vs.jobs`, `vs.recordings`,
|
|
|
19
19
|
- A **job** is a file or link recording's transcription work:
|
|
20
20
|
`vs.jobs.wait(recordingId)` polls it until it is `done` or `failed`
|
|
21
21
|
(`{ onProgress: (job) => … }` sees each read: `job.state`, `job.progress.pct`).
|
|
22
|
-
- A **batch** is many files transcribed together for less than one
|
|
23
|
-
transcription each: `vs.batches.create()`, `addFile`/`addUrl` per file,
|
|
24
|
-
`start`, then `wait` (section 6).
|
|
25
22
|
- A **broadcast** is a link listeners open to follow a live recording.
|
|
26
23
|
- A **realtime session** (`vs.realtime`) is a socket you stream audio into and
|
|
27
24
|
read the transcript from. Nothing is stored. "Session" means only this.
|
|
@@ -189,28 +186,6 @@ const { hits: found } = await vs.search.vector('how much does housing cost');
|
|
|
189
186
|
for (const h of found) console.log(h.similarity.toFixed(2), h.passage.mediaStart, h.passage.text);
|
|
190
187
|
```
|
|
191
188
|
|
|
192
|
-
## 6. A batch of files
|
|
193
|
-
|
|
194
|
-
Many files at once cost less as a batch: one create, one minimum charge for
|
|
195
|
-
the whole batch. Its files get transcripts, exports and speaker labels (when
|
|
196
|
-
`settings.speakerLabels` asks), never a summary, title, share link or voices.
|
|
197
|
-
|
|
198
|
-
```js
|
|
199
|
-
import { VocalStack } from '@vocalstack/js-sdk';
|
|
200
|
-
const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
|
|
201
|
-
|
|
202
|
-
const batch = await vs.batches.create({ name: 'Interviews', settings: { spokenLanguage: 'en' } });
|
|
203
|
-
for (const path of process.argv.slice(2)) await vs.batches.addFile(batch.id, { file: path }); // or addUrl(batch.id, url)
|
|
204
|
-
await vs.batches.start(batch.id);
|
|
205
|
-
const done = await vs.batches.wait(batch.id); // done (or stopped); check done.counts.failed
|
|
206
|
-
for (const tx of done.files ?? []) {
|
|
207
|
-
if (tx.job?.state !== 'done') continue;
|
|
208
|
-
const { sentences } = await vs.recordings.transcript(tx.job.recordingId);
|
|
209
|
-
console.log(tx.name, sentences.map((s) => s.text).join(' '));
|
|
210
|
-
}
|
|
211
|
-
// vs.batches.export(batch.id, 'srt') is every finished transcript in one zip.
|
|
212
|
-
```
|
|
213
|
-
|
|
214
189
|
## Errors
|
|
215
190
|
|
|
216
191
|
A failed call throws `VocalStackError` with `code`, `message`, `status`,
|
|
@@ -248,8 +223,7 @@ try {
|
|
|
248
223
|
- The other groups: `vs.transcriptions` (`list`, `get`, `update`, `archive`,
|
|
249
224
|
`restore`, `purge`, `listShareLinks`, `createShareLink`), `vs.recordings`
|
|
250
225
|
(`get`, `summarize`, `summary`, `translation`, `audioUrl`, `subscribe` for a
|
|
251
|
-
live transcript feed), `vs.
|
|
252
|
-
`wait`, `get`, `list`, `export`, `stop`, `delete`), `vs.corrections`, `vs.shareLinks`, `vs.voices`,
|
|
226
|
+
live transcript feed), `vs.corrections`, `vs.shareLinks`, `vs.speakers`, `vs.voices`,
|
|
253
227
|
`vs.broadcasts`, `vs.me` (`get`, `usage`), `vs.languages`,
|
|
254
228
|
`vs.rtmp`, `vs.events`, `vs.meta`. Each method is named after its operation
|
|
255
229
|
in the OpenAPI document (`transcriptions.create` is `POST /v1/transcriptions`).
|