@vocalstack/js-sdk 2.0.0-alpha.1 → 2.0.0-alpha.2

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 CHANGED
@@ -31,8 +31,9 @@ npm install @vocalstack/js-sdk
31
31
 
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
- - [Transcribe a link](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-link.md): The server fetches a public URL or a YouTube video, then transcribes it like a file. Asynchronous, with a fetch phase first.
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
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
+ - [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.
36
37
  - [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.
37
38
  - [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.
38
39
  - [Go live](https://github.com/vocalstack/js-sdk/blob/main/docs/go-live.md): Publish live audio to a stored transcription, and put it on a broadcast link listeners open. Control is HTTP; audio is one WebSocket.
package/SKILL.md CHANGED
@@ -179,6 +179,16 @@ for (const h of hits) {
179
179
  }
180
180
  ```
181
181
 
182
+ By meaning, in any language, even with none of the words (vector search). Each
183
+ hit's `passage` is its whole paragraph: give the passages to your own model as
184
+ context to answer questions about what was said (RAG). Pay as you go counts 60
185
+ an hour (`allowance`); Premium and Enterprise have no limit.
186
+
187
+ ```js
188
+ const { hits: found } = await vs.search.vector('how much does housing cost');
189
+ for (const h of found) console.log(h.similarity.toFixed(2), h.passage.mediaStart, h.passage.text);
190
+ ```
191
+
182
192
  ## 6. A batch of files
183
193
 
184
194
  Many files at once cost less as a batch: one create, one minimum charge for
package/dist/index.d.ts CHANGED
@@ -14,8 +14,8 @@ export { Subscription } from './subscription.js';
14
14
  export type { SubscribeOptions, SubscriptionEvent } from './subscription.js';
15
15
  export type { WsLike } from './ws.js';
16
16
  export { Batches, Broadcasts, Connect, Corrections, Events, Jobs, Languages, MeApi, Meta, Recordings, Rtmp, Search, ShareLinks, Tags, Transcriptions, Voices, playableFormat, } from './resources.js';
17
- export type { AudioKind, MediaAuth, MediaFormat, RenderVoice } from './resources.js';
18
- export type { AddBatchFileInput, ConnectToken, ConnectTokenInput, CreateTranscriptionInput, LifecycleFilter, Me, PageOptions, RecordingPageOptions, SearchOptions, Upload, UsageChargesOptions, UsageOptions } from './resources.js';
17
+ export type { AudioKind, MediaAuth, MediaFormat, RenderVoice, VoicesChoice } from './resources.js';
18
+ export type { AddBatchFileInput, 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 {
@@ -1,10 +1,23 @@
1
- import type { AppStreamKey, AudioSourceCheck, Batch, BatchPage, 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, CreateBatch, CreateLiveTranscription, CreateBroadcast, CreateShareLink, CreateTag, CreateTranscription, CreateVoiceFromSpeaker, CreatedAppStreamKey, ChargePage, ExportFormat, ClientApp, ClientPolicy, Health, LanguageLists, LedgerPage, LinkProbe, PatchVoice, PlanList, PublishGrant, Recording, RecordingEvent, RecordingEvents, RecordingPage, RetranscribeLine, RtmpStatus, SearchResults, SettingsPatch, ShareLink, SharedTranscript, StartRecording, StartJob, SummaryStatus, Tag, TagTranscriptions, Transcription, TranscriptionJob, TranscriptionPage, TranscriptSnapshot, UpdateBroadcast, UpdateTag, UpdateTranscription, UpdateShareLink, UploadRecording, Voice, VoiceCatalogue, VoiceTrack, ManyResult } from '@vocalstack/contract';
1
+ import type { AppStreamKey, AudioSourceCheck, Batch, BatchPage, 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, CreateBatch, CreateLiveTranscription, CreateBroadcast, CreateShareLink, CreateTag, CreateTranscription, CreateVoiceFromSpeaker, CreatedAppStreamKey, ChargePage, ExportFormat, ClientApp, ClientPolicy, Health, LanguageLists, LedgerPage, LinkProbe, PatchVoice, 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, Voice, 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';
5
5
  import { type WsLike } from './ws.js';
6
6
  export type Upload = Blob | Uint8Array | ArrayBuffer | string;
7
7
  export type LifecycleFilter = 'active' | 'archived' | 'all';
8
+ export interface TranscriptionFilters {
9
+ lifecycle?: LifecycleFilter;
10
+ q?: string;
11
+ site?: string;
12
+ language?: string;
13
+ kind?: 'file' | 'link' | 'live';
14
+ origin?: Transcription['origin'];
15
+ tag?: string;
16
+ broadcast?: string;
17
+ createdAfter?: string | Date;
18
+ createdBefore?: string | Date;
19
+ shared?: boolean;
20
+ }
8
21
  export interface RecordingPageOptions extends PageOptions {
9
22
  lifecycle?: 'active' | 'archived';
10
23
  }
@@ -49,13 +62,13 @@ export type CreateTranscriptionInput = CreateTranscription & {
49
62
  export declare class Transcriptions extends ParentResource<Transcription, UpdateTranscription> {
50
63
  protected readonly base: "/v1/transcriptions";
51
64
  protected readonly key: "transcriptions";
52
- listPage(opts?: PageOptions & {
53
- lifecycle?: LifecycleFilter;
54
- }): Promise<TranscriptionPage>;
65
+ list(opts?: LifecycleFilter | TranscriptionFilters): Promise<Transcription[]>;
66
+ listPage(opts?: PageOptions & TranscriptionFilters): Promise<TranscriptionPage>;
55
67
  uploadRecording(id: string, req?: UploadRecording, call?: CallOptions): Promise<PublishGrant>;
56
68
  create(req: CreateTranscriptionInput, call?: CallOptions): Promise<Transcription>;
57
69
  createFromUrl(url: string, opts?: Omit<CreateTranscription, 'url'>, call?: CallOptions): Promise<Transcription>;
58
70
  createLive(req: CreateLiveTranscription, call?: CallOptions): Promise<Transcription>;
71
+ lookup(url: string): Promise<Transcription | null>;
59
72
  probe(url: string): Promise<LinkProbe>;
60
73
  attachBroadcast(id: string, broadcastId: string): Promise<Transcription>;
61
74
  detachBroadcast(id: string, broadcastId: string): Promise<Transcription>;
@@ -131,6 +144,7 @@ export declare class Recordings {
131
144
  audioSrc(id: string, opts?: {
132
145
  kind?: AudioKind;
133
146
  lang?: string;
147
+ voices?: VoicesChoice;
134
148
  voice?: string;
135
149
  format?: MediaFormat;
136
150
  } & MediaAuth): string;
@@ -138,6 +152,7 @@ export declare class Recordings {
138
152
  clean?: boolean;
139
153
  } & MediaAuth): string;
140
154
  voiceClipSrc(id: string, sentence: number, lang: string, opts?: {
155
+ voices?: VoicesChoice;
141
156
  voice?: string;
142
157
  format?: 'ogg' | 'caf';
143
158
  part?: number;
@@ -149,6 +164,7 @@ export declare class Recordings {
149
164
  renderVoice(id: string, req: RenderVoice & ReadAs, call?: CallOptions): Promise<VoiceTrack[]>;
150
165
  voiceClip(id: string, sentence: number, lang: string, opts?: {
151
166
  format?: 'ogg' | 'caf';
167
+ voices?: VoicesChoice;
152
168
  } & ReadAs): Promise<Response>;
153
169
  mediaToken(id: string): Promise<{
154
170
  token: string;
@@ -168,11 +184,14 @@ export declare class Recordings {
168
184
  }
169
185
  export type AudioKind = 'delivery' | 'voice' | 'background' | 'speech' | 'master' | 'source' | 'video';
170
186
  export type MediaFormat = 'ogg' | 'caf' | 'mp3';
187
+ export type VoicesChoice = 'cloned' | 'synthetic';
171
188
  export interface RenderVoice {
172
189
  langs: string[];
190
+ voices?: VoicesChoice;
173
191
  voice?: string;
174
192
  voiceBySpeaker?: Record<string, string>;
175
193
  near?: number;
194
+ consent?: boolean;
176
195
  }
177
196
  export interface MediaAuth extends ReadAs {
178
197
  token?: string;
@@ -260,10 +279,11 @@ export declare class Voices {
260
279
  } & ReadAs): Promise<Response>;
261
280
  sample(id: string): Promise<Response>;
262
281
  }
263
- export interface SearchOptions {
282
+ export interface SearchOptions extends Omit<TranscriptionFilters, 'lifecycle' | 'q' | 'broadcast'> {
264
283
  broadcasts?: string[];
265
284
  listenerTokens?: string[];
266
285
  recording?: string;
286
+ transcription?: string;
267
287
  lang?: string;
268
288
  limit?: number;
269
289
  }
@@ -271,7 +291,9 @@ export declare class Search {
271
291
  #private;
272
292
  constructor(t: Transport);
273
293
  query(q: string, opts?: SearchOptions): Promise<SearchResults>;
294
+ vector(q: string, opts?: VectorSearchOptions): Promise<VectorResults>;
274
295
  }
296
+ export type VectorSearchOptions = Omit<SearchOptions, 'broadcasts' | 'listenerTokens' | 'lang' | 'limit'>;
275
297
  export interface Me {
276
298
  userId?: string | null;
277
299
  apiKeyId?: string | null;
package/dist/resources.js CHANGED
@@ -3,6 +3,10 @@ import { listenerQuery, seg } from './http.js';
3
3
  import { RealtimeSession } from './realtime.js';
4
4
  import { Subscription } from './subscription.js';
5
5
  import { openWebSocket } from './ws.js';
6
+ function filterQuery(f) {
7
+ const at = (d) => (d instanceof Date ? d.toISOString() : d);
8
+ return { lifecycle: f.lifecycle, q: f.q, site: f.site, language: f.language, kind: f.kind, origin: f.origin, tag: f.tag, broadcast: f.broadcast, createdAfter: at(f.createdAfter), createdBefore: at(f.createdBefore), shared: f.shared };
9
+ }
6
10
  async function toBlob(file) {
7
11
  if (typeof file === 'string') {
8
12
  const fsSpecifier = 'node:' + 'fs';
@@ -106,8 +110,15 @@ export class Broadcasts extends ParentResource {
106
110
  export class Transcriptions extends ParentResource {
107
111
  base = '/v1/transcriptions';
108
112
  key = 'transcriptions';
113
+ list(opts = 'active') {
114
+ const f = typeof opts === 'string' ? { lifecycle: opts } : opts;
115
+ return allPages(async (cursor) => {
116
+ const r = await this.listPage({ ...f, cursor });
117
+ return { items: r.transcriptions, nextCursor: r.nextCursor };
118
+ });
119
+ }
109
120
  listPage(opts = {}) {
110
- return this.t.json('GET', this.base, { query: { lifecycle: opts.lifecycle, cursor: opts.cursor, limit: opts.limit } });
121
+ return this.t.json('GET', this.base, { query: { ...filterQuery(opts), cursor: opts.cursor, limit: opts.limit } });
111
122
  }
112
123
  uploadRecording(id, req = {}, call = {}) {
113
124
  return this.t.json('POST', this.p(id, '/recordings/upload'), { body: req, ...call });
@@ -128,6 +139,10 @@ export class Transcriptions extends ParentResource {
128
139
  createLive(req, call = {}) {
129
140
  return this.t.json('POST', `${this.base}/live`, { body: req, ...call });
130
141
  }
142
+ async lookup(url) {
143
+ const r = await this.t.json('GET', `${this.base}/lookup`, { query: { url } });
144
+ return r.transcription ?? null;
145
+ }
131
146
  probe(url) {
132
147
  return this.t.json('GET', `${this.base}/probe`, { query: { url } });
133
148
  }
@@ -292,7 +307,7 @@ export class Recordings {
292
307
  return location;
293
308
  }
294
309
  audioSrc(id, opts = {}) {
295
- return this.#t.url(this.#p(id, '/audio'), { kind: opts.kind ?? 'delivery', lang: opts.lang, format: opts.format, voice: opts.voice, ...mediaQuery(opts) });
310
+ return this.#t.url(this.#p(id, '/audio'), { kind: opts.kind ?? 'delivery', lang: opts.lang, format: opts.format, voices: opts.voices, voice: opts.voice, ...mediaQuery(opts) });
296
311
  }
297
312
  clipSrc(id, startS, endS, opts = {}) {
298
313
  return this.#t.url(this.#p(id, '/audio/clip'), { startS: startS.toFixed(2), endS: endS.toFixed(2), clean: opts.clean ? 'true' : undefined, ...mediaQuery(opts) });
@@ -300,6 +315,7 @@ export class Recordings {
300
315
  voiceClipSrc(id, sentence, lang, opts = {}) {
301
316
  return this.#t.url(this.#p(id, `/voice/${seg(sentence)}`), {
302
317
  lang,
318
+ voices: opts.voices,
303
319
  voice: opts.voice,
304
320
  format: opts.format,
305
321
  part: opts.part ? opts.part : undefined,
@@ -317,12 +333,12 @@ export class Recordings {
317
333
  const r = Array.isArray(req) ? { langs: req } : req;
318
334
  return this.#t.json('POST', this.#p(id, '/voice'), {
319
335
  query: listenerQuery(r),
320
- body: { langs: r.langs, voice: r.voice, voiceBySpeaker: r.voiceBySpeaker, near: r.near },
336
+ body: { langs: r.langs, voices: r.voices, voice: r.voice, voiceBySpeaker: r.voiceBySpeaker, near: r.near, consent: r.consent },
321
337
  ...call,
322
338
  });
323
339
  }
324
340
  voiceClip(id, sentence, lang, opts = {}) {
325
- return this.#t.raw('GET', this.#p(id, `/voice/${seg(sentence)}`), { headers: { accept: '*/*' }, query: { ...listenerQuery(opts), lang, format: opts.format } });
341
+ return this.#t.raw('GET', this.#p(id, `/voice/${seg(sentence)}`), { headers: { accept: '*/*' }, query: { ...listenerQuery(opts), lang, format: opts.format, voices: opts.voices } });
326
342
  }
327
343
  mediaToken(id) {
328
344
  return this.#t.json('GET', this.#p(id, '/media-token'));
@@ -542,15 +558,26 @@ export class Search {
542
558
  }
543
559
  query(q, opts = {}) {
544
560
  const query = {
561
+ ...filterQuery({ site: opts.site, language: opts.language, kind: opts.kind, origin: opts.origin, tag: opts.tag, createdAfter: opts.createdAfter, createdBefore: opts.createdBefore, shared: opts.shared }),
545
562
  q,
546
563
  broadcasts: opts.broadcasts?.join(','),
547
564
  listenerTokens: opts.listenerTokens?.join(','),
548
565
  recording: opts.recording,
566
+ transcription: opts.transcription,
549
567
  lang: opts.lang,
550
568
  limit: opts.limit,
551
569
  };
552
570
  return this.#t.json('GET', '/v1/search', { query });
553
571
  }
572
+ vector(q, opts = {}) {
573
+ const query = {
574
+ ...filterQuery({ site: opts.site, language: opts.language, kind: opts.kind, origin: opts.origin, tag: opts.tag, createdAfter: opts.createdAfter, createdBefore: opts.createdBefore, shared: opts.shared }),
575
+ q,
576
+ recording: opts.recording,
577
+ transcription: opts.transcription,
578
+ };
579
+ return this.#t.json('GET', '/v1/search/vector', { query });
580
+ }
554
581
  }
555
582
  export class MeApi {
556
583
  #t;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocalstack/js-sdk",
3
- "version": "2.0.0-alpha.1",
3
+ "version": "2.0.0-alpha.2",
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",
@@ -25,20 +25,16 @@
25
25
  "skills"
26
26
  ],
27
27
  "scripts": {
28
- "build": "npm run build --prefix contract && tsc -p tsconfig.json",
28
+ "build": "tsc -p tsconfig.json",
29
29
  "test": "node --test test/*.test.mjs"
30
30
  },
31
31
  "dependencies": {
32
- "@vocalstack/contract": "1.0.0-alpha.1",
32
+ "@vocalstack/contract": "1.0.0-alpha.2",
33
33
  "ws": "^8.18.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^22.0.0",
37
37
  "@types/ws": "^8.5.0",
38
38
  "typescript": "^5.6.0"
39
- },
40
- "repository": {
41
- "type": "git",
42
- "url": "git+https://github.com/vocalstack/js-sdk.git"
43
39
  }
44
40
  }
@@ -179,6 +179,16 @@ for (const h of hits) {
179
179
  }
180
180
  ```
181
181
 
182
+ By meaning, in any language, even with none of the words (vector search). Each
183
+ hit's `passage` is its whole paragraph: give the passages to your own model as
184
+ context to answer questions about what was said (RAG). Pay as you go counts 60
185
+ an hour (`allowance`); Premium and Enterprise have no limit.
186
+
187
+ ```js
188
+ const { hits: found } = await vs.search.vector('how much does housing cost');
189
+ for (const h of found) console.log(h.similarity.toFixed(2), h.passage.mediaStart, h.passage.text);
190
+ ```
191
+
182
192
  ## 6. A batch of files
183
193
 
184
194
  Many files at once cost less as a batch: one create, one minimum charge for