voice-router-dev 0.1.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 +455 -0
- package/dist/index.d.mts +10799 -0
- package/dist/index.d.ts +10799 -0
- package/dist/index.js +4880 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4821 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +115 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4880 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
__export(src_exports, {
|
|
34
|
+
AssemblyAIAdapter: () => AssemblyAIAdapter,
|
|
35
|
+
AssemblyAITypes: () => schema_exports2,
|
|
36
|
+
AssemblyAIWebhookHandler: () => AssemblyAIWebhookHandler,
|
|
37
|
+
AzureSTTAdapter: () => AzureSTTAdapter,
|
|
38
|
+
AzureWebhookHandler: () => AzureWebhookHandler,
|
|
39
|
+
BaseAdapter: () => BaseAdapter,
|
|
40
|
+
BaseWebhookHandler: () => BaseWebhookHandler,
|
|
41
|
+
DeepgramAdapter: () => DeepgramAdapter,
|
|
42
|
+
DeepgramWebhookHandler: () => DeepgramWebhookHandler,
|
|
43
|
+
GladiaAdapter: () => GladiaAdapter,
|
|
44
|
+
GladiaTypes: () => schema_exports,
|
|
45
|
+
GladiaWebhookHandler: () => GladiaWebhookHandler,
|
|
46
|
+
OpenAIWhisperAdapter: () => OpenAIWhisperAdapter,
|
|
47
|
+
SpeechmaticsAdapter: () => SpeechmaticsAdapter,
|
|
48
|
+
SpeechmaticsWebhookHandler: () => SpeechmaticsWebhookHandler,
|
|
49
|
+
VoiceRouter: () => VoiceRouter,
|
|
50
|
+
WebhookRouter: () => WebhookRouter,
|
|
51
|
+
createAssemblyAIAdapter: () => createAssemblyAIAdapter,
|
|
52
|
+
createAssemblyAIWebhookHandler: () => createAssemblyAIWebhookHandler,
|
|
53
|
+
createAzureSTTAdapter: () => createAzureSTTAdapter,
|
|
54
|
+
createAzureWebhookHandler: () => createAzureWebhookHandler,
|
|
55
|
+
createDeepgramAdapter: () => createDeepgramAdapter,
|
|
56
|
+
createDeepgramWebhookHandler: () => createDeepgramWebhookHandler,
|
|
57
|
+
createGladiaAdapter: () => createGladiaAdapter,
|
|
58
|
+
createGladiaWebhookHandler: () => createGladiaWebhookHandler,
|
|
59
|
+
createOpenAIWhisperAdapter: () => createOpenAIWhisperAdapter,
|
|
60
|
+
createSpeechmaticsAdapter: () => createSpeechmaticsAdapter,
|
|
61
|
+
createVoiceRouter: () => createVoiceRouter,
|
|
62
|
+
createWebhookRouter: () => createWebhookRouter
|
|
63
|
+
});
|
|
64
|
+
module.exports = __toCommonJS(src_exports);
|
|
65
|
+
|
|
66
|
+
// src/router/voice-router.ts
|
|
67
|
+
var VoiceRouter = class {
|
|
68
|
+
constructor(config) {
|
|
69
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
70
|
+
this.roundRobinIndex = 0;
|
|
71
|
+
this.config = {
|
|
72
|
+
selectionStrategy: "default",
|
|
73
|
+
...config
|
|
74
|
+
};
|
|
75
|
+
if (Object.keys(config.providers).length === 0) {
|
|
76
|
+
throw new Error("VoiceRouter requires at least one provider configuration");
|
|
77
|
+
}
|
|
78
|
+
if (this.config.selectionStrategy === "default" && !this.config.defaultProvider) {
|
|
79
|
+
this.config.defaultProvider = Object.keys(config.providers)[0];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Register an adapter for a provider
|
|
84
|
+
*
|
|
85
|
+
* Call this method for each provider you want to use. The adapter will be
|
|
86
|
+
* initialized with the configuration provided in the constructor.
|
|
87
|
+
*
|
|
88
|
+
* @param adapter - Provider adapter instance to register
|
|
89
|
+
* @throws {Error} If no configuration found for the provider
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const router = new VoiceRouter({
|
|
94
|
+
* providers: {
|
|
95
|
+
* gladia: { apiKey: 'YOUR_KEY' }
|
|
96
|
+
* }
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* router.registerAdapter(new GladiaAdapter());
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
registerAdapter(adapter) {
|
|
103
|
+
const providerConfig = this.config.providers[adapter.name];
|
|
104
|
+
if (!providerConfig) {
|
|
105
|
+
throw new Error(`No configuration found for provider: ${adapter.name}`);
|
|
106
|
+
}
|
|
107
|
+
adapter.initialize(providerConfig);
|
|
108
|
+
this.adapters.set(adapter.name, adapter);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get an adapter by provider name
|
|
112
|
+
*/
|
|
113
|
+
getAdapter(provider) {
|
|
114
|
+
const adapter = this.adapters.get(provider);
|
|
115
|
+
if (!adapter) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Provider '${provider}' is not registered. Available providers: ${Array.from(this.adapters.keys()).join(", ")}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return adapter;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Select provider based on configured strategy
|
|
124
|
+
*/
|
|
125
|
+
selectProvider(preferredProvider) {
|
|
126
|
+
if (preferredProvider) {
|
|
127
|
+
if (!this.adapters.has(preferredProvider)) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Provider '${preferredProvider}' is not registered. Available providers: ${Array.from(this.adapters.keys()).join(", ")}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return preferredProvider;
|
|
133
|
+
}
|
|
134
|
+
switch (this.config.selectionStrategy) {
|
|
135
|
+
case "explicit":
|
|
136
|
+
throw new Error(
|
|
137
|
+
"Provider must be explicitly specified when using 'explicit' selection strategy"
|
|
138
|
+
);
|
|
139
|
+
case "round-robin": {
|
|
140
|
+
const providers = Array.from(this.adapters.keys());
|
|
141
|
+
const provider = providers[this.roundRobinIndex % providers.length];
|
|
142
|
+
this.roundRobinIndex++;
|
|
143
|
+
return provider;
|
|
144
|
+
}
|
|
145
|
+
case "default":
|
|
146
|
+
default:
|
|
147
|
+
if (!this.config.defaultProvider) {
|
|
148
|
+
throw new Error("No default provider configured");
|
|
149
|
+
}
|
|
150
|
+
return this.config.defaultProvider;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Transcribe audio using a specific provider or the default
|
|
155
|
+
*
|
|
156
|
+
* Submit audio for transcription. The provider will be selected based on
|
|
157
|
+
* your configuration strategy (explicit, default, or round-robin).
|
|
158
|
+
*
|
|
159
|
+
* @param audio - Audio input (URL, file buffer, or stream)
|
|
160
|
+
* @param options - Transcription options (language, diarization, etc.)
|
|
161
|
+
* @param options.provider - Specific provider to use (overrides selection strategy)
|
|
162
|
+
* @returns Unified transcription response with normalized format
|
|
163
|
+
* @throws {Error} If provider not registered or selection fails
|
|
164
|
+
*
|
|
165
|
+
* @example URL audio
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const result = await router.transcribe({
|
|
168
|
+
* type: 'url',
|
|
169
|
+
* url: 'https://example.com/audio.mp3'
|
|
170
|
+
* }, {
|
|
171
|
+
* language: 'en',
|
|
172
|
+
* diarization: true,
|
|
173
|
+
* summarization: true
|
|
174
|
+
* });
|
|
175
|
+
*
|
|
176
|
+
* if (result.success) {
|
|
177
|
+
* console.log('Transcript:', result.data.text);
|
|
178
|
+
* console.log('Speakers:', result.data.speakers);
|
|
179
|
+
* console.log('Summary:', result.data.summary);
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @example Specific provider
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const result = await router.transcribe(audio, {
|
|
186
|
+
* provider: 'gladia', // Force use of Gladia
|
|
187
|
+
* language: 'en'
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
async transcribe(audio, options) {
|
|
192
|
+
const provider = this.selectProvider(options?.provider);
|
|
193
|
+
const adapter = this.getAdapter(provider);
|
|
194
|
+
const { provider: _, ...adapterOptions } = options || {};
|
|
195
|
+
return adapter.transcribe(audio, adapterOptions);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get transcription result by ID
|
|
199
|
+
* Provider must be specified since IDs are provider-specific
|
|
200
|
+
*/
|
|
201
|
+
async getTranscript(transcriptId, provider) {
|
|
202
|
+
const adapter = this.getAdapter(provider);
|
|
203
|
+
return adapter.getTranscript(transcriptId);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Stream audio for real-time transcription
|
|
207
|
+
* Only works with providers that support streaming
|
|
208
|
+
*
|
|
209
|
+
* @param options - Streaming options including provider selection
|
|
210
|
+
* @param callbacks - Event callbacks for transcription results
|
|
211
|
+
* @returns Promise that resolves with a StreamingSession
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* import { VoiceRouter } from '@meeting-baas/sdk';
|
|
216
|
+
*
|
|
217
|
+
* const router = new VoiceRouter();
|
|
218
|
+
* router.initialize({
|
|
219
|
+
* gladia: { apiKey: process.env.GLADIA_KEY },
|
|
220
|
+
* deepgram: { apiKey: process.env.DEEPGRAM_KEY }
|
|
221
|
+
* });
|
|
222
|
+
*
|
|
223
|
+
* const session = await router.transcribeStream({
|
|
224
|
+
* provider: 'deepgram',
|
|
225
|
+
* encoding: 'linear16',
|
|
226
|
+
* sampleRate: 16000,
|
|
227
|
+
* language: 'en'
|
|
228
|
+
* }, {
|
|
229
|
+
* onTranscript: (event) => console.log(event.text),
|
|
230
|
+
* onError: (error) => console.error(error)
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* // Send audio chunks
|
|
234
|
+
* await session.sendAudio({ data: audioBuffer });
|
|
235
|
+
* await session.close();
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
async transcribeStream(options, callbacks) {
|
|
239
|
+
const provider = this.selectProvider(options?.provider);
|
|
240
|
+
const adapter = this.getAdapter(provider);
|
|
241
|
+
if (!adapter.capabilities.streaming || !adapter.transcribeStream) {
|
|
242
|
+
throw new Error(`Provider '${provider}' does not support streaming transcription`);
|
|
243
|
+
}
|
|
244
|
+
const { provider: _, ...adapterOptions } = options || {};
|
|
245
|
+
return adapter.transcribeStream(adapterOptions, callbacks);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Delete a transcription
|
|
249
|
+
* Not all providers support this operation
|
|
250
|
+
*/
|
|
251
|
+
async deleteTranscript(transcriptId, provider) {
|
|
252
|
+
const adapter = this.getAdapter(provider);
|
|
253
|
+
if (!adapter.deleteTranscript) {
|
|
254
|
+
throw new Error(`Provider '${provider}' does not support deleting transcripts`);
|
|
255
|
+
}
|
|
256
|
+
return adapter.deleteTranscript(transcriptId);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* List recent transcriptions
|
|
260
|
+
* Not all providers support this operation
|
|
261
|
+
*/
|
|
262
|
+
async listTranscripts(provider, options) {
|
|
263
|
+
const adapter = this.getAdapter(provider);
|
|
264
|
+
if (!adapter.listTranscripts) {
|
|
265
|
+
throw new Error(`Provider '${provider}' does not support listing transcripts`);
|
|
266
|
+
}
|
|
267
|
+
return adapter.listTranscripts(options);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Get capabilities for a specific provider
|
|
271
|
+
*/
|
|
272
|
+
getProviderCapabilities(provider) {
|
|
273
|
+
const adapter = this.getAdapter(provider);
|
|
274
|
+
return adapter.capabilities;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get all registered providers
|
|
278
|
+
*/
|
|
279
|
+
getRegisteredProviders() {
|
|
280
|
+
return Array.from(this.adapters.keys());
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get raw provider client for advanced usage
|
|
284
|
+
*/
|
|
285
|
+
getRawProviderClient(provider) {
|
|
286
|
+
const adapter = this.getAdapter(provider);
|
|
287
|
+
if (!adapter.getRawClient) {
|
|
288
|
+
throw new Error(`Provider '${provider}' does not expose a raw client`);
|
|
289
|
+
}
|
|
290
|
+
return adapter.getRawClient();
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
function createVoiceRouter(config, adapters) {
|
|
294
|
+
const router = new VoiceRouter(config);
|
|
295
|
+
if (adapters && adapters.length > 0) {
|
|
296
|
+
for (const adapter of adapters) {
|
|
297
|
+
router.registerAdapter(adapter);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return router;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/adapters/base-adapter.ts
|
|
304
|
+
var BaseAdapter = class {
|
|
305
|
+
initialize(config) {
|
|
306
|
+
this.config = config;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Helper method to create error responses
|
|
310
|
+
*/
|
|
311
|
+
createErrorResponse(error, statusCode) {
|
|
312
|
+
const err = error;
|
|
313
|
+
return {
|
|
314
|
+
success: false,
|
|
315
|
+
provider: this.name,
|
|
316
|
+
error: {
|
|
317
|
+
code: err.code || "UNKNOWN_ERROR",
|
|
318
|
+
message: err.message || "An unknown error occurred",
|
|
319
|
+
statusCode: statusCode || err.statusCode,
|
|
320
|
+
details: error
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Helper method to validate configuration
|
|
326
|
+
*/
|
|
327
|
+
validateConfig() {
|
|
328
|
+
if (!this.config) {
|
|
329
|
+
throw new Error(`Adapter ${this.name} is not initialized. Call initialize() first.`);
|
|
330
|
+
}
|
|
331
|
+
if (!this.config.apiKey) {
|
|
332
|
+
throw new Error(`API key is required for ${this.name} provider`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// src/adapters/gladia-adapter.ts
|
|
338
|
+
var import_axios = __toESM(require("axios"));
|
|
339
|
+
var import_ws = __toESM(require("ws"));
|
|
340
|
+
var GladiaAdapter = class extends BaseAdapter {
|
|
341
|
+
constructor() {
|
|
342
|
+
super(...arguments);
|
|
343
|
+
this.name = "gladia";
|
|
344
|
+
this.capabilities = {
|
|
345
|
+
streaming: true,
|
|
346
|
+
diarization: true,
|
|
347
|
+
wordTimestamps: true,
|
|
348
|
+
languageDetection: true,
|
|
349
|
+
customVocabulary: true,
|
|
350
|
+
summarization: true,
|
|
351
|
+
sentimentAnalysis: true,
|
|
352
|
+
entityDetection: true,
|
|
353
|
+
piiRedaction: false
|
|
354
|
+
// Gladia doesn't have PII redaction in their API
|
|
355
|
+
};
|
|
356
|
+
this.baseUrl = "https://api.gladia.io/v2";
|
|
357
|
+
}
|
|
358
|
+
initialize(config) {
|
|
359
|
+
super.initialize(config);
|
|
360
|
+
this.client = import_axios.default.create({
|
|
361
|
+
baseURL: config.baseUrl || this.baseUrl,
|
|
362
|
+
timeout: config.timeout || 6e4,
|
|
363
|
+
headers: {
|
|
364
|
+
"x-gladia-key": config.apiKey,
|
|
365
|
+
"Content-Type": "application/json",
|
|
366
|
+
...config.headers
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Submit audio for transcription
|
|
372
|
+
*
|
|
373
|
+
* Sends audio to Gladia API for transcription. If a webhook URL is provided,
|
|
374
|
+
* returns immediately with the job ID. Otherwise, polls until completion.
|
|
375
|
+
*
|
|
376
|
+
* @param audio - Audio input (currently only URL type supported)
|
|
377
|
+
* @param options - Transcription options
|
|
378
|
+
* @param options.language - Language code (e.g., 'en', 'es', 'fr')
|
|
379
|
+
* @param options.languageDetection - Enable automatic language detection
|
|
380
|
+
* @param options.diarization - Enable speaker identification
|
|
381
|
+
* @param options.speakersExpected - Number of expected speakers (for diarization)
|
|
382
|
+
* @param options.summarization - Generate text summary
|
|
383
|
+
* @param options.sentimentAnalysis - Analyze sentiment of transcription
|
|
384
|
+
* @param options.customVocabulary - Words to boost in recognition
|
|
385
|
+
* @param options.webhookUrl - Callback URL for async results
|
|
386
|
+
* @returns Normalized transcription response
|
|
387
|
+
* @throws {Error} If audio type is not 'url' (file/stream not yet supported)
|
|
388
|
+
*
|
|
389
|
+
* @example Simple transcription
|
|
390
|
+
* ```typescript
|
|
391
|
+
* const result = await adapter.transcribe({
|
|
392
|
+
* type: 'url',
|
|
393
|
+
* url: 'https://example.com/meeting.mp3'
|
|
394
|
+
* });
|
|
395
|
+
* ```
|
|
396
|
+
*
|
|
397
|
+
* @example With advanced features
|
|
398
|
+
* ```typescript
|
|
399
|
+
* const result = await adapter.transcribe({
|
|
400
|
+
* type: 'url',
|
|
401
|
+
* url: 'https://example.com/meeting.mp3'
|
|
402
|
+
* }, {
|
|
403
|
+
* language: 'en',
|
|
404
|
+
* diarization: true,
|
|
405
|
+
* speakersExpected: 3,
|
|
406
|
+
* summarization: true,
|
|
407
|
+
* customVocabulary: ['API', 'TypeScript', 'JavaScript']
|
|
408
|
+
* });
|
|
409
|
+
* ```
|
|
410
|
+
*
|
|
411
|
+
* @example With webhook (returns job ID immediately for polling)
|
|
412
|
+
* ```typescript
|
|
413
|
+
* // Submit transcription with webhook
|
|
414
|
+
* const result = await adapter.transcribe({
|
|
415
|
+
* type: 'url',
|
|
416
|
+
* url: 'https://example.com/meeting.mp3'
|
|
417
|
+
* }, {
|
|
418
|
+
* webhookUrl: 'https://myapp.com/webhook/transcription',
|
|
419
|
+
* language: 'en'
|
|
420
|
+
* });
|
|
421
|
+
*
|
|
422
|
+
* // Get job ID for polling
|
|
423
|
+
* const jobId = result.data?.id;
|
|
424
|
+
* console.log('Job ID:', jobId); // Use this to poll for status
|
|
425
|
+
*
|
|
426
|
+
* // Later: Poll for completion (if webhook fails or you want to check)
|
|
427
|
+
* const status = await adapter.getTranscript(jobId);
|
|
428
|
+
* if (status.data?.status === 'completed') {
|
|
429
|
+
* console.log('Transcript:', status.data.text);
|
|
430
|
+
* }
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
async transcribe(audio, options) {
|
|
434
|
+
this.validateConfig();
|
|
435
|
+
try {
|
|
436
|
+
const payload = this.buildTranscriptionRequest(audio, options);
|
|
437
|
+
const response = await this.client.post(
|
|
438
|
+
"/transcription",
|
|
439
|
+
payload
|
|
440
|
+
);
|
|
441
|
+
const jobId = response.data.id;
|
|
442
|
+
if (options?.webhookUrl) {
|
|
443
|
+
return {
|
|
444
|
+
success: true,
|
|
445
|
+
provider: this.name,
|
|
446
|
+
data: {
|
|
447
|
+
id: jobId,
|
|
448
|
+
text: "",
|
|
449
|
+
status: "queued"
|
|
450
|
+
},
|
|
451
|
+
raw: response.data
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
return await this.pollForCompletion(jobId);
|
|
455
|
+
} catch (error) {
|
|
456
|
+
return this.createErrorResponse(error);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Get transcription result by ID
|
|
461
|
+
*/
|
|
462
|
+
async getTranscript(transcriptId) {
|
|
463
|
+
this.validateConfig();
|
|
464
|
+
try {
|
|
465
|
+
const response = await this.client.get(`/transcription/${transcriptId}`);
|
|
466
|
+
return this.normalizeResponse(response.data);
|
|
467
|
+
} catch (error) {
|
|
468
|
+
return this.createErrorResponse(error);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Build Gladia transcription request from unified options
|
|
473
|
+
*/
|
|
474
|
+
buildTranscriptionRequest(audio, options) {
|
|
475
|
+
let audioUrl;
|
|
476
|
+
if (audio.type === "url") {
|
|
477
|
+
audioUrl = audio.url;
|
|
478
|
+
} else {
|
|
479
|
+
throw new Error(
|
|
480
|
+
"Gladia adapter currently only supports URL-based audio input. Use audio.type='url'"
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
const request = {
|
|
484
|
+
audio_url: audioUrl
|
|
485
|
+
};
|
|
486
|
+
if (options) {
|
|
487
|
+
if (options.language || options.languageDetection) {
|
|
488
|
+
request.language_config = {
|
|
489
|
+
languages: options.language ? [options.language] : void 0,
|
|
490
|
+
code_switching: options.languageDetection
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (options.diarization) {
|
|
494
|
+
request.diarization = true;
|
|
495
|
+
if (options.speakersExpected) {
|
|
496
|
+
request.diarization_config = {
|
|
497
|
+
number_of_speakers: options.speakersExpected
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (options.customVocabulary && options.customVocabulary.length > 0) {
|
|
502
|
+
request.custom_vocabulary = true;
|
|
503
|
+
request.custom_vocabulary_config = {
|
|
504
|
+
vocabulary: options.customVocabulary
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
if (options.summarization) {
|
|
508
|
+
request.summarization = true;
|
|
509
|
+
}
|
|
510
|
+
if (options.sentimentAnalysis) {
|
|
511
|
+
request.sentiment_analysis = true;
|
|
512
|
+
}
|
|
513
|
+
if (options.entityDetection) {
|
|
514
|
+
request.named_entity_recognition = true;
|
|
515
|
+
}
|
|
516
|
+
if (options.webhookUrl) {
|
|
517
|
+
request.callback = true;
|
|
518
|
+
request.callback_config = {
|
|
519
|
+
url: options.webhookUrl
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
if (options.metadata) {
|
|
523
|
+
request.custom_metadata = options.metadata;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return request;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Normalize Gladia response to unified format
|
|
530
|
+
*/
|
|
531
|
+
normalizeResponse(response) {
|
|
532
|
+
let status;
|
|
533
|
+
switch (response.status) {
|
|
534
|
+
case "queued":
|
|
535
|
+
status = "queued";
|
|
536
|
+
break;
|
|
537
|
+
case "processing":
|
|
538
|
+
status = "processing";
|
|
539
|
+
break;
|
|
540
|
+
case "done":
|
|
541
|
+
status = "completed";
|
|
542
|
+
break;
|
|
543
|
+
case "error":
|
|
544
|
+
status = "error";
|
|
545
|
+
break;
|
|
546
|
+
default:
|
|
547
|
+
status = "queued";
|
|
548
|
+
}
|
|
549
|
+
if (response.status === "error") {
|
|
550
|
+
return {
|
|
551
|
+
success: false,
|
|
552
|
+
provider: this.name,
|
|
553
|
+
error: {
|
|
554
|
+
code: response.error_code?.toString() || "TRANSCRIPTION_ERROR",
|
|
555
|
+
message: "Transcription failed",
|
|
556
|
+
statusCode: response.error_code || void 0
|
|
557
|
+
},
|
|
558
|
+
raw: response
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
const result = response.result;
|
|
562
|
+
const transcription = result?.transcription;
|
|
563
|
+
return {
|
|
564
|
+
success: true,
|
|
565
|
+
provider: this.name,
|
|
566
|
+
data: {
|
|
567
|
+
id: response.id,
|
|
568
|
+
text: transcription?.full_transcript || "",
|
|
569
|
+
confidence: void 0,
|
|
570
|
+
// Gladia doesn't provide overall confidence
|
|
571
|
+
status,
|
|
572
|
+
language: transcription?.languages?.[0],
|
|
573
|
+
// Use first detected language
|
|
574
|
+
duration: void 0,
|
|
575
|
+
// Not directly available in Gladia response
|
|
576
|
+
speakers: this.extractSpeakers(transcription),
|
|
577
|
+
words: this.extractWords(transcription),
|
|
578
|
+
utterances: this.extractUtterances(transcription),
|
|
579
|
+
summary: result?.summarization?.results || void 0,
|
|
580
|
+
metadata: {
|
|
581
|
+
requestParams: response.request_params,
|
|
582
|
+
customMetadata: response.custom_metadata
|
|
583
|
+
},
|
|
584
|
+
createdAt: response.created_at,
|
|
585
|
+
completedAt: response.completed_at || void 0
|
|
586
|
+
},
|
|
587
|
+
raw: response
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Extract speaker information from Gladia response
|
|
592
|
+
*/
|
|
593
|
+
extractSpeakers(transcription) {
|
|
594
|
+
if (!transcription?.utterances) {
|
|
595
|
+
return void 0;
|
|
596
|
+
}
|
|
597
|
+
const speakerSet = /* @__PURE__ */ new Set();
|
|
598
|
+
transcription.utterances.forEach((utterance) => {
|
|
599
|
+
if (utterance.speaker !== void 0) {
|
|
600
|
+
speakerSet.add(utterance.speaker);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
if (speakerSet.size === 0) {
|
|
604
|
+
return void 0;
|
|
605
|
+
}
|
|
606
|
+
return Array.from(speakerSet).map((speakerId) => ({
|
|
607
|
+
id: speakerId.toString(),
|
|
608
|
+
label: `Speaker ${speakerId}`
|
|
609
|
+
}));
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Extract word timestamps from Gladia response
|
|
613
|
+
*/
|
|
614
|
+
extractWords(transcription) {
|
|
615
|
+
if (!transcription?.utterances) {
|
|
616
|
+
return void 0;
|
|
617
|
+
}
|
|
618
|
+
const allWords = transcription.utterances.flatMap(
|
|
619
|
+
(utterance) => utterance.words.map((word) => ({
|
|
620
|
+
text: word.word,
|
|
621
|
+
start: word.start,
|
|
622
|
+
end: word.end,
|
|
623
|
+
confidence: word.confidence,
|
|
624
|
+
speaker: utterance.speaker?.toString()
|
|
625
|
+
}))
|
|
626
|
+
);
|
|
627
|
+
return allWords.length > 0 ? allWords : void 0;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Extract utterances from Gladia response
|
|
631
|
+
*/
|
|
632
|
+
extractUtterances(transcription) {
|
|
633
|
+
if (!transcription?.utterances) {
|
|
634
|
+
return void 0;
|
|
635
|
+
}
|
|
636
|
+
return transcription.utterances.map((utterance) => ({
|
|
637
|
+
text: utterance.text,
|
|
638
|
+
start: utterance.start,
|
|
639
|
+
end: utterance.end,
|
|
640
|
+
speaker: utterance.speaker?.toString(),
|
|
641
|
+
confidence: utterance.confidence,
|
|
642
|
+
words: utterance.words.map((word) => ({
|
|
643
|
+
text: word.word,
|
|
644
|
+
start: word.start,
|
|
645
|
+
end: word.end,
|
|
646
|
+
confidence: word.confidence
|
|
647
|
+
}))
|
|
648
|
+
}));
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Poll for transcription completion
|
|
652
|
+
*/
|
|
653
|
+
async pollForCompletion(jobId, maxAttempts = 60, intervalMs = 2e3) {
|
|
654
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
655
|
+
const result = await this.getTranscript(jobId);
|
|
656
|
+
if (!result.success) {
|
|
657
|
+
return result;
|
|
658
|
+
}
|
|
659
|
+
const status = result.data?.status;
|
|
660
|
+
if (status === "completed") {
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
if (status === "error") {
|
|
664
|
+
return {
|
|
665
|
+
success: false,
|
|
666
|
+
provider: this.name,
|
|
667
|
+
error: {
|
|
668
|
+
code: "TRANSCRIPTION_ERROR",
|
|
669
|
+
message: "Transcription failed"
|
|
670
|
+
},
|
|
671
|
+
raw: result.raw
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
success: false,
|
|
678
|
+
provider: this.name,
|
|
679
|
+
error: {
|
|
680
|
+
code: "POLLING_TIMEOUT",
|
|
681
|
+
message: `Transcription did not complete after ${maxAttempts} attempts`
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Stream audio for real-time transcription
|
|
687
|
+
*
|
|
688
|
+
* Creates a WebSocket connection to Gladia for streaming transcription.
|
|
689
|
+
* First initializes a session via REST API, then connects to WebSocket.
|
|
690
|
+
*
|
|
691
|
+
* @param options - Streaming configuration options
|
|
692
|
+
* @param callbacks - Event callbacks for transcription results
|
|
693
|
+
* @returns Promise that resolves with a StreamingSession
|
|
694
|
+
*
|
|
695
|
+
* @example Real-time streaming
|
|
696
|
+
* ```typescript
|
|
697
|
+
* const session = await adapter.transcribeStream({
|
|
698
|
+
* encoding: 'wav/pcm',
|
|
699
|
+
* sampleRate: 16000,
|
|
700
|
+
* channels: 1,
|
|
701
|
+
* language: 'en',
|
|
702
|
+
* interimResults: true
|
|
703
|
+
* }, {
|
|
704
|
+
* onOpen: () => console.log('Connected'),
|
|
705
|
+
* onTranscript: (event) => {
|
|
706
|
+
* if (event.isFinal) {
|
|
707
|
+
* console.log('Final:', event.text);
|
|
708
|
+
* } else {
|
|
709
|
+
* console.log('Interim:', event.text);
|
|
710
|
+
* }
|
|
711
|
+
* },
|
|
712
|
+
* onError: (error) => console.error('Error:', error),
|
|
713
|
+
* onClose: () => console.log('Disconnected')
|
|
714
|
+
* });
|
|
715
|
+
*
|
|
716
|
+
* // Send audio chunks
|
|
717
|
+
* const audioChunk = getAudioChunk(); // Your audio source
|
|
718
|
+
* await session.sendAudio({ data: audioChunk });
|
|
719
|
+
*
|
|
720
|
+
* // Close when done
|
|
721
|
+
* await session.close();
|
|
722
|
+
* ```
|
|
723
|
+
*/
|
|
724
|
+
async transcribeStream(options, callbacks) {
|
|
725
|
+
this.validateConfig();
|
|
726
|
+
const streamingRequest = {
|
|
727
|
+
encoding: options?.encoding,
|
|
728
|
+
sample_rate: options?.sampleRate,
|
|
729
|
+
channels: options?.channels,
|
|
730
|
+
endpointing: options?.endpointing
|
|
731
|
+
};
|
|
732
|
+
if (options?.language) {
|
|
733
|
+
streamingRequest.language_config = {
|
|
734
|
+
languages: [options.language]
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
const initResponse = await this.client.post(
|
|
738
|
+
"/streaming/init",
|
|
739
|
+
streamingRequest
|
|
740
|
+
);
|
|
741
|
+
const { id, url: wsUrl } = initResponse.data;
|
|
742
|
+
const ws = new import_ws.default(wsUrl);
|
|
743
|
+
let sessionStatus = "connecting";
|
|
744
|
+
ws.on("open", () => {
|
|
745
|
+
sessionStatus = "open";
|
|
746
|
+
callbacks?.onOpen?.();
|
|
747
|
+
});
|
|
748
|
+
ws.on("message", (data) => {
|
|
749
|
+
try {
|
|
750
|
+
const message = JSON.parse(data.toString());
|
|
751
|
+
if (message.type === "transcript") {
|
|
752
|
+
callbacks?.onTranscript?.({
|
|
753
|
+
type: "transcript",
|
|
754
|
+
text: message.text || "",
|
|
755
|
+
isFinal: message.is_final === true,
|
|
756
|
+
confidence: message.confidence,
|
|
757
|
+
words: message.words?.map((word) => ({
|
|
758
|
+
text: word.word || word.text,
|
|
759
|
+
start: word.start,
|
|
760
|
+
end: word.end,
|
|
761
|
+
confidence: word.confidence
|
|
762
|
+
})),
|
|
763
|
+
data: message
|
|
764
|
+
});
|
|
765
|
+
} else if (message.type === "utterance") {
|
|
766
|
+
const utterance = {
|
|
767
|
+
text: message.text || "",
|
|
768
|
+
start: message.start || 0,
|
|
769
|
+
end: message.end || 0,
|
|
770
|
+
speaker: message.speaker?.toString(),
|
|
771
|
+
confidence: message.confidence,
|
|
772
|
+
words: message.words?.map((word) => ({
|
|
773
|
+
text: word.word || word.text,
|
|
774
|
+
start: word.start,
|
|
775
|
+
end: word.end,
|
|
776
|
+
confidence: word.confidence
|
|
777
|
+
}))
|
|
778
|
+
};
|
|
779
|
+
callbacks?.onUtterance?.(utterance);
|
|
780
|
+
} else if (message.type === "metadata") {
|
|
781
|
+
callbacks?.onMetadata?.(message);
|
|
782
|
+
}
|
|
783
|
+
} catch (error) {
|
|
784
|
+
callbacks?.onError?.({
|
|
785
|
+
code: "PARSE_ERROR",
|
|
786
|
+
message: "Failed to parse WebSocket message",
|
|
787
|
+
details: error
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
ws.on("error", (error) => {
|
|
792
|
+
callbacks?.onError?.({
|
|
793
|
+
code: "WEBSOCKET_ERROR",
|
|
794
|
+
message: error.message,
|
|
795
|
+
details: error
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
ws.on("close", (code, reason) => {
|
|
799
|
+
sessionStatus = "closed";
|
|
800
|
+
callbacks?.onClose?.(code, reason.toString());
|
|
801
|
+
});
|
|
802
|
+
await new Promise((resolve, reject) => {
|
|
803
|
+
const timeout = setTimeout(() => {
|
|
804
|
+
reject(new Error("WebSocket connection timeout"));
|
|
805
|
+
}, 1e4);
|
|
806
|
+
ws.once("open", () => {
|
|
807
|
+
clearTimeout(timeout);
|
|
808
|
+
resolve();
|
|
809
|
+
});
|
|
810
|
+
ws.once("error", (error) => {
|
|
811
|
+
clearTimeout(timeout);
|
|
812
|
+
reject(error);
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
return {
|
|
816
|
+
id,
|
|
817
|
+
provider: this.name,
|
|
818
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
819
|
+
getStatus: () => sessionStatus,
|
|
820
|
+
sendAudio: async (chunk) => {
|
|
821
|
+
if (sessionStatus !== "open") {
|
|
822
|
+
throw new Error(`Cannot send audio: session is ${sessionStatus}`);
|
|
823
|
+
}
|
|
824
|
+
if (ws.readyState !== import_ws.default.OPEN) {
|
|
825
|
+
throw new Error("WebSocket is not open");
|
|
826
|
+
}
|
|
827
|
+
ws.send(chunk.data);
|
|
828
|
+
if (chunk.isLast) {
|
|
829
|
+
ws.send(
|
|
830
|
+
JSON.stringify({
|
|
831
|
+
type: "stop_recording"
|
|
832
|
+
})
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
close: async () => {
|
|
837
|
+
if (sessionStatus === "closed" || sessionStatus === "closing") {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
sessionStatus = "closing";
|
|
841
|
+
if (ws.readyState === import_ws.default.OPEN) {
|
|
842
|
+
ws.send(
|
|
843
|
+
JSON.stringify({
|
|
844
|
+
type: "stop_recording"
|
|
845
|
+
})
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
return new Promise((resolve) => {
|
|
849
|
+
const timeout = setTimeout(() => {
|
|
850
|
+
ws.terminate();
|
|
851
|
+
resolve();
|
|
852
|
+
}, 5e3);
|
|
853
|
+
ws.close();
|
|
854
|
+
ws.once("close", () => {
|
|
855
|
+
clearTimeout(timeout);
|
|
856
|
+
sessionStatus = "closed";
|
|
857
|
+
resolve();
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
function createGladiaAdapter(config) {
|
|
865
|
+
const adapter = new GladiaAdapter();
|
|
866
|
+
adapter.initialize(config);
|
|
867
|
+
return adapter;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// src/adapters/assemblyai-adapter.ts
|
|
871
|
+
var import_axios2 = __toESM(require("axios"));
|
|
872
|
+
var import_ws2 = __toESM(require("ws"));
|
|
873
|
+
var AssemblyAIAdapter = class extends BaseAdapter {
|
|
874
|
+
constructor() {
|
|
875
|
+
super(...arguments);
|
|
876
|
+
this.name = "assemblyai";
|
|
877
|
+
this.capabilities = {
|
|
878
|
+
streaming: true,
|
|
879
|
+
diarization: true,
|
|
880
|
+
wordTimestamps: true,
|
|
881
|
+
languageDetection: true,
|
|
882
|
+
customVocabulary: true,
|
|
883
|
+
summarization: true,
|
|
884
|
+
sentimentAnalysis: true,
|
|
885
|
+
entityDetection: true,
|
|
886
|
+
piiRedaction: true
|
|
887
|
+
};
|
|
888
|
+
this.baseUrl = "https://api.assemblyai.com/v2";
|
|
889
|
+
this.wsBaseUrl = "wss://api.assemblyai.com/v2/realtime/ws";
|
|
890
|
+
}
|
|
891
|
+
initialize(config) {
|
|
892
|
+
super.initialize(config);
|
|
893
|
+
this.client = import_axios2.default.create({
|
|
894
|
+
baseURL: config.baseUrl || this.baseUrl,
|
|
895
|
+
timeout: config.timeout || 6e4,
|
|
896
|
+
headers: {
|
|
897
|
+
authorization: config.apiKey,
|
|
898
|
+
"Content-Type": "application/json",
|
|
899
|
+
...config.headers
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Submit audio for transcription
|
|
905
|
+
*
|
|
906
|
+
* Sends audio to AssemblyAI API for transcription. If a webhook URL is provided,
|
|
907
|
+
* returns immediately with the job ID. Otherwise, polls until completion.
|
|
908
|
+
*
|
|
909
|
+
* @param audio - Audio input (currently only URL type supported)
|
|
910
|
+
* @param options - Transcription options
|
|
911
|
+
* @param options.language - Language code (e.g., 'en', 'en_us', 'es', 'fr')
|
|
912
|
+
* @param options.languageDetection - Enable automatic language detection
|
|
913
|
+
* @param options.diarization - Enable speaker identification (speaker_labels)
|
|
914
|
+
* @param options.speakersExpected - Number of expected speakers
|
|
915
|
+
* @param options.summarization - Generate text summary
|
|
916
|
+
* @param options.sentimentAnalysis - Analyze sentiment of transcription
|
|
917
|
+
* @param options.entityDetection - Detect named entities (people, places, etc.)
|
|
918
|
+
* @param options.piiRedaction - Redact personally identifiable information
|
|
919
|
+
* @param options.customVocabulary - Words to boost in recognition
|
|
920
|
+
* @param options.webhookUrl - Callback URL for async results
|
|
921
|
+
* @returns Normalized transcription response
|
|
922
|
+
* @throws {Error} If audio type is not 'url' (file/stream not yet supported)
|
|
923
|
+
*
|
|
924
|
+
* @example Simple transcription
|
|
925
|
+
* ```typescript
|
|
926
|
+
* const result = await adapter.transcribe({
|
|
927
|
+
* type: 'url',
|
|
928
|
+
* url: 'https://example.com/meeting.mp3'
|
|
929
|
+
* });
|
|
930
|
+
* ```
|
|
931
|
+
*
|
|
932
|
+
* @example With advanced features
|
|
933
|
+
* ```typescript
|
|
934
|
+
* const result = await adapter.transcribe({
|
|
935
|
+
* type: 'url',
|
|
936
|
+
* url: 'https://example.com/meeting.mp3'
|
|
937
|
+
* }, {
|
|
938
|
+
* language: 'en_us',
|
|
939
|
+
* diarization: true,
|
|
940
|
+
* speakersExpected: 3,
|
|
941
|
+
* summarization: true,
|
|
942
|
+
* sentimentAnalysis: true,
|
|
943
|
+
* entityDetection: true,
|
|
944
|
+
* customVocabulary: ['API', 'TypeScript', 'JavaScript']
|
|
945
|
+
* });
|
|
946
|
+
* ```
|
|
947
|
+
*
|
|
948
|
+
* @example With webhook (returns transcript ID immediately for polling)
|
|
949
|
+
* ```typescript
|
|
950
|
+
* // Submit transcription with webhook
|
|
951
|
+
* const result = await adapter.transcribe({
|
|
952
|
+
* type: 'url',
|
|
953
|
+
* url: 'https://example.com/meeting.mp3'
|
|
954
|
+
* }, {
|
|
955
|
+
* webhookUrl: 'https://myapp.com/webhook/transcription',
|
|
956
|
+
* language: 'en_us'
|
|
957
|
+
* });
|
|
958
|
+
*
|
|
959
|
+
* // Get transcript ID for polling
|
|
960
|
+
* const transcriptId = result.data?.id;
|
|
961
|
+
* console.log('Transcript ID:', transcriptId); // Use this to poll for status
|
|
962
|
+
*
|
|
963
|
+
* // Later: Poll for completion (if webhook fails or you want to check)
|
|
964
|
+
* const status = await adapter.getTranscript(transcriptId);
|
|
965
|
+
* if (status.data?.status === 'completed') {
|
|
966
|
+
* console.log('Transcript:', status.data.text);
|
|
967
|
+
* }
|
|
968
|
+
* ```
|
|
969
|
+
*/
|
|
970
|
+
async transcribe(audio, options) {
|
|
971
|
+
this.validateConfig();
|
|
972
|
+
try {
|
|
973
|
+
const payload = this.buildTranscriptionRequest(audio, options);
|
|
974
|
+
const response = await this.client.post("/transcript", payload);
|
|
975
|
+
const transcriptId = response.data.id;
|
|
976
|
+
if (options?.webhookUrl) {
|
|
977
|
+
return {
|
|
978
|
+
success: true,
|
|
979
|
+
provider: this.name,
|
|
980
|
+
data: {
|
|
981
|
+
id: transcriptId,
|
|
982
|
+
text: "",
|
|
983
|
+
status: "queued"
|
|
984
|
+
},
|
|
985
|
+
raw: response.data
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
return await this.pollForCompletion(transcriptId);
|
|
989
|
+
} catch (error) {
|
|
990
|
+
return this.createErrorResponse(error);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Get transcription result by ID
|
|
995
|
+
*/
|
|
996
|
+
async getTranscript(transcriptId) {
|
|
997
|
+
this.validateConfig();
|
|
998
|
+
try {
|
|
999
|
+
const response = await this.client.get(`/transcript/${transcriptId}`);
|
|
1000
|
+
return this.normalizeResponse(response.data);
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
return this.createErrorResponse(error);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Build AssemblyAI transcription request from unified options
|
|
1007
|
+
*/
|
|
1008
|
+
buildTranscriptionRequest(audio, options) {
|
|
1009
|
+
let audioUrl;
|
|
1010
|
+
if (audio.type === "url") {
|
|
1011
|
+
audioUrl = audio.url;
|
|
1012
|
+
} else {
|
|
1013
|
+
throw new Error(
|
|
1014
|
+
"AssemblyAI adapter currently only supports URL-based audio input. Use audio.type='url'"
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
const request = {
|
|
1018
|
+
audio_url: audioUrl
|
|
1019
|
+
};
|
|
1020
|
+
if (options) {
|
|
1021
|
+
if (options.language) {
|
|
1022
|
+
const languageCode = options.language.includes("_") ? options.language : `${options.language}_us`;
|
|
1023
|
+
request.language_code = languageCode;
|
|
1024
|
+
}
|
|
1025
|
+
if (options.languageDetection) {
|
|
1026
|
+
request.language_detection = true;
|
|
1027
|
+
}
|
|
1028
|
+
if (options.diarization) {
|
|
1029
|
+
request.speaker_labels = true;
|
|
1030
|
+
if (options.speakersExpected) {
|
|
1031
|
+
request.speakers_expected = options.speakersExpected;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
if (options.customVocabulary && options.customVocabulary.length > 0) {
|
|
1035
|
+
request.word_boost = options.customVocabulary;
|
|
1036
|
+
request.boost_param = "high";
|
|
1037
|
+
}
|
|
1038
|
+
if (options.summarization) {
|
|
1039
|
+
request.summarization = true;
|
|
1040
|
+
request.summary_model = "informative";
|
|
1041
|
+
request.summary_type = "bullets";
|
|
1042
|
+
}
|
|
1043
|
+
if (options.sentimentAnalysis) {
|
|
1044
|
+
request.sentiment_analysis = true;
|
|
1045
|
+
}
|
|
1046
|
+
if (options.entityDetection) {
|
|
1047
|
+
request.entity_detection = true;
|
|
1048
|
+
}
|
|
1049
|
+
if (options.piiRedaction) {
|
|
1050
|
+
request.redact_pii = true;
|
|
1051
|
+
}
|
|
1052
|
+
if (options.webhookUrl) {
|
|
1053
|
+
request.webhook_url = options.webhookUrl;
|
|
1054
|
+
}
|
|
1055
|
+
request.punctuate = true;
|
|
1056
|
+
request.format_text = true;
|
|
1057
|
+
}
|
|
1058
|
+
return request;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Normalize AssemblyAI response to unified format
|
|
1062
|
+
*/
|
|
1063
|
+
normalizeResponse(response) {
|
|
1064
|
+
let status;
|
|
1065
|
+
switch (response.status) {
|
|
1066
|
+
case "queued":
|
|
1067
|
+
status = "queued";
|
|
1068
|
+
break;
|
|
1069
|
+
case "processing":
|
|
1070
|
+
status = "processing";
|
|
1071
|
+
break;
|
|
1072
|
+
case "completed":
|
|
1073
|
+
status = "completed";
|
|
1074
|
+
break;
|
|
1075
|
+
case "error":
|
|
1076
|
+
status = "error";
|
|
1077
|
+
break;
|
|
1078
|
+
default:
|
|
1079
|
+
status = "queued";
|
|
1080
|
+
}
|
|
1081
|
+
if (response.status === "error") {
|
|
1082
|
+
return {
|
|
1083
|
+
success: false,
|
|
1084
|
+
provider: this.name,
|
|
1085
|
+
error: {
|
|
1086
|
+
code: "TRANSCRIPTION_ERROR",
|
|
1087
|
+
message: response.error || "Transcription failed"
|
|
1088
|
+
},
|
|
1089
|
+
raw: response
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
return {
|
|
1093
|
+
success: true,
|
|
1094
|
+
provider: this.name,
|
|
1095
|
+
data: {
|
|
1096
|
+
id: response.id,
|
|
1097
|
+
text: response.text || "",
|
|
1098
|
+
confidence: response.confidence !== null ? response.confidence : void 0,
|
|
1099
|
+
status,
|
|
1100
|
+
language: response.language_code,
|
|
1101
|
+
duration: response.audio_duration ? response.audio_duration / 1e3 : void 0,
|
|
1102
|
+
// Convert ms to seconds
|
|
1103
|
+
speakers: this.extractSpeakers(response),
|
|
1104
|
+
words: this.extractWords(response),
|
|
1105
|
+
utterances: this.extractUtterances(response),
|
|
1106
|
+
summary: response.summary || void 0,
|
|
1107
|
+
metadata: {
|
|
1108
|
+
audioUrl: response.audio_url,
|
|
1109
|
+
entities: response.entities,
|
|
1110
|
+
sentimentAnalysis: response.sentiment_analysis_results,
|
|
1111
|
+
contentModeration: response.content_safety_labels
|
|
1112
|
+
}
|
|
1113
|
+
},
|
|
1114
|
+
raw: response
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Extract speaker information from AssemblyAI response
|
|
1119
|
+
*/
|
|
1120
|
+
extractSpeakers(transcript) {
|
|
1121
|
+
if (!transcript.utterances || transcript.utterances.length === 0) {
|
|
1122
|
+
return void 0;
|
|
1123
|
+
}
|
|
1124
|
+
const speakerSet = /* @__PURE__ */ new Set();
|
|
1125
|
+
transcript.utterances.forEach((utterance) => {
|
|
1126
|
+
if (utterance.speaker) {
|
|
1127
|
+
speakerSet.add(utterance.speaker);
|
|
1128
|
+
}
|
|
1129
|
+
});
|
|
1130
|
+
if (speakerSet.size === 0) {
|
|
1131
|
+
return void 0;
|
|
1132
|
+
}
|
|
1133
|
+
return Array.from(speakerSet).map((speakerId) => ({
|
|
1134
|
+
id: speakerId,
|
|
1135
|
+
label: speakerId
|
|
1136
|
+
// AssemblyAI uses format like "A", "B", "C"
|
|
1137
|
+
}));
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Extract word timestamps from AssemblyAI response
|
|
1141
|
+
*/
|
|
1142
|
+
extractWords(transcript) {
|
|
1143
|
+
if (!transcript.words || transcript.words.length === 0) {
|
|
1144
|
+
return void 0;
|
|
1145
|
+
}
|
|
1146
|
+
return transcript.words.map((word) => ({
|
|
1147
|
+
text: word.text,
|
|
1148
|
+
start: word.start / 1e3,
|
|
1149
|
+
// Convert ms to seconds
|
|
1150
|
+
end: word.end / 1e3,
|
|
1151
|
+
// Convert ms to seconds
|
|
1152
|
+
confidence: word.confidence,
|
|
1153
|
+
speaker: word.speaker || void 0
|
|
1154
|
+
}));
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Extract utterances from AssemblyAI response
|
|
1158
|
+
*/
|
|
1159
|
+
extractUtterances(transcript) {
|
|
1160
|
+
if (!transcript.utterances || transcript.utterances.length === 0) {
|
|
1161
|
+
return void 0;
|
|
1162
|
+
}
|
|
1163
|
+
return transcript.utterances.map((utterance) => ({
|
|
1164
|
+
text: utterance.text,
|
|
1165
|
+
start: utterance.start / 1e3,
|
|
1166
|
+
// Convert ms to seconds
|
|
1167
|
+
end: utterance.end / 1e3,
|
|
1168
|
+
// Convert ms to seconds
|
|
1169
|
+
speaker: utterance.speaker || void 0,
|
|
1170
|
+
confidence: utterance.confidence,
|
|
1171
|
+
words: utterance.words.map((word) => ({
|
|
1172
|
+
text: word.text,
|
|
1173
|
+
start: word.start / 1e3,
|
|
1174
|
+
end: word.end / 1e3,
|
|
1175
|
+
confidence: word.confidence
|
|
1176
|
+
}))
|
|
1177
|
+
}));
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Poll for transcription completion
|
|
1181
|
+
*/
|
|
1182
|
+
async pollForCompletion(transcriptId, maxAttempts = 60, intervalMs = 3e3) {
|
|
1183
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1184
|
+
const result = await this.getTranscript(transcriptId);
|
|
1185
|
+
if (!result.success) {
|
|
1186
|
+
return result;
|
|
1187
|
+
}
|
|
1188
|
+
const status = result.data?.status;
|
|
1189
|
+
if (status === "completed") {
|
|
1190
|
+
return result;
|
|
1191
|
+
}
|
|
1192
|
+
if (status === "error") {
|
|
1193
|
+
return {
|
|
1194
|
+
success: false,
|
|
1195
|
+
provider: this.name,
|
|
1196
|
+
error: {
|
|
1197
|
+
code: "TRANSCRIPTION_ERROR",
|
|
1198
|
+
message: "Transcription failed"
|
|
1199
|
+
},
|
|
1200
|
+
raw: result.raw
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
1204
|
+
}
|
|
1205
|
+
return {
|
|
1206
|
+
success: false,
|
|
1207
|
+
provider: this.name,
|
|
1208
|
+
error: {
|
|
1209
|
+
code: "POLLING_TIMEOUT",
|
|
1210
|
+
message: `Transcription did not complete after ${maxAttempts} attempts`
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Stream audio for real-time transcription
|
|
1216
|
+
*
|
|
1217
|
+
* Creates a WebSocket connection to AssemblyAI for streaming transcription.
|
|
1218
|
+
* First obtains a temporary token, then connects and streams audio chunks.
|
|
1219
|
+
*
|
|
1220
|
+
* @param options - Streaming configuration options
|
|
1221
|
+
* @param callbacks - Event callbacks for transcription results
|
|
1222
|
+
* @returns Promise that resolves with a StreamingSession
|
|
1223
|
+
*
|
|
1224
|
+
* @example Real-time streaming
|
|
1225
|
+
* ```typescript
|
|
1226
|
+
* const session = await adapter.transcribeStream({
|
|
1227
|
+
* encoding: 'pcm_s16le',
|
|
1228
|
+
* sampleRate: 16000,
|
|
1229
|
+
* language: 'en',
|
|
1230
|
+
* interimResults: true
|
|
1231
|
+
* }, {
|
|
1232
|
+
* onOpen: () => console.log('Connected'),
|
|
1233
|
+
* onTranscript: (event) => {
|
|
1234
|
+
* if (event.isFinal) {
|
|
1235
|
+
* console.log('Final:', event.text);
|
|
1236
|
+
* } else {
|
|
1237
|
+
* console.log('Interim:', event.text);
|
|
1238
|
+
* }
|
|
1239
|
+
* },
|
|
1240
|
+
* onError: (error) => console.error('Error:', error),
|
|
1241
|
+
* onClose: () => console.log('Disconnected')
|
|
1242
|
+
* });
|
|
1243
|
+
*
|
|
1244
|
+
* // Send audio chunks
|
|
1245
|
+
* const audioChunk = getAudioChunk(); // Your audio source
|
|
1246
|
+
* await session.sendAudio({ data: audioChunk });
|
|
1247
|
+
*
|
|
1248
|
+
* // Close when done
|
|
1249
|
+
* await session.close();
|
|
1250
|
+
* ```
|
|
1251
|
+
*/
|
|
1252
|
+
async transcribeStream(options, callbacks) {
|
|
1253
|
+
this.validateConfig();
|
|
1254
|
+
const tokenResponse = await this.client.post("/realtime/token", {
|
|
1255
|
+
expires_in: 3600
|
|
1256
|
+
// Token expires in 1 hour
|
|
1257
|
+
});
|
|
1258
|
+
const token = tokenResponse.data.token;
|
|
1259
|
+
const wsUrl = `${this.wsBaseUrl}?sample_rate=${options?.sampleRate || 16e3}&token=${token}`;
|
|
1260
|
+
const ws = new import_ws2.default(wsUrl);
|
|
1261
|
+
let sessionStatus = "connecting";
|
|
1262
|
+
const sessionId = `assemblyai-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
1263
|
+
ws.on("open", () => {
|
|
1264
|
+
sessionStatus = "open";
|
|
1265
|
+
callbacks?.onOpen?.();
|
|
1266
|
+
});
|
|
1267
|
+
ws.on("message", (data) => {
|
|
1268
|
+
try {
|
|
1269
|
+
const message = JSON.parse(data.toString());
|
|
1270
|
+
if (message.message_type === "SessionBegins") {
|
|
1271
|
+
callbacks?.onMetadata?.({
|
|
1272
|
+
sessionId: message.session_id,
|
|
1273
|
+
expiresAt: message.expires_at
|
|
1274
|
+
});
|
|
1275
|
+
} else if (message.message_type === "PartialTranscript") {
|
|
1276
|
+
callbacks?.onTranscript?.({
|
|
1277
|
+
type: "transcript",
|
|
1278
|
+
text: message.text || "",
|
|
1279
|
+
isFinal: false,
|
|
1280
|
+
confidence: message.confidence,
|
|
1281
|
+
words: message.words?.map((word) => ({
|
|
1282
|
+
text: word.text,
|
|
1283
|
+
start: word.start / 1e3,
|
|
1284
|
+
end: word.end / 1e3,
|
|
1285
|
+
confidence: word.confidence
|
|
1286
|
+
})),
|
|
1287
|
+
data: message
|
|
1288
|
+
});
|
|
1289
|
+
} else if (message.message_type === "FinalTranscript") {
|
|
1290
|
+
callbacks?.onTranscript?.({
|
|
1291
|
+
type: "transcript",
|
|
1292
|
+
text: message.text || "",
|
|
1293
|
+
isFinal: true,
|
|
1294
|
+
confidence: message.confidence,
|
|
1295
|
+
words: message.words?.map((word) => ({
|
|
1296
|
+
text: word.text,
|
|
1297
|
+
start: word.start / 1e3,
|
|
1298
|
+
end: word.end / 1e3,
|
|
1299
|
+
confidence: word.confidence
|
|
1300
|
+
})),
|
|
1301
|
+
data: message
|
|
1302
|
+
});
|
|
1303
|
+
} else if (message.message_type === "SessionTerminated") {
|
|
1304
|
+
callbacks?.onMetadata?.({ terminated: true });
|
|
1305
|
+
}
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
callbacks?.onError?.({
|
|
1308
|
+
code: "PARSE_ERROR",
|
|
1309
|
+
message: "Failed to parse WebSocket message",
|
|
1310
|
+
details: error
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
});
|
|
1314
|
+
ws.on("error", (error) => {
|
|
1315
|
+
callbacks?.onError?.({
|
|
1316
|
+
code: "WEBSOCKET_ERROR",
|
|
1317
|
+
message: error.message,
|
|
1318
|
+
details: error
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1321
|
+
ws.on("close", (code, reason) => {
|
|
1322
|
+
sessionStatus = "closed";
|
|
1323
|
+
callbacks?.onClose?.(code, reason.toString());
|
|
1324
|
+
});
|
|
1325
|
+
await new Promise((resolve, reject) => {
|
|
1326
|
+
const timeout = setTimeout(() => {
|
|
1327
|
+
reject(new Error("WebSocket connection timeout"));
|
|
1328
|
+
}, 1e4);
|
|
1329
|
+
ws.once("open", () => {
|
|
1330
|
+
clearTimeout(timeout);
|
|
1331
|
+
resolve();
|
|
1332
|
+
});
|
|
1333
|
+
ws.once("error", (error) => {
|
|
1334
|
+
clearTimeout(timeout);
|
|
1335
|
+
reject(error);
|
|
1336
|
+
});
|
|
1337
|
+
});
|
|
1338
|
+
return {
|
|
1339
|
+
id: sessionId,
|
|
1340
|
+
provider: this.name,
|
|
1341
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1342
|
+
getStatus: () => sessionStatus,
|
|
1343
|
+
sendAudio: async (chunk) => {
|
|
1344
|
+
if (sessionStatus !== "open") {
|
|
1345
|
+
throw new Error(`Cannot send audio: session is ${sessionStatus}`);
|
|
1346
|
+
}
|
|
1347
|
+
if (ws.readyState !== import_ws2.default.OPEN) {
|
|
1348
|
+
throw new Error("WebSocket is not open");
|
|
1349
|
+
}
|
|
1350
|
+
const base64Audio = chunk.data.toString("base64");
|
|
1351
|
+
ws.send(
|
|
1352
|
+
JSON.stringify({
|
|
1353
|
+
audio_data: base64Audio
|
|
1354
|
+
})
|
|
1355
|
+
);
|
|
1356
|
+
if (chunk.isLast) {
|
|
1357
|
+
ws.send(
|
|
1358
|
+
JSON.stringify({
|
|
1359
|
+
terminate_session: true
|
|
1360
|
+
})
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
},
|
|
1364
|
+
close: async () => {
|
|
1365
|
+
if (sessionStatus === "closed" || sessionStatus === "closing") {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
sessionStatus = "closing";
|
|
1369
|
+
if (ws.readyState === import_ws2.default.OPEN) {
|
|
1370
|
+
ws.send(
|
|
1371
|
+
JSON.stringify({
|
|
1372
|
+
terminate_session: true
|
|
1373
|
+
})
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
return new Promise((resolve) => {
|
|
1377
|
+
const timeout = setTimeout(() => {
|
|
1378
|
+
ws.terminate();
|
|
1379
|
+
resolve();
|
|
1380
|
+
}, 5e3);
|
|
1381
|
+
ws.close();
|
|
1382
|
+
ws.once("close", () => {
|
|
1383
|
+
clearTimeout(timeout);
|
|
1384
|
+
sessionStatus = "closed";
|
|
1385
|
+
resolve();
|
|
1386
|
+
});
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
function createAssemblyAIAdapter(config) {
|
|
1393
|
+
const adapter = new AssemblyAIAdapter();
|
|
1394
|
+
adapter.initialize(config);
|
|
1395
|
+
return adapter;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// src/adapters/deepgram-adapter.ts
|
|
1399
|
+
var import_axios3 = __toESM(require("axios"));
|
|
1400
|
+
var import_ws3 = __toESM(require("ws"));
|
|
1401
|
+
var DeepgramAdapter = class extends BaseAdapter {
|
|
1402
|
+
constructor() {
|
|
1403
|
+
super(...arguments);
|
|
1404
|
+
this.name = "deepgram";
|
|
1405
|
+
this.capabilities = {
|
|
1406
|
+
streaming: true,
|
|
1407
|
+
diarization: true,
|
|
1408
|
+
wordTimestamps: true,
|
|
1409
|
+
languageDetection: true,
|
|
1410
|
+
customVocabulary: true,
|
|
1411
|
+
summarization: true,
|
|
1412
|
+
sentimentAnalysis: true,
|
|
1413
|
+
entityDetection: true,
|
|
1414
|
+
piiRedaction: true
|
|
1415
|
+
};
|
|
1416
|
+
this.baseUrl = "https://api.deepgram.com/v1";
|
|
1417
|
+
this.wsBaseUrl = "wss://api.deepgram.com/v1/listen";
|
|
1418
|
+
}
|
|
1419
|
+
initialize(config) {
|
|
1420
|
+
super.initialize(config);
|
|
1421
|
+
this.client = import_axios3.default.create({
|
|
1422
|
+
baseURL: config.baseUrl || this.baseUrl,
|
|
1423
|
+
timeout: config.timeout || 6e4,
|
|
1424
|
+
headers: {
|
|
1425
|
+
Authorization: `Token ${config.apiKey}`,
|
|
1426
|
+
"Content-Type": "application/json",
|
|
1427
|
+
...config.headers
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Submit audio for transcription
|
|
1433
|
+
*
|
|
1434
|
+
* Sends audio to Deepgram API for transcription. Deepgram processes
|
|
1435
|
+
* synchronously and returns results immediately (no polling required).
|
|
1436
|
+
*
|
|
1437
|
+
* @param audio - Audio input (URL or file buffer)
|
|
1438
|
+
* @param options - Transcription options
|
|
1439
|
+
* @param options.language - Language code (e.g., 'en', 'es', 'fr')
|
|
1440
|
+
* @param options.languageDetection - Enable automatic language detection
|
|
1441
|
+
* @param options.diarization - Enable speaker identification (diarize)
|
|
1442
|
+
* @param options.speakersExpected - Expected number of speakers
|
|
1443
|
+
* @param options.summarization - Generate text summary
|
|
1444
|
+
* @param options.sentimentAnalysis - Analyze sentiment
|
|
1445
|
+
* @param options.entityDetection - Detect named entities
|
|
1446
|
+
* @param options.piiRedaction - Redact personally identifiable information
|
|
1447
|
+
* @param options.customVocabulary - Keywords to boost in recognition
|
|
1448
|
+
* @param options.webhookUrl - Callback URL for async processing
|
|
1449
|
+
* @returns Normalized transcription response
|
|
1450
|
+
*
|
|
1451
|
+
* @example Simple transcription
|
|
1452
|
+
* ```typescript
|
|
1453
|
+
* const result = await adapter.transcribe({
|
|
1454
|
+
* type: 'url',
|
|
1455
|
+
* url: 'https://example.com/meeting.mp3'
|
|
1456
|
+
* });
|
|
1457
|
+
* ```
|
|
1458
|
+
*
|
|
1459
|
+
* @example With advanced features
|
|
1460
|
+
* ```typescript
|
|
1461
|
+
* const result = await adapter.transcribe({
|
|
1462
|
+
* type: 'url',
|
|
1463
|
+
* url: 'https://example.com/meeting.mp3'
|
|
1464
|
+
* }, {
|
|
1465
|
+
* language: 'en',
|
|
1466
|
+
* diarization: true,
|
|
1467
|
+
* summarization: true,
|
|
1468
|
+
* sentimentAnalysis: true,
|
|
1469
|
+
* entityDetection: true,
|
|
1470
|
+
* customVocabulary: ['API', 'TypeScript', 'JavaScript']
|
|
1471
|
+
* });
|
|
1472
|
+
* ```
|
|
1473
|
+
*/
|
|
1474
|
+
async transcribe(audio, options) {
|
|
1475
|
+
this.validateConfig();
|
|
1476
|
+
try {
|
|
1477
|
+
const params = this.buildTranscriptionParams(options);
|
|
1478
|
+
let response;
|
|
1479
|
+
if (audio.type === "url") {
|
|
1480
|
+
response = await this.client.post(
|
|
1481
|
+
"/listen",
|
|
1482
|
+
{ url: audio.url },
|
|
1483
|
+
{ params }
|
|
1484
|
+
).then((res) => res.data);
|
|
1485
|
+
} else if (audio.type === "file") {
|
|
1486
|
+
response = await this.client.post("/listen", audio.file, {
|
|
1487
|
+
params,
|
|
1488
|
+
headers: {
|
|
1489
|
+
"Content-Type": "audio/*"
|
|
1490
|
+
}
|
|
1491
|
+
}).then((res) => res.data);
|
|
1492
|
+
} else {
|
|
1493
|
+
throw new Error(
|
|
1494
|
+
"Deepgram adapter does not support stream type for pre-recorded transcription. Use transcribeStream() for real-time streaming."
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
return this.normalizeResponse(response);
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
return this.createErrorResponse(error);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Get transcription result by ID
|
|
1504
|
+
*
|
|
1505
|
+
* Note: Deepgram processes synchronously, so this method is primarily
|
|
1506
|
+
* for retrieving cached results if you've stored the request ID.
|
|
1507
|
+
* The initial transcribe() call already returns complete results.
|
|
1508
|
+
*
|
|
1509
|
+
* @param transcriptId - Request ID from Deepgram
|
|
1510
|
+
* @returns Normalized transcription response
|
|
1511
|
+
*/
|
|
1512
|
+
async getTranscript(transcriptId) {
|
|
1513
|
+
this.validateConfig();
|
|
1514
|
+
return {
|
|
1515
|
+
success: false,
|
|
1516
|
+
provider: this.name,
|
|
1517
|
+
error: {
|
|
1518
|
+
code: "NOT_SUPPORTED",
|
|
1519
|
+
message: "Deepgram returns transcription results immediately. Store the response from transcribe() instead of using getTranscript()."
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Build Deepgram transcription parameters from unified options
|
|
1525
|
+
*/
|
|
1526
|
+
buildTranscriptionParams(options) {
|
|
1527
|
+
const params = {};
|
|
1528
|
+
if (!options) {
|
|
1529
|
+
return params;
|
|
1530
|
+
}
|
|
1531
|
+
if (options.language) {
|
|
1532
|
+
params.language = options.language;
|
|
1533
|
+
}
|
|
1534
|
+
if (options.languageDetection) {
|
|
1535
|
+
params.detect_language = true;
|
|
1536
|
+
}
|
|
1537
|
+
if (options.diarization) {
|
|
1538
|
+
params.diarize = true;
|
|
1539
|
+
}
|
|
1540
|
+
if (options.customVocabulary && options.customVocabulary.length > 0) {
|
|
1541
|
+
params.keywords = options.customVocabulary;
|
|
1542
|
+
}
|
|
1543
|
+
if (options.summarization) {
|
|
1544
|
+
params.summarize = true;
|
|
1545
|
+
}
|
|
1546
|
+
if (options.sentimentAnalysis) {
|
|
1547
|
+
params.sentiment = true;
|
|
1548
|
+
}
|
|
1549
|
+
if (options.entityDetection) {
|
|
1550
|
+
params.detect_entities = true;
|
|
1551
|
+
}
|
|
1552
|
+
if (options.piiRedaction) {
|
|
1553
|
+
params.redact = true;
|
|
1554
|
+
}
|
|
1555
|
+
if (options.webhookUrl) {
|
|
1556
|
+
params.callback = options.webhookUrl;
|
|
1557
|
+
}
|
|
1558
|
+
params.punctuate = true;
|
|
1559
|
+
params.utterances = true;
|
|
1560
|
+
params.smart_format = true;
|
|
1561
|
+
return params;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Normalize Deepgram response to unified format
|
|
1565
|
+
*/
|
|
1566
|
+
normalizeResponse(response) {
|
|
1567
|
+
const channel = response.results.channels?.[0];
|
|
1568
|
+
const alternative = channel?.alternatives?.[0];
|
|
1569
|
+
if (!alternative) {
|
|
1570
|
+
return {
|
|
1571
|
+
success: false,
|
|
1572
|
+
provider: this.name,
|
|
1573
|
+
error: {
|
|
1574
|
+
code: "NO_RESULTS",
|
|
1575
|
+
message: "No transcription results returned by Deepgram"
|
|
1576
|
+
},
|
|
1577
|
+
raw: response
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
return {
|
|
1581
|
+
success: true,
|
|
1582
|
+
provider: this.name,
|
|
1583
|
+
data: {
|
|
1584
|
+
id: response.metadata?.request_id || "",
|
|
1585
|
+
text: alternative.transcript || "",
|
|
1586
|
+
confidence: alternative.confidence,
|
|
1587
|
+
status: "completed",
|
|
1588
|
+
// Deepgram returns completed results immediately
|
|
1589
|
+
language: channel?.detected_language || void 0,
|
|
1590
|
+
duration: response.metadata?.duration,
|
|
1591
|
+
speakers: this.extractSpeakers(response),
|
|
1592
|
+
words: this.extractWords(alternative),
|
|
1593
|
+
utterances: this.extractUtterances(response),
|
|
1594
|
+
summary: this.extractSummary(alternative),
|
|
1595
|
+
metadata: {
|
|
1596
|
+
modelInfo: response.metadata?.model_info,
|
|
1597
|
+
channels: response.metadata?.channels,
|
|
1598
|
+
sentiment: response.results.sentiments,
|
|
1599
|
+
intents: response.results.intents,
|
|
1600
|
+
topics: response.results.topics
|
|
1601
|
+
}
|
|
1602
|
+
},
|
|
1603
|
+
raw: response
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Extract speaker information from Deepgram response
|
|
1608
|
+
*/
|
|
1609
|
+
extractSpeakers(response) {
|
|
1610
|
+
const utterances = response.results.utterances;
|
|
1611
|
+
if (!utterances || utterances.length === 0) {
|
|
1612
|
+
return void 0;
|
|
1613
|
+
}
|
|
1614
|
+
const speakerSet = /* @__PURE__ */ new Set();
|
|
1615
|
+
utterances.forEach((utterance) => {
|
|
1616
|
+
if (utterance.speaker !== void 0) {
|
|
1617
|
+
speakerSet.add(utterance.speaker);
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
if (speakerSet.size === 0) {
|
|
1621
|
+
return void 0;
|
|
1622
|
+
}
|
|
1623
|
+
return Array.from(speakerSet).map((speakerId) => ({
|
|
1624
|
+
id: speakerId.toString(),
|
|
1625
|
+
label: `Speaker ${speakerId}`
|
|
1626
|
+
}));
|
|
1627
|
+
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Extract word timestamps from Deepgram response
|
|
1630
|
+
*/
|
|
1631
|
+
extractWords(alternative) {
|
|
1632
|
+
if (!alternative.words || alternative.words.length === 0) {
|
|
1633
|
+
return void 0;
|
|
1634
|
+
}
|
|
1635
|
+
return alternative.words.map(
|
|
1636
|
+
(word) => ({
|
|
1637
|
+
text: word.word || "",
|
|
1638
|
+
start: word.start || 0,
|
|
1639
|
+
end: word.end || 0,
|
|
1640
|
+
confidence: word.confidence,
|
|
1641
|
+
speaker: void 0
|
|
1642
|
+
// Speaker info is at utterance level, not word level
|
|
1643
|
+
})
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Extract utterances from Deepgram response
|
|
1648
|
+
*/
|
|
1649
|
+
extractUtterances(response) {
|
|
1650
|
+
const utterances = response.results.utterances;
|
|
1651
|
+
if (!utterances || utterances.length === 0) {
|
|
1652
|
+
return void 0;
|
|
1653
|
+
}
|
|
1654
|
+
return utterances.map((utterance) => ({
|
|
1655
|
+
text: utterance.transcript || "",
|
|
1656
|
+
start: utterance.start || 0,
|
|
1657
|
+
end: utterance.end || 0,
|
|
1658
|
+
speaker: utterance.speaker?.toString(),
|
|
1659
|
+
confidence: utterance.confidence,
|
|
1660
|
+
words: utterance.words?.map((word) => ({
|
|
1661
|
+
text: word.word || "",
|
|
1662
|
+
start: word.start || 0,
|
|
1663
|
+
end: word.end || 0,
|
|
1664
|
+
confidence: word.confidence
|
|
1665
|
+
}))
|
|
1666
|
+
}));
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Extract summary from Deepgram response
|
|
1670
|
+
*/
|
|
1671
|
+
extractSummary(alternative) {
|
|
1672
|
+
if (!alternative.summaries || alternative.summaries.length === 0) {
|
|
1673
|
+
return void 0;
|
|
1674
|
+
}
|
|
1675
|
+
return alternative.summaries.map((summary) => summary.summary).filter(Boolean).join(" ");
|
|
1676
|
+
}
|
|
1677
|
+
/**
|
|
1678
|
+
* Stream audio for real-time transcription
|
|
1679
|
+
*
|
|
1680
|
+
* Creates a WebSocket connection to Deepgram for streaming transcription.
|
|
1681
|
+
* Send audio chunks via session.sendAudio() and receive results via callbacks.
|
|
1682
|
+
*
|
|
1683
|
+
* @param options - Streaming configuration options
|
|
1684
|
+
* @param callbacks - Event callbacks for transcription results
|
|
1685
|
+
* @returns Promise that resolves with a StreamingSession
|
|
1686
|
+
*
|
|
1687
|
+
* @example Real-time streaming
|
|
1688
|
+
* ```typescript
|
|
1689
|
+
* const session = await adapter.transcribeStream({
|
|
1690
|
+
* encoding: 'linear16',
|
|
1691
|
+
* sampleRate: 16000,
|
|
1692
|
+
* channels: 1,
|
|
1693
|
+
* language: 'en',
|
|
1694
|
+
* diarization: true,
|
|
1695
|
+
* interimResults: true
|
|
1696
|
+
* }, {
|
|
1697
|
+
* onOpen: () => console.log('Connected'),
|
|
1698
|
+
* onTranscript: (event) => {
|
|
1699
|
+
* if (event.isFinal) {
|
|
1700
|
+
* console.log('Final:', event.text);
|
|
1701
|
+
* } else {
|
|
1702
|
+
* console.log('Interim:', event.text);
|
|
1703
|
+
* }
|
|
1704
|
+
* },
|
|
1705
|
+
* onError: (error) => console.error('Error:', error),
|
|
1706
|
+
* onClose: () => console.log('Disconnected')
|
|
1707
|
+
* });
|
|
1708
|
+
*
|
|
1709
|
+
* // Send audio chunks
|
|
1710
|
+
* const audioChunk = getAudioChunk(); // Your audio source
|
|
1711
|
+
* await session.sendAudio({ data: audioChunk });
|
|
1712
|
+
*
|
|
1713
|
+
* // Close when done
|
|
1714
|
+
* await session.close();
|
|
1715
|
+
* ```
|
|
1716
|
+
*/
|
|
1717
|
+
async transcribeStream(options, callbacks) {
|
|
1718
|
+
this.validateConfig();
|
|
1719
|
+
const params = new URLSearchParams();
|
|
1720
|
+
if (options?.encoding) params.append("encoding", options.encoding);
|
|
1721
|
+
if (options?.sampleRate) params.append("sample_rate", options.sampleRate.toString());
|
|
1722
|
+
if (options?.channels) params.append("channels", options.channels.toString());
|
|
1723
|
+
if (options?.language) params.append("language", options.language);
|
|
1724
|
+
if (options?.languageDetection) params.append("detect_language", "true");
|
|
1725
|
+
if (options?.diarization) params.append("diarize", "true");
|
|
1726
|
+
if (options?.interimResults) params.append("interim_results", "true");
|
|
1727
|
+
if (options?.summarization) params.append("summarize", "true");
|
|
1728
|
+
if (options?.sentimentAnalysis) params.append("sentiment", "true");
|
|
1729
|
+
if (options?.entityDetection) params.append("detect_entities", "true");
|
|
1730
|
+
if (options?.piiRedaction) params.append("redact", "pii");
|
|
1731
|
+
if (options?.customVocabulary && options.customVocabulary.length > 0) {
|
|
1732
|
+
params.append("keywords", options.customVocabulary.join(","));
|
|
1733
|
+
}
|
|
1734
|
+
const wsUrl = `${this.wsBaseUrl}?${params.toString()}`;
|
|
1735
|
+
const ws = new import_ws3.default(wsUrl, {
|
|
1736
|
+
headers: {
|
|
1737
|
+
Authorization: `Token ${this.config.apiKey}`
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
let sessionStatus = "connecting";
|
|
1741
|
+
const sessionId = `deepgram-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
1742
|
+
ws.on("open", () => {
|
|
1743
|
+
sessionStatus = "open";
|
|
1744
|
+
callbacks?.onOpen?.();
|
|
1745
|
+
});
|
|
1746
|
+
ws.on("message", (data) => {
|
|
1747
|
+
try {
|
|
1748
|
+
const message = JSON.parse(data.toString());
|
|
1749
|
+
if (message.type === "Results") {
|
|
1750
|
+
const result = message;
|
|
1751
|
+
const channel = result.channel?.alternatives?.[0];
|
|
1752
|
+
if (channel) {
|
|
1753
|
+
const transcript = channel.transcript || "";
|
|
1754
|
+
const isFinal = message.is_final === true;
|
|
1755
|
+
const words = channel.words?.map((word) => ({
|
|
1756
|
+
text: word.word || "",
|
|
1757
|
+
start: word.start || 0,
|
|
1758
|
+
end: word.end || 0,
|
|
1759
|
+
confidence: word.confidence
|
|
1760
|
+
}));
|
|
1761
|
+
callbacks?.onTranscript?.({
|
|
1762
|
+
type: "transcript",
|
|
1763
|
+
text: transcript,
|
|
1764
|
+
isFinal,
|
|
1765
|
+
words,
|
|
1766
|
+
confidence: channel.confidence,
|
|
1767
|
+
data: result
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
} else if (message.type === "UtteranceEnd") {
|
|
1771
|
+
callbacks?.onMetadata?.(message);
|
|
1772
|
+
} else if (message.type === "Metadata") {
|
|
1773
|
+
callbacks?.onMetadata?.(message);
|
|
1774
|
+
}
|
|
1775
|
+
} catch (error) {
|
|
1776
|
+
callbacks?.onError?.({
|
|
1777
|
+
code: "PARSE_ERROR",
|
|
1778
|
+
message: "Failed to parse WebSocket message",
|
|
1779
|
+
details: error
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
ws.on("error", (error) => {
|
|
1784
|
+
callbacks?.onError?.({
|
|
1785
|
+
code: "WEBSOCKET_ERROR",
|
|
1786
|
+
message: error.message,
|
|
1787
|
+
details: error
|
|
1788
|
+
});
|
|
1789
|
+
});
|
|
1790
|
+
ws.on("close", (code, reason) => {
|
|
1791
|
+
sessionStatus = "closed";
|
|
1792
|
+
callbacks?.onClose?.(code, reason.toString());
|
|
1793
|
+
});
|
|
1794
|
+
await new Promise((resolve, reject) => {
|
|
1795
|
+
const timeout = setTimeout(() => {
|
|
1796
|
+
reject(new Error("WebSocket connection timeout"));
|
|
1797
|
+
}, 1e4);
|
|
1798
|
+
ws.once("open", () => {
|
|
1799
|
+
clearTimeout(timeout);
|
|
1800
|
+
resolve();
|
|
1801
|
+
});
|
|
1802
|
+
ws.once("error", (error) => {
|
|
1803
|
+
clearTimeout(timeout);
|
|
1804
|
+
reject(error);
|
|
1805
|
+
});
|
|
1806
|
+
});
|
|
1807
|
+
return {
|
|
1808
|
+
id: sessionId,
|
|
1809
|
+
provider: this.name,
|
|
1810
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1811
|
+
getStatus: () => sessionStatus,
|
|
1812
|
+
sendAudio: async (chunk) => {
|
|
1813
|
+
if (sessionStatus !== "open") {
|
|
1814
|
+
throw new Error(`Cannot send audio: session is ${sessionStatus}`);
|
|
1815
|
+
}
|
|
1816
|
+
if (ws.readyState !== import_ws3.default.OPEN) {
|
|
1817
|
+
throw new Error("WebSocket is not open");
|
|
1818
|
+
}
|
|
1819
|
+
ws.send(chunk.data);
|
|
1820
|
+
if (chunk.isLast) {
|
|
1821
|
+
ws.send(JSON.stringify({ type: "CloseStream" }));
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1824
|
+
close: async () => {
|
|
1825
|
+
if (sessionStatus === "closed" || sessionStatus === "closing") {
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
sessionStatus = "closing";
|
|
1829
|
+
if (ws.readyState === import_ws3.default.OPEN) {
|
|
1830
|
+
ws.send(JSON.stringify({ type: "CloseStream" }));
|
|
1831
|
+
}
|
|
1832
|
+
return new Promise((resolve) => {
|
|
1833
|
+
const timeout = setTimeout(() => {
|
|
1834
|
+
ws.terminate();
|
|
1835
|
+
resolve();
|
|
1836
|
+
}, 5e3);
|
|
1837
|
+
ws.close();
|
|
1838
|
+
ws.once("close", () => {
|
|
1839
|
+
clearTimeout(timeout);
|
|
1840
|
+
sessionStatus = "closed";
|
|
1841
|
+
resolve();
|
|
1842
|
+
});
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
function createDeepgramAdapter(config) {
|
|
1849
|
+
const adapter = new DeepgramAdapter();
|
|
1850
|
+
adapter.initialize(config);
|
|
1851
|
+
return adapter;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
// src/adapters/azure-stt-adapter.ts
|
|
1855
|
+
var import_axios4 = __toESM(require("axios"));
|
|
1856
|
+
var AzureSTTAdapter = class extends BaseAdapter {
|
|
1857
|
+
constructor() {
|
|
1858
|
+
super(...arguments);
|
|
1859
|
+
this.name = "azure-stt";
|
|
1860
|
+
this.capabilities = {
|
|
1861
|
+
streaming: false,
|
|
1862
|
+
// Batch transcription only
|
|
1863
|
+
diarization: true,
|
|
1864
|
+
wordTimestamps: true,
|
|
1865
|
+
languageDetection: false,
|
|
1866
|
+
customVocabulary: true,
|
|
1867
|
+
summarization: false,
|
|
1868
|
+
sentimentAnalysis: false,
|
|
1869
|
+
entityDetection: false,
|
|
1870
|
+
piiRedaction: false
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
initialize(config) {
|
|
1874
|
+
super.initialize(config);
|
|
1875
|
+
this.region = config.region || "eastus";
|
|
1876
|
+
this.baseUrl = config.baseUrl || `https://${this.region}.api.cognitive.microsoft.com/speechtotext/v3.1`;
|
|
1877
|
+
this.client = import_axios4.default.create({
|
|
1878
|
+
baseURL: this.baseUrl,
|
|
1879
|
+
timeout: config.timeout || 6e4,
|
|
1880
|
+
headers: {
|
|
1881
|
+
"Ocp-Apim-Subscription-Key": config.apiKey,
|
|
1882
|
+
"Content-Type": "application/json",
|
|
1883
|
+
...config.headers
|
|
1884
|
+
}
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Submit audio for transcription
|
|
1889
|
+
*
|
|
1890
|
+
* Azure Speech-to-Text uses batch transcription which processes asynchronously.
|
|
1891
|
+
* You need to poll getTranscript() to retrieve the completed transcription.
|
|
1892
|
+
*
|
|
1893
|
+
* @param audio - Audio input (URL only for batch transcription)
|
|
1894
|
+
* @param options - Transcription options
|
|
1895
|
+
* @returns Response with transcription ID for polling
|
|
1896
|
+
*/
|
|
1897
|
+
async transcribe(audio, options) {
|
|
1898
|
+
this.validateConfig();
|
|
1899
|
+
if (audio.type !== "url") {
|
|
1900
|
+
return {
|
|
1901
|
+
success: false,
|
|
1902
|
+
provider: this.name,
|
|
1903
|
+
error: {
|
|
1904
|
+
code: "INVALID_INPUT",
|
|
1905
|
+
message: "Azure Speech-to-Text batch transcription only supports URL input"
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
try {
|
|
1910
|
+
const transcriptionRequest = {
|
|
1911
|
+
displayName: options?.metadata?.displayName || "SDK Transcription",
|
|
1912
|
+
description: options?.metadata?.description || "",
|
|
1913
|
+
locale: options?.language || "en-US",
|
|
1914
|
+
contentUrls: [audio.url],
|
|
1915
|
+
properties: this.buildTranscriptionProperties(options)
|
|
1916
|
+
};
|
|
1917
|
+
const response = await this.client.post(
|
|
1918
|
+
"/transcriptions",
|
|
1919
|
+
transcriptionRequest
|
|
1920
|
+
);
|
|
1921
|
+
const transcription = response.data;
|
|
1922
|
+
return {
|
|
1923
|
+
success: true,
|
|
1924
|
+
provider: this.name,
|
|
1925
|
+
data: {
|
|
1926
|
+
id: transcription.self?.split("/").pop() || "",
|
|
1927
|
+
text: "",
|
|
1928
|
+
// Will be populated after polling
|
|
1929
|
+
status: this.normalizeStatus(transcription.status),
|
|
1930
|
+
language: transcription.locale,
|
|
1931
|
+
createdAt: transcription.createdDateTime
|
|
1932
|
+
},
|
|
1933
|
+
raw: transcription
|
|
1934
|
+
};
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
return this.createErrorResponse(error);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
/**
|
|
1940
|
+
* Get transcription result by ID
|
|
1941
|
+
*
|
|
1942
|
+
* Poll this method to check transcription status and retrieve results.
|
|
1943
|
+
*
|
|
1944
|
+
* @param transcriptId - Transcription ID from Azure
|
|
1945
|
+
* @returns Transcription response with status and results
|
|
1946
|
+
*/
|
|
1947
|
+
async getTranscript(transcriptId) {
|
|
1948
|
+
this.validateConfig();
|
|
1949
|
+
try {
|
|
1950
|
+
const statusResponse = await this.client.get(
|
|
1951
|
+
`/transcriptions/${transcriptId}`
|
|
1952
|
+
);
|
|
1953
|
+
const transcription = statusResponse.data;
|
|
1954
|
+
const status = this.normalizeStatus(transcription.status);
|
|
1955
|
+
if (status !== "completed") {
|
|
1956
|
+
return {
|
|
1957
|
+
success: true,
|
|
1958
|
+
provider: this.name,
|
|
1959
|
+
data: {
|
|
1960
|
+
id: transcriptId,
|
|
1961
|
+
text: "",
|
|
1962
|
+
status,
|
|
1963
|
+
language: transcription.locale,
|
|
1964
|
+
createdAt: transcription.createdDateTime
|
|
1965
|
+
},
|
|
1966
|
+
raw: transcription
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
if (!transcription.links?.files) {
|
|
1970
|
+
return {
|
|
1971
|
+
success: false,
|
|
1972
|
+
provider: this.name,
|
|
1973
|
+
error: {
|
|
1974
|
+
code: "NO_RESULTS",
|
|
1975
|
+
message: "Transcription completed but no result files available"
|
|
1976
|
+
},
|
|
1977
|
+
raw: transcription
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
const filesResponse = await this.client.get(transcription.links.files);
|
|
1981
|
+
const files = filesResponse.data?.values || [];
|
|
1982
|
+
const resultFile = files.find((file) => file.kind === "Transcription");
|
|
1983
|
+
if (!resultFile?.links?.contentUrl) {
|
|
1984
|
+
return {
|
|
1985
|
+
success: false,
|
|
1986
|
+
provider: this.name,
|
|
1987
|
+
error: {
|
|
1988
|
+
code: "NO_RESULTS",
|
|
1989
|
+
message: "Transcription result file not found"
|
|
1990
|
+
},
|
|
1991
|
+
raw: transcription
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
const contentResponse = await import_axios4.default.get(resultFile.links.contentUrl);
|
|
1995
|
+
const transcriptionData = contentResponse.data;
|
|
1996
|
+
return this.normalizeResponse(transcription, transcriptionData);
|
|
1997
|
+
} catch (error) {
|
|
1998
|
+
return this.createErrorResponse(error);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* Build Azure-specific transcription properties
|
|
2003
|
+
*/
|
|
2004
|
+
buildTranscriptionProperties(options) {
|
|
2005
|
+
const properties = {
|
|
2006
|
+
wordLevelTimestampsEnabled: options?.wordTimestamps ?? true,
|
|
2007
|
+
punctuationMode: "DictatedAndAutomatic",
|
|
2008
|
+
profanityFilterMode: "Masked"
|
|
2009
|
+
};
|
|
2010
|
+
if (options?.diarization) {
|
|
2011
|
+
properties.diarizationEnabled = true;
|
|
2012
|
+
if (options.speakersExpected) {
|
|
2013
|
+
properties.diarization = {
|
|
2014
|
+
speakers: {
|
|
2015
|
+
minCount: 1,
|
|
2016
|
+
maxCount: options.speakersExpected
|
|
2017
|
+
}
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
if (options?.customVocabulary && options.customVocabulary.length > 0) {
|
|
2022
|
+
properties.customProperties = {
|
|
2023
|
+
phrases: options.customVocabulary.join(",")
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
return properties;
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* Normalize Azure status to unified status
|
|
2030
|
+
*/
|
|
2031
|
+
normalizeStatus(status) {
|
|
2032
|
+
const statusStr = status?.toString().toLowerCase() || "";
|
|
2033
|
+
if (statusStr.includes("succeeded")) return "completed";
|
|
2034
|
+
if (statusStr.includes("running")) return "processing";
|
|
2035
|
+
if (statusStr.includes("notstarted")) return "queued";
|
|
2036
|
+
if (statusStr.includes("failed")) return "error";
|
|
2037
|
+
return "queued";
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Normalize Azure transcription response to unified format
|
|
2041
|
+
*/
|
|
2042
|
+
normalizeResponse(transcription, transcriptionData) {
|
|
2043
|
+
const combinedPhrases = transcriptionData.combinedRecognizedPhrases || [];
|
|
2044
|
+
const recognizedPhrases = transcriptionData.recognizedPhrases || [];
|
|
2045
|
+
const fullText = combinedPhrases.map((phrase) => phrase.display || phrase.lexical).join(" ") || "";
|
|
2046
|
+
const words = recognizedPhrases.flatMap(
|
|
2047
|
+
(phrase) => (phrase.nBest?.[0]?.words || []).map((word) => ({
|
|
2048
|
+
text: word.word,
|
|
2049
|
+
start: word.offsetInTicks / 1e7,
|
|
2050
|
+
// Convert ticks to seconds
|
|
2051
|
+
end: (word.offsetInTicks + word.durationInTicks) / 1e7,
|
|
2052
|
+
confidence: word.confidence,
|
|
2053
|
+
speaker: phrase.speaker !== void 0 ? phrase.speaker.toString() : void 0
|
|
2054
|
+
}))
|
|
2055
|
+
);
|
|
2056
|
+
const speakers = recognizedPhrases.length > 0 && recognizedPhrases[0].speaker !== void 0 ? Array.from(
|
|
2057
|
+
new Set(
|
|
2058
|
+
recognizedPhrases.map((p) => p.speaker).filter((s) => s !== void 0)
|
|
2059
|
+
)
|
|
2060
|
+
).map((speakerId) => ({
|
|
2061
|
+
id: String(speakerId),
|
|
2062
|
+
label: `Speaker ${speakerId}`
|
|
2063
|
+
})) : void 0;
|
|
2064
|
+
return {
|
|
2065
|
+
success: true,
|
|
2066
|
+
provider: this.name,
|
|
2067
|
+
data: {
|
|
2068
|
+
id: transcription.self?.split("/").pop() || "",
|
|
2069
|
+
text: fullText,
|
|
2070
|
+
confidence: recognizedPhrases[0]?.nBest?.[0]?.confidence,
|
|
2071
|
+
status: "completed",
|
|
2072
|
+
language: transcription.locale,
|
|
2073
|
+
duration: transcriptionData.duration ? transcriptionData.duration / 1e7 : void 0,
|
|
2074
|
+
speakers,
|
|
2075
|
+
words: words.length > 0 ? words : void 0,
|
|
2076
|
+
createdAt: transcription.createdDateTime,
|
|
2077
|
+
completedAt: transcription.lastActionDateTime
|
|
2078
|
+
},
|
|
2079
|
+
raw: {
|
|
2080
|
+
transcription,
|
|
2081
|
+
transcriptionData
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
2086
|
+
function createAzureSTTAdapter(config) {
|
|
2087
|
+
const adapter = new AzureSTTAdapter();
|
|
2088
|
+
adapter.initialize(config);
|
|
2089
|
+
return adapter;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// src/adapters/openai-whisper-adapter.ts
|
|
2093
|
+
var import_axios5 = __toESM(require("axios"));
|
|
2094
|
+
var OpenAIWhisperAdapter = class extends BaseAdapter {
|
|
2095
|
+
constructor() {
|
|
2096
|
+
super(...arguments);
|
|
2097
|
+
this.name = "openai-whisper";
|
|
2098
|
+
this.capabilities = {
|
|
2099
|
+
streaming: false,
|
|
2100
|
+
// Synchronous only (no streaming API for transcription)
|
|
2101
|
+
diarization: true,
|
|
2102
|
+
// Available with gpt-4o-transcribe-diarize model
|
|
2103
|
+
wordTimestamps: true,
|
|
2104
|
+
languageDetection: false,
|
|
2105
|
+
// Language should be provided for best accuracy
|
|
2106
|
+
customVocabulary: false,
|
|
2107
|
+
// Uses prompt instead
|
|
2108
|
+
summarization: false,
|
|
2109
|
+
sentimentAnalysis: false,
|
|
2110
|
+
entityDetection: false,
|
|
2111
|
+
piiRedaction: false
|
|
2112
|
+
};
|
|
2113
|
+
this.baseUrl = "https://api.openai.com/v1";
|
|
2114
|
+
}
|
|
2115
|
+
initialize(config) {
|
|
2116
|
+
super.initialize(config);
|
|
2117
|
+
this.baseUrl = config.baseUrl || this.baseUrl;
|
|
2118
|
+
this.client = import_axios5.default.create({
|
|
2119
|
+
baseURL: this.baseUrl,
|
|
2120
|
+
timeout: config.timeout || 12e4,
|
|
2121
|
+
// 2 minutes default (audio processing can take time)
|
|
2122
|
+
headers: {
|
|
2123
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
2124
|
+
"Content-Type": "multipart/form-data",
|
|
2125
|
+
...config.headers
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Submit audio for transcription
|
|
2131
|
+
*
|
|
2132
|
+
* OpenAI Whisper API processes audio synchronously and returns results immediately.
|
|
2133
|
+
* Supports multiple models with different capabilities:
|
|
2134
|
+
* - whisper-1: Open source Whisper V2 model
|
|
2135
|
+
* - gpt-4o-transcribe: More accurate GPT-4o based transcription
|
|
2136
|
+
* - gpt-4o-mini-transcribe: Faster, cost-effective GPT-4o mini
|
|
2137
|
+
* - gpt-4o-transcribe-diarize: GPT-4o with speaker diarization
|
|
2138
|
+
*
|
|
2139
|
+
* @param audio - Audio input (URL or Buffer)
|
|
2140
|
+
* @param options - Transcription options
|
|
2141
|
+
* @returns Transcription response with full results
|
|
2142
|
+
*/
|
|
2143
|
+
async transcribe(audio, options) {
|
|
2144
|
+
this.validateConfig();
|
|
2145
|
+
try {
|
|
2146
|
+
let audioData;
|
|
2147
|
+
let fileName = "audio.mp3";
|
|
2148
|
+
if (audio.type === "url") {
|
|
2149
|
+
const response2 = await import_axios5.default.get(audio.url, {
|
|
2150
|
+
responseType: "arraybuffer"
|
|
2151
|
+
});
|
|
2152
|
+
audioData = Buffer.from(response2.data);
|
|
2153
|
+
const urlPath = new URL(audio.url).pathname;
|
|
2154
|
+
const extractedName = urlPath.split("/").pop();
|
|
2155
|
+
if (extractedName) {
|
|
2156
|
+
fileName = extractedName;
|
|
2157
|
+
}
|
|
2158
|
+
} else if (audio.type === "file") {
|
|
2159
|
+
audioData = audio.file;
|
|
2160
|
+
fileName = audio.filename || fileName;
|
|
2161
|
+
} else {
|
|
2162
|
+
return {
|
|
2163
|
+
success: false,
|
|
2164
|
+
provider: this.name,
|
|
2165
|
+
error: {
|
|
2166
|
+
code: "INVALID_INPUT",
|
|
2167
|
+
message: "OpenAI Whisper only supports URL and File audio input (not stream)"
|
|
2168
|
+
}
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
const model = this.selectModel(options);
|
|
2172
|
+
const isDiarization = model === "gpt-4o-transcribe-diarize";
|
|
2173
|
+
const needsWords = options?.wordTimestamps === true;
|
|
2174
|
+
const requestBody = {
|
|
2175
|
+
file: audioData,
|
|
2176
|
+
model
|
|
2177
|
+
};
|
|
2178
|
+
if (options?.language) {
|
|
2179
|
+
requestBody.language = options.language;
|
|
2180
|
+
}
|
|
2181
|
+
if (options?.metadata?.prompt) {
|
|
2182
|
+
requestBody.prompt = options.metadata.prompt;
|
|
2183
|
+
}
|
|
2184
|
+
if (options?.metadata?.temperature !== void 0) {
|
|
2185
|
+
requestBody.temperature = options.metadata.temperature;
|
|
2186
|
+
}
|
|
2187
|
+
if (isDiarization) {
|
|
2188
|
+
requestBody.response_format = "diarized_json";
|
|
2189
|
+
if (options?.metadata?.knownSpeakerNames) {
|
|
2190
|
+
requestBody["known_speaker_names"] = options.metadata.knownSpeakerNames;
|
|
2191
|
+
}
|
|
2192
|
+
if (options?.metadata?.knownSpeakerReferences) {
|
|
2193
|
+
requestBody["known_speaker_references"] = options.metadata.knownSpeakerReferences;
|
|
2194
|
+
}
|
|
2195
|
+
} else if (needsWords || options?.diarization) {
|
|
2196
|
+
requestBody.response_format = "verbose_json";
|
|
2197
|
+
if (needsWords) {
|
|
2198
|
+
requestBody.timestamp_granularities = ["word", "segment"];
|
|
2199
|
+
}
|
|
2200
|
+
} else {
|
|
2201
|
+
requestBody.response_format = "json";
|
|
2202
|
+
}
|
|
2203
|
+
const response = await this.client.post("/audio/transcriptions", requestBody, {
|
|
2204
|
+
headers: {
|
|
2205
|
+
"Content-Type": "multipart/form-data"
|
|
2206
|
+
}
|
|
2207
|
+
});
|
|
2208
|
+
return this.normalizeResponse(response.data, model, isDiarization);
|
|
2209
|
+
} catch (error) {
|
|
2210
|
+
return this.createErrorResponse(error);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* OpenAI Whisper returns results synchronously, so getTranscript is not needed.
|
|
2215
|
+
* This method exists for interface compatibility but will return an error.
|
|
2216
|
+
*/
|
|
2217
|
+
async getTranscript(transcriptId) {
|
|
2218
|
+
return {
|
|
2219
|
+
success: false,
|
|
2220
|
+
provider: this.name,
|
|
2221
|
+
error: {
|
|
2222
|
+
code: "NOT_SUPPORTED",
|
|
2223
|
+
message: "OpenAI Whisper processes transcriptions synchronously. Use transcribe() method directly."
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Select appropriate model based on transcription options
|
|
2229
|
+
*/
|
|
2230
|
+
selectModel(options) {
|
|
2231
|
+
if (options?.metadata?.model) {
|
|
2232
|
+
return options.metadata.model;
|
|
2233
|
+
}
|
|
2234
|
+
if (options?.diarization) {
|
|
2235
|
+
return "gpt-4o-transcribe-diarize";
|
|
2236
|
+
}
|
|
2237
|
+
return "gpt-4o-transcribe";
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Normalize OpenAI response to unified format
|
|
2241
|
+
*/
|
|
2242
|
+
normalizeResponse(response, model, isDiarization) {
|
|
2243
|
+
if ("text" in response && Object.keys(response).length === 1) {
|
|
2244
|
+
return {
|
|
2245
|
+
success: true,
|
|
2246
|
+
provider: this.name,
|
|
2247
|
+
data: {
|
|
2248
|
+
id: `openai-${Date.now()}`,
|
|
2249
|
+
text: response.text,
|
|
2250
|
+
status: "completed",
|
|
2251
|
+
language: void 0,
|
|
2252
|
+
confidence: void 0
|
|
2253
|
+
},
|
|
2254
|
+
raw: response
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
if (isDiarization && "segments" in response) {
|
|
2258
|
+
const diarizedResponse = response;
|
|
2259
|
+
const speakerSet = new Set(diarizedResponse.segments.map((seg) => seg.speaker));
|
|
2260
|
+
const speakers = Array.from(speakerSet).map((speaker) => ({
|
|
2261
|
+
id: speaker,
|
|
2262
|
+
label: speaker
|
|
2263
|
+
// Already labeled by OpenAI (A, B, C or custom names)
|
|
2264
|
+
}));
|
|
2265
|
+
const utterances = diarizedResponse.segments.map((segment) => ({
|
|
2266
|
+
speaker: segment.speaker,
|
|
2267
|
+
text: segment.text,
|
|
2268
|
+
start: segment.start,
|
|
2269
|
+
end: segment.end,
|
|
2270
|
+
confidence: void 0
|
|
2271
|
+
}));
|
|
2272
|
+
return {
|
|
2273
|
+
success: true,
|
|
2274
|
+
provider: this.name,
|
|
2275
|
+
data: {
|
|
2276
|
+
id: `openai-${Date.now()}`,
|
|
2277
|
+
text: diarizedResponse.text,
|
|
2278
|
+
status: "completed",
|
|
2279
|
+
language: void 0,
|
|
2280
|
+
duration: diarizedResponse.duration,
|
|
2281
|
+
speakers,
|
|
2282
|
+
utterances
|
|
2283
|
+
},
|
|
2284
|
+
raw: response
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
if ("duration" in response && "language" in response) {
|
|
2288
|
+
const verboseResponse = response;
|
|
2289
|
+
const words = verboseResponse.words?.map((word) => ({
|
|
2290
|
+
text: word.word,
|
|
2291
|
+
start: word.start,
|
|
2292
|
+
end: word.end,
|
|
2293
|
+
confidence: void 0
|
|
2294
|
+
}));
|
|
2295
|
+
return {
|
|
2296
|
+
success: true,
|
|
2297
|
+
provider: this.name,
|
|
2298
|
+
data: {
|
|
2299
|
+
id: `openai-${Date.now()}`,
|
|
2300
|
+
text: verboseResponse.text,
|
|
2301
|
+
status: "completed",
|
|
2302
|
+
language: verboseResponse.language,
|
|
2303
|
+
duration: verboseResponse.duration,
|
|
2304
|
+
words
|
|
2305
|
+
},
|
|
2306
|
+
raw: response
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
2309
|
+
return {
|
|
2310
|
+
success: true,
|
|
2311
|
+
provider: this.name,
|
|
2312
|
+
data: {
|
|
2313
|
+
id: `openai-${Date.now()}`,
|
|
2314
|
+
text: "text" in response ? response.text : "",
|
|
2315
|
+
status: "completed"
|
|
2316
|
+
},
|
|
2317
|
+
raw: response
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
function createOpenAIWhisperAdapter(config) {
|
|
2322
|
+
const adapter = new OpenAIWhisperAdapter();
|
|
2323
|
+
adapter.initialize(config);
|
|
2324
|
+
return adapter;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
// src/adapters/speechmatics-adapter.ts
|
|
2328
|
+
var import_axios6 = __toESM(require("axios"));
|
|
2329
|
+
var SpeechmaticsAdapter = class extends BaseAdapter {
|
|
2330
|
+
constructor() {
|
|
2331
|
+
super(...arguments);
|
|
2332
|
+
this.name = "speechmatics";
|
|
2333
|
+
this.capabilities = {
|
|
2334
|
+
streaming: false,
|
|
2335
|
+
// Batch only (streaming available via separate WebSocket API)
|
|
2336
|
+
diarization: true,
|
|
2337
|
+
wordTimestamps: true,
|
|
2338
|
+
languageDetection: false,
|
|
2339
|
+
customVocabulary: true,
|
|
2340
|
+
summarization: true,
|
|
2341
|
+
sentimentAnalysis: true,
|
|
2342
|
+
entityDetection: true,
|
|
2343
|
+
piiRedaction: false
|
|
2344
|
+
};
|
|
2345
|
+
this.baseUrl = "https://asr.api.speechmatics.com/v2";
|
|
2346
|
+
}
|
|
2347
|
+
initialize(config) {
|
|
2348
|
+
super.initialize(config);
|
|
2349
|
+
this.baseUrl = config.baseUrl || this.baseUrl;
|
|
2350
|
+
this.client = import_axios6.default.create({
|
|
2351
|
+
baseURL: this.baseUrl,
|
|
2352
|
+
timeout: config.timeout || 12e4,
|
|
2353
|
+
headers: {
|
|
2354
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
2355
|
+
...config.headers
|
|
2356
|
+
}
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
/**
|
|
2360
|
+
* Submit audio for transcription
|
|
2361
|
+
*
|
|
2362
|
+
* Speechmatics uses async batch processing. Returns a job ID immediately.
|
|
2363
|
+
* Poll getTranscript() to retrieve results.
|
|
2364
|
+
*
|
|
2365
|
+
* @param audio - Audio input (URL or file)
|
|
2366
|
+
* @param options - Transcription options
|
|
2367
|
+
* @returns Job submission response with ID for polling
|
|
2368
|
+
*/
|
|
2369
|
+
async transcribe(audio, options) {
|
|
2370
|
+
this.validateConfig();
|
|
2371
|
+
try {
|
|
2372
|
+
const jobConfig = {
|
|
2373
|
+
type: "transcription",
|
|
2374
|
+
transcription_config: {
|
|
2375
|
+
language: options?.language || "en",
|
|
2376
|
+
operating_point: options?.metadata?.operating_point || "standard"
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
if (options?.diarization) {
|
|
2380
|
+
jobConfig.transcription_config.diarization = "speaker";
|
|
2381
|
+
if (options.speakersExpected) {
|
|
2382
|
+
jobConfig.transcription_config.speaker_diarization_config = {
|
|
2383
|
+
max_speakers: options.speakersExpected
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
if (options?.sentimentAnalysis) {
|
|
2388
|
+
jobConfig.transcription_config.enable_sentiment_analysis = true;
|
|
2389
|
+
}
|
|
2390
|
+
if (options?.summarization && options?.metadata?.summary_type) {
|
|
2391
|
+
jobConfig.transcription_config.summarization_config = {
|
|
2392
|
+
type: options.metadata.summary_type,
|
|
2393
|
+
length: options.metadata.summary_length || "medium"
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
if (options?.customVocabulary && options.customVocabulary.length > 0) {
|
|
2397
|
+
jobConfig.transcription_config.additional_vocab = options.customVocabulary;
|
|
2398
|
+
}
|
|
2399
|
+
let requestBody;
|
|
2400
|
+
let headers = {};
|
|
2401
|
+
if (audio.type === "url") {
|
|
2402
|
+
jobConfig.fetch_data = {
|
|
2403
|
+
url: audio.url
|
|
2404
|
+
};
|
|
2405
|
+
requestBody = { config: JSON.stringify(jobConfig) };
|
|
2406
|
+
headers = { "Content-Type": "application/json" };
|
|
2407
|
+
} else if (audio.type === "file") {
|
|
2408
|
+
requestBody = {
|
|
2409
|
+
config: JSON.stringify(jobConfig),
|
|
2410
|
+
data_file: audio.file
|
|
2411
|
+
};
|
|
2412
|
+
headers = { "Content-Type": "multipart/form-data" };
|
|
2413
|
+
} else {
|
|
2414
|
+
return {
|
|
2415
|
+
success: false,
|
|
2416
|
+
provider: this.name,
|
|
2417
|
+
error: {
|
|
2418
|
+
code: "INVALID_INPUT",
|
|
2419
|
+
message: "Speechmatics only supports URL and File audio input"
|
|
2420
|
+
}
|
|
2421
|
+
};
|
|
2422
|
+
}
|
|
2423
|
+
const response = await this.client.post("/jobs", requestBody, { headers });
|
|
2424
|
+
return {
|
|
2425
|
+
success: true,
|
|
2426
|
+
provider: this.name,
|
|
2427
|
+
data: {
|
|
2428
|
+
id: response.data.id,
|
|
2429
|
+
text: "",
|
|
2430
|
+
status: "queued",
|
|
2431
|
+
createdAt: response.data.created_at
|
|
2432
|
+
},
|
|
2433
|
+
raw: response.data
|
|
2434
|
+
};
|
|
2435
|
+
} catch (error) {
|
|
2436
|
+
return this.createErrorResponse(error);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Get transcription result by job ID
|
|
2441
|
+
*
|
|
2442
|
+
* Poll this method to check job status and retrieve completed transcription.
|
|
2443
|
+
*
|
|
2444
|
+
* @param transcriptId - Job ID from Speechmatics
|
|
2445
|
+
* @returns Transcription response with status and results
|
|
2446
|
+
*/
|
|
2447
|
+
async getTranscript(transcriptId) {
|
|
2448
|
+
this.validateConfig();
|
|
2449
|
+
try {
|
|
2450
|
+
const statusResponse = await this.client.get(`/jobs/${transcriptId}`);
|
|
2451
|
+
const status = this.normalizeStatus(statusResponse.data.job.status);
|
|
2452
|
+
if (status !== "completed") {
|
|
2453
|
+
return {
|
|
2454
|
+
success: true,
|
|
2455
|
+
provider: this.name,
|
|
2456
|
+
data: {
|
|
2457
|
+
id: transcriptId,
|
|
2458
|
+
text: "",
|
|
2459
|
+
status,
|
|
2460
|
+
createdAt: statusResponse.data.job.created_at
|
|
2461
|
+
},
|
|
2462
|
+
raw: statusResponse.data
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
const transcriptResponse = await this.client.get(
|
|
2466
|
+
`/jobs/${transcriptId}/transcript`
|
|
2467
|
+
);
|
|
2468
|
+
return this.normalizeResponse(transcriptResponse.data);
|
|
2469
|
+
} catch (error) {
|
|
2470
|
+
return this.createErrorResponse(error);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Normalize Speechmatics status to unified status
|
|
2475
|
+
*/
|
|
2476
|
+
normalizeStatus(status) {
|
|
2477
|
+
switch (status) {
|
|
2478
|
+
case "running":
|
|
2479
|
+
return "processing";
|
|
2480
|
+
case "done":
|
|
2481
|
+
return "completed";
|
|
2482
|
+
case "rejected":
|
|
2483
|
+
case "expired":
|
|
2484
|
+
return "error";
|
|
2485
|
+
default:
|
|
2486
|
+
return "queued";
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* Normalize Speechmatics response to unified format
|
|
2491
|
+
*/
|
|
2492
|
+
normalizeResponse(response) {
|
|
2493
|
+
const text = response.results.filter((r) => r.type === "word").map((r) => r.alternatives[0]?.content || "").join(" ");
|
|
2494
|
+
const words = response.results.filter((r) => r.type === "word").map((result) => ({
|
|
2495
|
+
text: result.alternatives[0]?.content || "",
|
|
2496
|
+
start: result.start_time,
|
|
2497
|
+
end: result.end_time,
|
|
2498
|
+
confidence: result.alternatives[0]?.confidence,
|
|
2499
|
+
speaker: result.alternatives[0]?.speaker
|
|
2500
|
+
}));
|
|
2501
|
+
const speakerSet = /* @__PURE__ */ new Set();
|
|
2502
|
+
response.results.forEach((r) => {
|
|
2503
|
+
const speaker = r.alternatives[0]?.speaker;
|
|
2504
|
+
if (speaker) speakerSet.add(speaker);
|
|
2505
|
+
});
|
|
2506
|
+
const speakers = speakerSet.size > 0 ? Array.from(speakerSet).map((id) => ({
|
|
2507
|
+
id,
|
|
2508
|
+
label: `Speaker ${id}`
|
|
2509
|
+
})) : void 0;
|
|
2510
|
+
const utterances = [];
|
|
2511
|
+
if (speakers) {
|
|
2512
|
+
let currentSpeaker;
|
|
2513
|
+
let currentUtterance = [];
|
|
2514
|
+
let utteranceStart = 0;
|
|
2515
|
+
response.results.filter((r) => r.type === "word").forEach((result, idx) => {
|
|
2516
|
+
const speaker = result.alternatives[0]?.speaker;
|
|
2517
|
+
const word = result.alternatives[0]?.content || "";
|
|
2518
|
+
if (speaker !== currentSpeaker) {
|
|
2519
|
+
if (currentSpeaker && currentUtterance.length > 0) {
|
|
2520
|
+
const prevResult = response.results.filter((r) => r.type === "word")[idx - 1];
|
|
2521
|
+
utterances.push({
|
|
2522
|
+
speaker: currentSpeaker,
|
|
2523
|
+
text: currentUtterance.join(" "),
|
|
2524
|
+
start: utteranceStart,
|
|
2525
|
+
end: prevResult?.end_time || result.start_time
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
currentSpeaker = speaker;
|
|
2529
|
+
currentUtterance = [word];
|
|
2530
|
+
utteranceStart = result.start_time;
|
|
2531
|
+
} else {
|
|
2532
|
+
currentUtterance.push(word);
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
if (currentSpeaker && currentUtterance.length > 0) {
|
|
2536
|
+
const lastWord = response.results.filter((r) => r.type === "word").pop();
|
|
2537
|
+
utterances.push({
|
|
2538
|
+
speaker: currentSpeaker,
|
|
2539
|
+
text: currentUtterance.join(" "),
|
|
2540
|
+
start: utteranceStart,
|
|
2541
|
+
end: lastWord?.end_time || utteranceStart
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
return {
|
|
2546
|
+
success: true,
|
|
2547
|
+
provider: this.name,
|
|
2548
|
+
data: {
|
|
2549
|
+
id: response.job.id,
|
|
2550
|
+
text,
|
|
2551
|
+
status: "completed",
|
|
2552
|
+
language: response.metadata.transcription_config.language,
|
|
2553
|
+
duration: response.job.duration,
|
|
2554
|
+
speakers,
|
|
2555
|
+
words: words.length > 0 ? words : void 0,
|
|
2556
|
+
utterances: utterances.length > 0 ? utterances : void 0,
|
|
2557
|
+
summary: response.summary?.content,
|
|
2558
|
+
createdAt: response.job.created_at
|
|
2559
|
+
},
|
|
2560
|
+
raw: response
|
|
2561
|
+
};
|
|
2562
|
+
}
|
|
2563
|
+
};
|
|
2564
|
+
function createSpeechmaticsAdapter(config) {
|
|
2565
|
+
const adapter = new SpeechmaticsAdapter();
|
|
2566
|
+
adapter.initialize(config);
|
|
2567
|
+
return adapter;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
// src/webhooks/base-webhook.ts
|
|
2571
|
+
var BaseWebhookHandler = class {
|
|
2572
|
+
/**
|
|
2573
|
+
* Validate webhook payload structure
|
|
2574
|
+
*
|
|
2575
|
+
* Checks if payload has required fields and correct types
|
|
2576
|
+
*
|
|
2577
|
+
* @param payload - Raw webhook payload
|
|
2578
|
+
* @param options - Optional context (query params, headers, etc.)
|
|
2579
|
+
* @returns Validation result with details
|
|
2580
|
+
*/
|
|
2581
|
+
validate(payload, options) {
|
|
2582
|
+
try {
|
|
2583
|
+
if (!this.matches(payload, options)) {
|
|
2584
|
+
return {
|
|
2585
|
+
valid: false,
|
|
2586
|
+
error: `Payload does not match ${this.provider} webhook format`
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
const event = this.parse(payload, options);
|
|
2590
|
+
if (!event.provider || !event.eventType) {
|
|
2591
|
+
return {
|
|
2592
|
+
valid: false,
|
|
2593
|
+
error: "Parsed event missing required fields"
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
return {
|
|
2597
|
+
valid: true,
|
|
2598
|
+
provider: this.provider,
|
|
2599
|
+
details: {
|
|
2600
|
+
eventType: event.eventType,
|
|
2601
|
+
success: event.success
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
return {
|
|
2606
|
+
valid: false,
|
|
2607
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
2608
|
+
details: { error }
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* Helper method to create error response
|
|
2614
|
+
*/
|
|
2615
|
+
createErrorEvent(payload, errorMessage) {
|
|
2616
|
+
return {
|
|
2617
|
+
success: false,
|
|
2618
|
+
provider: this.provider,
|
|
2619
|
+
eventType: "transcription.failed",
|
|
2620
|
+
data: {
|
|
2621
|
+
id: "",
|
|
2622
|
+
status: "error",
|
|
2623
|
+
error: errorMessage
|
|
2624
|
+
},
|
|
2625
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2626
|
+
raw: payload
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
|
|
2631
|
+
// src/webhooks/gladia-webhook.ts
|
|
2632
|
+
var GladiaWebhookHandler = class extends BaseWebhookHandler {
|
|
2633
|
+
constructor() {
|
|
2634
|
+
super(...arguments);
|
|
2635
|
+
this.provider = "gladia";
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* Check if payload matches Gladia webhook format
|
|
2639
|
+
*/
|
|
2640
|
+
matches(payload, _options) {
|
|
2641
|
+
if (!payload || typeof payload !== "object") {
|
|
2642
|
+
return false;
|
|
2643
|
+
}
|
|
2644
|
+
const obj = payload;
|
|
2645
|
+
if (!("event" in obj) || !("payload" in obj)) {
|
|
2646
|
+
return false;
|
|
2647
|
+
}
|
|
2648
|
+
if (typeof obj.event !== "string") {
|
|
2649
|
+
return false;
|
|
2650
|
+
}
|
|
2651
|
+
if (!obj.event.startsWith("transcription.")) {
|
|
2652
|
+
return false;
|
|
2653
|
+
}
|
|
2654
|
+
if (!obj.payload || typeof obj.payload !== "object") {
|
|
2655
|
+
return false;
|
|
2656
|
+
}
|
|
2657
|
+
const payloadObj = obj.payload;
|
|
2658
|
+
return typeof payloadObj.id === "string";
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Parse Gladia webhook payload to unified format
|
|
2662
|
+
*/
|
|
2663
|
+
parse(payload, _options) {
|
|
2664
|
+
if (!this.matches(payload)) {
|
|
2665
|
+
return this.createErrorEvent(payload, "Invalid Gladia webhook payload");
|
|
2666
|
+
}
|
|
2667
|
+
const webhookPayload = payload;
|
|
2668
|
+
const jobId = webhookPayload.payload.id;
|
|
2669
|
+
const event = webhookPayload.event;
|
|
2670
|
+
if (event === "transcription.created") {
|
|
2671
|
+
return {
|
|
2672
|
+
success: true,
|
|
2673
|
+
provider: this.provider,
|
|
2674
|
+
eventType: "transcription.created",
|
|
2675
|
+
data: {
|
|
2676
|
+
id: jobId,
|
|
2677
|
+
status: "queued"
|
|
2678
|
+
},
|
|
2679
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2680
|
+
raw: payload
|
|
2681
|
+
};
|
|
2682
|
+
}
|
|
2683
|
+
if (event === "transcription.success") {
|
|
2684
|
+
return {
|
|
2685
|
+
success: true,
|
|
2686
|
+
provider: this.provider,
|
|
2687
|
+
eventType: "transcription.completed",
|
|
2688
|
+
data: {
|
|
2689
|
+
id: jobId,
|
|
2690
|
+
status: "completed"
|
|
2691
|
+
// Note: Full transcript data needs to be fetched via API
|
|
2692
|
+
// using GladiaAdapter.getTranscript(jobId)
|
|
2693
|
+
},
|
|
2694
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2695
|
+
raw: payload
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
if (event === "transcription.error") {
|
|
2699
|
+
return {
|
|
2700
|
+
success: false,
|
|
2701
|
+
provider: this.provider,
|
|
2702
|
+
eventType: "transcription.failed",
|
|
2703
|
+
data: {
|
|
2704
|
+
id: jobId,
|
|
2705
|
+
status: "error",
|
|
2706
|
+
error: "Transcription failed"
|
|
2707
|
+
},
|
|
2708
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2709
|
+
raw: payload
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
return this.createErrorEvent(payload, `Unknown Gladia webhook event: ${event}`);
|
|
2713
|
+
}
|
|
2714
|
+
/**
|
|
2715
|
+
* Verify Gladia webhook signature
|
|
2716
|
+
*
|
|
2717
|
+
* Note: As of the current API version, Gladia does not provide
|
|
2718
|
+
* webhook signature verification. This method is a placeholder
|
|
2719
|
+
* for future implementation.
|
|
2720
|
+
*
|
|
2721
|
+
* @param payload - Webhook payload
|
|
2722
|
+
* @param options - Verification options
|
|
2723
|
+
* @returns Always returns true (no verification available)
|
|
2724
|
+
*/
|
|
2725
|
+
verify() {
|
|
2726
|
+
return true;
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
function createGladiaWebhookHandler() {
|
|
2730
|
+
return new GladiaWebhookHandler();
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// src/webhooks/assemblyai-webhook.ts
|
|
2734
|
+
var import_node_crypto = __toESM(require("crypto"));
|
|
2735
|
+
var AssemblyAIWebhookHandler = class extends BaseWebhookHandler {
|
|
2736
|
+
constructor() {
|
|
2737
|
+
super(...arguments);
|
|
2738
|
+
this.provider = "assemblyai";
|
|
2739
|
+
}
|
|
2740
|
+
/**
|
|
2741
|
+
* Check if payload matches AssemblyAI webhook format
|
|
2742
|
+
*/
|
|
2743
|
+
matches(payload, _options) {
|
|
2744
|
+
if (!payload || typeof payload !== "object") {
|
|
2745
|
+
return false;
|
|
2746
|
+
}
|
|
2747
|
+
const obj = payload;
|
|
2748
|
+
if (!("transcript_id" in obj) || !("status" in obj)) {
|
|
2749
|
+
return false;
|
|
2750
|
+
}
|
|
2751
|
+
if (typeof obj.transcript_id !== "string") {
|
|
2752
|
+
return false;
|
|
2753
|
+
}
|
|
2754
|
+
if (obj.status !== "completed" && obj.status !== "error") {
|
|
2755
|
+
return false;
|
|
2756
|
+
}
|
|
2757
|
+
return true;
|
|
2758
|
+
}
|
|
2759
|
+
/**
|
|
2760
|
+
* Parse AssemblyAI webhook payload to unified format
|
|
2761
|
+
*/
|
|
2762
|
+
parse(payload, _options) {
|
|
2763
|
+
if (!this.matches(payload)) {
|
|
2764
|
+
return this.createErrorEvent(payload, "Invalid AssemblyAI webhook payload");
|
|
2765
|
+
}
|
|
2766
|
+
const notification = payload;
|
|
2767
|
+
const transcriptId = notification.transcript_id;
|
|
2768
|
+
const status = notification.status;
|
|
2769
|
+
if (status === "completed") {
|
|
2770
|
+
return {
|
|
2771
|
+
success: true,
|
|
2772
|
+
provider: this.provider,
|
|
2773
|
+
eventType: "transcription.completed",
|
|
2774
|
+
data: {
|
|
2775
|
+
id: transcriptId,
|
|
2776
|
+
status: "completed"
|
|
2777
|
+
// Note: Full transcript data needs to be fetched via API
|
|
2778
|
+
// using AssemblyAIAdapter.getTranscript(transcriptId)
|
|
2779
|
+
},
|
|
2780
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2781
|
+
raw: payload
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
if (status === "error") {
|
|
2785
|
+
return {
|
|
2786
|
+
success: false,
|
|
2787
|
+
provider: this.provider,
|
|
2788
|
+
eventType: "transcription.failed",
|
|
2789
|
+
data: {
|
|
2790
|
+
id: transcriptId,
|
|
2791
|
+
status: "error",
|
|
2792
|
+
error: "Transcription failed"
|
|
2793
|
+
},
|
|
2794
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2795
|
+
raw: payload
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
return this.createErrorEvent(payload, `Unknown AssemblyAI status: ${status}`);
|
|
2799
|
+
}
|
|
2800
|
+
/**
|
|
2801
|
+
* Verify AssemblyAI webhook signature
|
|
2802
|
+
*
|
|
2803
|
+
* AssemblyAI uses HMAC-SHA256 for webhook signature verification.
|
|
2804
|
+
* The signature is sent in the X-AssemblyAI-Signature header.
|
|
2805
|
+
*
|
|
2806
|
+
* @param payload - Webhook payload
|
|
2807
|
+
* @param options - Verification options with signature and secret
|
|
2808
|
+
* @returns true if signature is valid
|
|
2809
|
+
*
|
|
2810
|
+
* @example
|
|
2811
|
+
* ```typescript
|
|
2812
|
+
* const isValid = handler.verify(req.body, {
|
|
2813
|
+
* signature: req.headers['x-assemblyai-signature'],
|
|
2814
|
+
* secret: process.env.ASSEMBLYAI_WEBHOOK_SECRET,
|
|
2815
|
+
* rawBody: req.rawBody // Raw request body as string or Buffer
|
|
2816
|
+
* });
|
|
2817
|
+
* ```
|
|
2818
|
+
*/
|
|
2819
|
+
verify(payload, options) {
|
|
2820
|
+
if (!options.signature || !options.secret) {
|
|
2821
|
+
return false;
|
|
2822
|
+
}
|
|
2823
|
+
try {
|
|
2824
|
+
const body = options.rawBody || (typeof payload === "string" ? payload : JSON.stringify(payload));
|
|
2825
|
+
const hmac = import_node_crypto.default.createHmac("sha256", options.secret);
|
|
2826
|
+
const bodyBuffer = typeof body === "string" ? Buffer.from(body) : body;
|
|
2827
|
+
hmac.update(bodyBuffer);
|
|
2828
|
+
const computedSignature = hmac.digest("hex");
|
|
2829
|
+
return import_node_crypto.default.timingSafeEqual(Buffer.from(options.signature), Buffer.from(computedSignature));
|
|
2830
|
+
} catch (error) {
|
|
2831
|
+
return false;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2835
|
+
function createAssemblyAIWebhookHandler() {
|
|
2836
|
+
return new AssemblyAIWebhookHandler();
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// src/webhooks/deepgram-webhook.ts
|
|
2840
|
+
var DeepgramWebhookHandler = class extends BaseWebhookHandler {
|
|
2841
|
+
constructor() {
|
|
2842
|
+
super(...arguments);
|
|
2843
|
+
this.provider = "deepgram";
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Check if payload matches Deepgram webhook format
|
|
2847
|
+
*/
|
|
2848
|
+
matches(payload, _options) {
|
|
2849
|
+
if (!payload || typeof payload !== "object") {
|
|
2850
|
+
return false;
|
|
2851
|
+
}
|
|
2852
|
+
const obj = payload;
|
|
2853
|
+
if (!("metadata" in obj) || !("results" in obj)) {
|
|
2854
|
+
return false;
|
|
2855
|
+
}
|
|
2856
|
+
if (!obj.metadata || typeof obj.metadata !== "object") {
|
|
2857
|
+
return false;
|
|
2858
|
+
}
|
|
2859
|
+
const metadata = obj.metadata;
|
|
2860
|
+
if (!("request_id" in metadata)) {
|
|
2861
|
+
return false;
|
|
2862
|
+
}
|
|
2863
|
+
if (!obj.results || typeof obj.results !== "object") {
|
|
2864
|
+
return false;
|
|
2865
|
+
}
|
|
2866
|
+
const results = obj.results;
|
|
2867
|
+
return "channels" in results;
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Parse Deepgram webhook payload to unified format
|
|
2871
|
+
*/
|
|
2872
|
+
parse(payload, _options) {
|
|
2873
|
+
if (!this.matches(payload)) {
|
|
2874
|
+
return this.createErrorEvent(payload, "Invalid Deepgram webhook payload");
|
|
2875
|
+
}
|
|
2876
|
+
const response = payload;
|
|
2877
|
+
try {
|
|
2878
|
+
const requestId = response.metadata.request_id;
|
|
2879
|
+
const duration = response.metadata.duration;
|
|
2880
|
+
const channels = response.results.channels || [];
|
|
2881
|
+
if (channels.length === 0) {
|
|
2882
|
+
return {
|
|
2883
|
+
success: false,
|
|
2884
|
+
provider: this.provider,
|
|
2885
|
+
eventType: "transcription.failed",
|
|
2886
|
+
data: {
|
|
2887
|
+
id: requestId || "",
|
|
2888
|
+
status: "error",
|
|
2889
|
+
error: "No channels in response"
|
|
2890
|
+
},
|
|
2891
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2892
|
+
raw: payload
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
const channel = channels[0];
|
|
2896
|
+
const alternatives = channel.alternatives || [];
|
|
2897
|
+
if (alternatives.length === 0) {
|
|
2898
|
+
return {
|
|
2899
|
+
success: false,
|
|
2900
|
+
provider: this.provider,
|
|
2901
|
+
eventType: "transcription.failed",
|
|
2902
|
+
data: {
|
|
2903
|
+
id: requestId || "",
|
|
2904
|
+
status: "error",
|
|
2905
|
+
error: "No alternatives in response"
|
|
2906
|
+
},
|
|
2907
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2908
|
+
raw: payload
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
const alternative = alternatives[0];
|
|
2912
|
+
const transcript = alternative.transcript;
|
|
2913
|
+
if (!transcript) {
|
|
2914
|
+
return {
|
|
2915
|
+
success: false,
|
|
2916
|
+
provider: this.provider,
|
|
2917
|
+
eventType: "transcription.failed",
|
|
2918
|
+
data: {
|
|
2919
|
+
id: requestId || "",
|
|
2920
|
+
status: "error",
|
|
2921
|
+
error: "Empty transcript"
|
|
2922
|
+
},
|
|
2923
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2924
|
+
raw: payload
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
const words = alternative.words && alternative.words.length > 0 ? alternative.words.map((word) => ({
|
|
2928
|
+
text: word.word || "",
|
|
2929
|
+
start: word.start || 0,
|
|
2930
|
+
end: word.end || 0,
|
|
2931
|
+
confidence: word.confidence
|
|
2932
|
+
})) : void 0;
|
|
2933
|
+
const speakers = response.results.utterances && response.results.utterances.length > 0 ? response.results.utterances.map((utterance) => ({
|
|
2934
|
+
id: utterance.speaker?.toString() || "unknown",
|
|
2935
|
+
speaker: utterance.speaker?.toString() || "unknown",
|
|
2936
|
+
text: utterance.transcript || "",
|
|
2937
|
+
confidence: utterance.confidence
|
|
2938
|
+
})) : void 0;
|
|
2939
|
+
const utterances = response.results.utterances && response.results.utterances.length > 0 ? response.results.utterances.map((utterance) => ({
|
|
2940
|
+
text: utterance.transcript || "",
|
|
2941
|
+
start: utterance.start || 0,
|
|
2942
|
+
end: utterance.end || 0,
|
|
2943
|
+
speaker: utterance.speaker?.toString(),
|
|
2944
|
+
confidence: utterance.confidence,
|
|
2945
|
+
words: utterance.words && utterance.words.length > 0 ? utterance.words.map((word) => ({
|
|
2946
|
+
text: word.word || "",
|
|
2947
|
+
start: word.start || 0,
|
|
2948
|
+
end: word.end || 0,
|
|
2949
|
+
confidence: word.confidence
|
|
2950
|
+
})) : void 0
|
|
2951
|
+
})) : void 0;
|
|
2952
|
+
const summary = alternative.summaries?.[0]?.summary;
|
|
2953
|
+
return {
|
|
2954
|
+
success: true,
|
|
2955
|
+
provider: this.provider,
|
|
2956
|
+
eventType: "transcription.completed",
|
|
2957
|
+
data: {
|
|
2958
|
+
id: requestId || "",
|
|
2959
|
+
status: "completed",
|
|
2960
|
+
text: transcript,
|
|
2961
|
+
confidence: alternative.confidence,
|
|
2962
|
+
duration,
|
|
2963
|
+
language: response.metadata.models?.[0] || void 0,
|
|
2964
|
+
speakers: speakers && speakers.length > 0 ? speakers : void 0,
|
|
2965
|
+
words: words && words.length > 0 ? words : void 0,
|
|
2966
|
+
utterances: utterances && utterances.length > 0 ? utterances : void 0,
|
|
2967
|
+
summary,
|
|
2968
|
+
metadata: {
|
|
2969
|
+
channels: response.metadata.channels,
|
|
2970
|
+
created: response.metadata.created,
|
|
2971
|
+
models: response.metadata.models
|
|
2972
|
+
}
|
|
2973
|
+
},
|
|
2974
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2975
|
+
raw: payload
|
|
2976
|
+
};
|
|
2977
|
+
} catch (error) {
|
|
2978
|
+
return this.createErrorEvent(
|
|
2979
|
+
payload,
|
|
2980
|
+
`Failed to parse Deepgram webhook: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
/**
|
|
2985
|
+
* Verify Deepgram webhook signature
|
|
2986
|
+
*
|
|
2987
|
+
* Note: Deepgram does not currently support webhook signature verification.
|
|
2988
|
+
* For security, use HTTPS and validate the request source (IP allowlist, etc.).
|
|
2989
|
+
*
|
|
2990
|
+
* @returns Always returns true (no verification available)
|
|
2991
|
+
*/
|
|
2992
|
+
verify() {
|
|
2993
|
+
return true;
|
|
2994
|
+
}
|
|
2995
|
+
};
|
|
2996
|
+
function createDeepgramWebhookHandler() {
|
|
2997
|
+
return new DeepgramWebhookHandler();
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
// src/webhooks/azure-webhook.ts
|
|
3001
|
+
var import_node_crypto2 = __toESM(require("crypto"));
|
|
3002
|
+
var AzureWebhookHandler = class extends BaseWebhookHandler {
|
|
3003
|
+
constructor() {
|
|
3004
|
+
super(...arguments);
|
|
3005
|
+
this.provider = "azure-stt";
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Check if payload matches Azure webhook format
|
|
3009
|
+
*/
|
|
3010
|
+
matches(payload, _options) {
|
|
3011
|
+
if (!payload || typeof payload !== "object") {
|
|
3012
|
+
return false;
|
|
3013
|
+
}
|
|
3014
|
+
const obj = payload;
|
|
3015
|
+
if (!("action" in obj) || !("timestamp" in obj)) {
|
|
3016
|
+
return false;
|
|
3017
|
+
}
|
|
3018
|
+
if (typeof obj.action !== "string") {
|
|
3019
|
+
return false;
|
|
3020
|
+
}
|
|
3021
|
+
if (!obj.action.startsWith("Transcription")) {
|
|
3022
|
+
return false;
|
|
3023
|
+
}
|
|
3024
|
+
return true;
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
3027
|
+
* Parse Azure webhook payload to unified format
|
|
3028
|
+
*/
|
|
3029
|
+
parse(payload, _options) {
|
|
3030
|
+
if (!this.matches(payload)) {
|
|
3031
|
+
return this.createErrorEvent(payload, "Invalid Azure webhook payload");
|
|
3032
|
+
}
|
|
3033
|
+
const webhookPayload = payload;
|
|
3034
|
+
const action = webhookPayload.action;
|
|
3035
|
+
const timestamp = webhookPayload.timestamp;
|
|
3036
|
+
let transcriptionId = "";
|
|
3037
|
+
if (webhookPayload.self) {
|
|
3038
|
+
const match = webhookPayload.self.match(/\/transcriptions\/([^/?]+)/);
|
|
3039
|
+
if (match) {
|
|
3040
|
+
transcriptionId = match[1];
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
if (action === "TranscriptionCreated") {
|
|
3044
|
+
return {
|
|
3045
|
+
success: true,
|
|
3046
|
+
provider: this.provider,
|
|
3047
|
+
eventType: "transcription.created",
|
|
3048
|
+
data: {
|
|
3049
|
+
id: transcriptionId,
|
|
3050
|
+
status: "queued",
|
|
3051
|
+
createdAt: timestamp
|
|
3052
|
+
},
|
|
3053
|
+
timestamp,
|
|
3054
|
+
raw: payload
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
if (action === "TranscriptionRunning") {
|
|
3058
|
+
return {
|
|
3059
|
+
success: true,
|
|
3060
|
+
provider: this.provider,
|
|
3061
|
+
eventType: "transcription.processing",
|
|
3062
|
+
data: {
|
|
3063
|
+
id: transcriptionId,
|
|
3064
|
+
status: "processing"
|
|
3065
|
+
},
|
|
3066
|
+
timestamp,
|
|
3067
|
+
raw: payload
|
|
3068
|
+
};
|
|
3069
|
+
}
|
|
3070
|
+
if (action === "TranscriptionSucceeded") {
|
|
3071
|
+
return {
|
|
3072
|
+
success: true,
|
|
3073
|
+
provider: this.provider,
|
|
3074
|
+
eventType: "transcription.completed",
|
|
3075
|
+
data: {
|
|
3076
|
+
id: transcriptionId,
|
|
3077
|
+
status: "completed",
|
|
3078
|
+
completedAt: timestamp
|
|
3079
|
+
// Note: Full transcript data needs to be fetched via API
|
|
3080
|
+
// using AzureAdapter.getTranscript(transcriptionId)
|
|
3081
|
+
},
|
|
3082
|
+
timestamp,
|
|
3083
|
+
raw: payload
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
if (action === "TranscriptionFailed") {
|
|
3087
|
+
return {
|
|
3088
|
+
success: false,
|
|
3089
|
+
provider: this.provider,
|
|
3090
|
+
eventType: "transcription.failed",
|
|
3091
|
+
data: {
|
|
3092
|
+
id: transcriptionId,
|
|
3093
|
+
status: "error",
|
|
3094
|
+
error: webhookPayload.error?.message || "Transcription failed",
|
|
3095
|
+
metadata: {
|
|
3096
|
+
errorCode: webhookPayload.error?.code
|
|
3097
|
+
}
|
|
3098
|
+
},
|
|
3099
|
+
timestamp,
|
|
3100
|
+
raw: payload
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
return this.createErrorEvent(payload, `Unknown Azure webhook action: ${action}`);
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
* Verify Azure webhook signature
|
|
3107
|
+
*
|
|
3108
|
+
* Azure can optionally sign webhooks using HMAC-SHA256.
|
|
3109
|
+
* The signature is sent in the X-Azure-Signature header.
|
|
3110
|
+
*
|
|
3111
|
+
* Note: Signature verification is optional in Azure and must be
|
|
3112
|
+
* configured when creating the webhook.
|
|
3113
|
+
*
|
|
3114
|
+
* @param payload - Webhook payload
|
|
3115
|
+
* @param options - Verification options with signature and secret
|
|
3116
|
+
* @returns true if signature is valid or no signature provided
|
|
3117
|
+
*
|
|
3118
|
+
* @example
|
|
3119
|
+
* ```typescript
|
|
3120
|
+
* const isValid = handler.verify(req.body, {
|
|
3121
|
+
* signature: req.headers['x-azure-signature'],
|
|
3122
|
+
* secret: process.env.AZURE_WEBHOOK_SECRET,
|
|
3123
|
+
* rawBody: req.rawBody
|
|
3124
|
+
* });
|
|
3125
|
+
* ```
|
|
3126
|
+
*/
|
|
3127
|
+
verify(payload, options) {
|
|
3128
|
+
if (!options.signature) {
|
|
3129
|
+
return true;
|
|
3130
|
+
}
|
|
3131
|
+
if (!options.secret) {
|
|
3132
|
+
return false;
|
|
3133
|
+
}
|
|
3134
|
+
try {
|
|
3135
|
+
const body = options.rawBody || (typeof payload === "string" ? payload : JSON.stringify(payload));
|
|
3136
|
+
const hmac = import_node_crypto2.default.createHmac("sha256", options.secret);
|
|
3137
|
+
const bodyBuffer = typeof body === "string" ? Buffer.from(body) : body;
|
|
3138
|
+
hmac.update(bodyBuffer);
|
|
3139
|
+
const computedSignature = hmac.digest("hex");
|
|
3140
|
+
return import_node_crypto2.default.timingSafeEqual(Buffer.from(options.signature), Buffer.from(computedSignature));
|
|
3141
|
+
} catch (error) {
|
|
3142
|
+
return false;
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
};
|
|
3146
|
+
function createAzureWebhookHandler() {
|
|
3147
|
+
return new AzureWebhookHandler();
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
// src/webhooks/speechmatics-webhook.ts
|
|
3151
|
+
var SpeechmaticsWebhookHandler = class extends BaseWebhookHandler {
|
|
3152
|
+
constructor() {
|
|
3153
|
+
super(...arguments);
|
|
3154
|
+
this.provider = "speechmatics";
|
|
3155
|
+
}
|
|
3156
|
+
/**
|
|
3157
|
+
* Check if payload matches Speechmatics webhook format
|
|
3158
|
+
*/
|
|
3159
|
+
matches(payload, options) {
|
|
3160
|
+
if (options?.userAgent) {
|
|
3161
|
+
if (!options.userAgent.includes("Speechmatics-API")) {
|
|
3162
|
+
return false;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
if (options?.queryParams) {
|
|
3166
|
+
const { id, status } = options.queryParams;
|
|
3167
|
+
if (!id || !status) {
|
|
3168
|
+
return false;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
if (payload && typeof payload === "object") {
|
|
3172
|
+
const obj = payload;
|
|
3173
|
+
if ("format" in obj && "job" in obj && "metadata" in obj) {
|
|
3174
|
+
return true;
|
|
3175
|
+
}
|
|
3176
|
+
if ("job" in obj || "id" in obj) {
|
|
3177
|
+
return true;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
return !!options?.queryParams?.id && !!options?.queryParams?.status;
|
|
3181
|
+
}
|
|
3182
|
+
/**
|
|
3183
|
+
* Validate webhook request
|
|
3184
|
+
*/
|
|
3185
|
+
validate(payload, options) {
|
|
3186
|
+
if (!options?.queryParams?.id) {
|
|
3187
|
+
return {
|
|
3188
|
+
valid: false,
|
|
3189
|
+
error: "Missing required query parameter: id"
|
|
3190
|
+
};
|
|
3191
|
+
}
|
|
3192
|
+
if (!options?.queryParams?.status) {
|
|
3193
|
+
return {
|
|
3194
|
+
valid: false,
|
|
3195
|
+
error: "Missing required query parameter: status"
|
|
3196
|
+
};
|
|
3197
|
+
}
|
|
3198
|
+
const validStatuses = ["success", "error", "fetch_error", "trim_error"];
|
|
3199
|
+
if (!validStatuses.includes(options.queryParams.status)) {
|
|
3200
|
+
return {
|
|
3201
|
+
valid: false,
|
|
3202
|
+
error: `Invalid status value: ${options.queryParams.status}`
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
if (options?.userAgent && !options.userAgent.includes("Speechmatics-API")) {
|
|
3206
|
+
return {
|
|
3207
|
+
valid: false,
|
|
3208
|
+
error: "Invalid user agent (expected Speechmatics-API/2.0)"
|
|
3209
|
+
};
|
|
3210
|
+
}
|
|
3211
|
+
return { valid: true };
|
|
3212
|
+
}
|
|
3213
|
+
/**
|
|
3214
|
+
* Parse webhook payload into unified event format
|
|
3215
|
+
*/
|
|
3216
|
+
parse(payload, options) {
|
|
3217
|
+
const queryParams = options?.queryParams || {};
|
|
3218
|
+
const jobId = queryParams.id;
|
|
3219
|
+
const status = queryParams.status;
|
|
3220
|
+
let eventType;
|
|
3221
|
+
if (status === "success") {
|
|
3222
|
+
eventType = "transcription.completed";
|
|
3223
|
+
} else if (status === "error" || status === "fetch_error" || status === "trim_error") {
|
|
3224
|
+
eventType = "transcription.failed";
|
|
3225
|
+
} else {
|
|
3226
|
+
eventType = "transcription.created";
|
|
3227
|
+
}
|
|
3228
|
+
if (status === "success" && payload && typeof payload === "object") {
|
|
3229
|
+
const transcript = payload;
|
|
3230
|
+
if (transcript.results && transcript.job) {
|
|
3231
|
+
const text = transcript.results.filter((r) => r.type === "word").map((r) => r.alternatives[0]?.content || "").join(" ");
|
|
3232
|
+
const speakerSet = /* @__PURE__ */ new Set();
|
|
3233
|
+
transcript.results.forEach((r) => {
|
|
3234
|
+
const speaker = r.alternatives[0]?.speaker;
|
|
3235
|
+
if (speaker) speakerSet.add(speaker);
|
|
3236
|
+
});
|
|
3237
|
+
const speakers = speakerSet.size > 0 ? Array.from(speakerSet).map((id) => ({
|
|
3238
|
+
id,
|
|
3239
|
+
label: `Speaker ${id}`
|
|
3240
|
+
})) : void 0;
|
|
3241
|
+
return {
|
|
3242
|
+
success: true,
|
|
3243
|
+
provider: this.provider,
|
|
3244
|
+
eventType,
|
|
3245
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3246
|
+
data: {
|
|
3247
|
+
id: jobId,
|
|
3248
|
+
text,
|
|
3249
|
+
status: "completed",
|
|
3250
|
+
language: transcript.metadata.transcription_config.language,
|
|
3251
|
+
duration: transcript.job.duration,
|
|
3252
|
+
speakers,
|
|
3253
|
+
createdAt: transcript.job.created_at
|
|
3254
|
+
},
|
|
3255
|
+
raw: payload
|
|
3256
|
+
};
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
return {
|
|
3260
|
+
success: status === "success",
|
|
3261
|
+
provider: this.provider,
|
|
3262
|
+
eventType,
|
|
3263
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3264
|
+
data: {
|
|
3265
|
+
id: jobId,
|
|
3266
|
+
text: "",
|
|
3267
|
+
status: status === "success" ? "completed" : "error"
|
|
3268
|
+
},
|
|
3269
|
+
raw: payload
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
};
|
|
3273
|
+
|
|
3274
|
+
// src/webhooks/webhook-router.ts
|
|
3275
|
+
var WebhookRouter = class {
|
|
3276
|
+
constructor() {
|
|
3277
|
+
this.handlers = /* @__PURE__ */ new Map([
|
|
3278
|
+
["gladia", new GladiaWebhookHandler()],
|
|
3279
|
+
["assemblyai", new AssemblyAIWebhookHandler()],
|
|
3280
|
+
["deepgram", new DeepgramWebhookHandler()],
|
|
3281
|
+
["azure-stt", new AzureWebhookHandler()],
|
|
3282
|
+
["speechmatics", new SpeechmaticsWebhookHandler()]
|
|
3283
|
+
]);
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
3286
|
+
* Route webhook payload to the correct handler
|
|
3287
|
+
*
|
|
3288
|
+
* @param payload - Raw webhook payload
|
|
3289
|
+
* @param options - Routing options (provider, verification, etc.)
|
|
3290
|
+
* @returns Routing result with parsed event
|
|
3291
|
+
*/
|
|
3292
|
+
route(payload, options) {
|
|
3293
|
+
if (options?.provider) {
|
|
3294
|
+
return this.routeToProvider(payload, options.provider, options);
|
|
3295
|
+
}
|
|
3296
|
+
const detectedProvider = this.detectProvider(payload, {
|
|
3297
|
+
queryParams: options?.queryParams,
|
|
3298
|
+
userAgent: options?.userAgent
|
|
3299
|
+
});
|
|
3300
|
+
if (!detectedProvider) {
|
|
3301
|
+
return {
|
|
3302
|
+
success: false,
|
|
3303
|
+
error: "Could not detect webhook provider from payload structure"
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
return this.routeToProvider(payload, detectedProvider, options);
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Detect provider from webhook payload structure
|
|
3310
|
+
*
|
|
3311
|
+
* @param payload - Raw webhook payload
|
|
3312
|
+
* @param options - Detection options (query params, user agent, etc.)
|
|
3313
|
+
* @returns Detected provider or undefined
|
|
3314
|
+
*/
|
|
3315
|
+
detectProvider(payload, options) {
|
|
3316
|
+
for (const [provider, handler] of this.handlers) {
|
|
3317
|
+
if (handler.matches(payload, options)) {
|
|
3318
|
+
return provider;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
return void 0;
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Validate webhook payload
|
|
3325
|
+
*
|
|
3326
|
+
* @param payload - Raw webhook payload
|
|
3327
|
+
* @param options - Routing options
|
|
3328
|
+
* @returns Validation result
|
|
3329
|
+
*/
|
|
3330
|
+
validate(payload, options) {
|
|
3331
|
+
if (options?.provider) {
|
|
3332
|
+
const handler2 = this.handlers.get(options.provider);
|
|
3333
|
+
if (!handler2) {
|
|
3334
|
+
return {
|
|
3335
|
+
valid: false,
|
|
3336
|
+
error: `Unknown provider: ${options.provider}`
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
return handler2.validate(payload, {
|
|
3340
|
+
queryParams: options.queryParams,
|
|
3341
|
+
userAgent: options.userAgent
|
|
3342
|
+
});
|
|
3343
|
+
}
|
|
3344
|
+
const detectedProvider = this.detectProvider(payload, {
|
|
3345
|
+
queryParams: options?.queryParams,
|
|
3346
|
+
userAgent: options?.userAgent
|
|
3347
|
+
});
|
|
3348
|
+
if (!detectedProvider) {
|
|
3349
|
+
return {
|
|
3350
|
+
valid: false,
|
|
3351
|
+
error: "Could not detect webhook provider from payload structure"
|
|
3352
|
+
};
|
|
3353
|
+
}
|
|
3354
|
+
const handler = this.handlers.get(detectedProvider);
|
|
3355
|
+
if (!handler) {
|
|
3356
|
+
return {
|
|
3357
|
+
valid: false,
|
|
3358
|
+
error: `Handler not found for provider: ${detectedProvider}`
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3361
|
+
return handler.validate(payload, {
|
|
3362
|
+
queryParams: options?.queryParams,
|
|
3363
|
+
userAgent: options?.userAgent
|
|
3364
|
+
});
|
|
3365
|
+
}
|
|
3366
|
+
/**
|
|
3367
|
+
* Verify webhook signature
|
|
3368
|
+
*
|
|
3369
|
+
* @param payload - Raw webhook payload
|
|
3370
|
+
* @param provider - Provider name
|
|
3371
|
+
* @param options - Verification options
|
|
3372
|
+
* @returns true if signature is valid
|
|
3373
|
+
*/
|
|
3374
|
+
verify(payload, provider, options) {
|
|
3375
|
+
const handler = this.handlers.get(provider);
|
|
3376
|
+
if (!handler || !handler.verify) {
|
|
3377
|
+
return true;
|
|
3378
|
+
}
|
|
3379
|
+
return handler.verify(payload, options);
|
|
3380
|
+
}
|
|
3381
|
+
/**
|
|
3382
|
+
* Route to a specific provider handler
|
|
3383
|
+
*/
|
|
3384
|
+
routeToProvider(payload, provider, options) {
|
|
3385
|
+
const handler = this.handlers.get(provider);
|
|
3386
|
+
if (!handler) {
|
|
3387
|
+
return {
|
|
3388
|
+
success: false,
|
|
3389
|
+
error: `Handler not found for provider: ${provider}`
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
let verified = true;
|
|
3393
|
+
if (options?.verifySignature !== false && options?.verification && handler.verify) {
|
|
3394
|
+
verified = handler.verify(payload, options.verification);
|
|
3395
|
+
if (!verified) {
|
|
3396
|
+
return {
|
|
3397
|
+
success: false,
|
|
3398
|
+
provider,
|
|
3399
|
+
error: "Webhook signature verification failed",
|
|
3400
|
+
verified: false
|
|
3401
|
+
};
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
const validation = handler.validate(payload, {
|
|
3405
|
+
queryParams: options?.queryParams,
|
|
3406
|
+
userAgent: options?.userAgent
|
|
3407
|
+
});
|
|
3408
|
+
if (!validation.valid) {
|
|
3409
|
+
return {
|
|
3410
|
+
success: false,
|
|
3411
|
+
provider,
|
|
3412
|
+
error: validation.error,
|
|
3413
|
+
verified
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
try {
|
|
3417
|
+
const event = handler.parse(payload, {
|
|
3418
|
+
queryParams: options?.queryParams
|
|
3419
|
+
});
|
|
3420
|
+
return {
|
|
3421
|
+
success: true,
|
|
3422
|
+
provider,
|
|
3423
|
+
event,
|
|
3424
|
+
verified
|
|
3425
|
+
};
|
|
3426
|
+
} catch (error) {
|
|
3427
|
+
return {
|
|
3428
|
+
success: false,
|
|
3429
|
+
provider,
|
|
3430
|
+
error: `Failed to parse webhook: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
3431
|
+
verified
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
/**
|
|
3436
|
+
* Get handler for a specific provider
|
|
3437
|
+
*
|
|
3438
|
+
* @param provider - Provider name
|
|
3439
|
+
* @returns Handler instance or undefined
|
|
3440
|
+
*/
|
|
3441
|
+
getHandler(provider) {
|
|
3442
|
+
return this.handlers.get(provider);
|
|
3443
|
+
}
|
|
3444
|
+
/**
|
|
3445
|
+
* Get all registered providers
|
|
3446
|
+
*
|
|
3447
|
+
* @returns Array of provider names
|
|
3448
|
+
*/
|
|
3449
|
+
getProviders() {
|
|
3450
|
+
return Array.from(this.handlers.keys());
|
|
3451
|
+
}
|
|
3452
|
+
};
|
|
3453
|
+
function createWebhookRouter() {
|
|
3454
|
+
return new WebhookRouter();
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3457
|
+
// src/generated/gladia/schema/index.ts
|
|
3458
|
+
var schema_exports = {};
|
|
3459
|
+
__export(schema_exports, {
|
|
3460
|
+
AudioChunkAckMessageType: () => AudioChunkAckMessageType,
|
|
3461
|
+
AudioChunkActionType: () => AudioChunkActionType,
|
|
3462
|
+
AudioToTextControllerAudioTranscriptionBodyLanguage: () => AudioToTextControllerAudioTranscriptionBodyLanguage,
|
|
3463
|
+
AudioToTextControllerAudioTranscriptionBodyLanguageBehaviour: () => AudioToTextControllerAudioTranscriptionBodyLanguageBehaviour,
|
|
3464
|
+
AudioToTextControllerAudioTranscriptionBodyOutputFormat: () => AudioToTextControllerAudioTranscriptionBodyOutputFormat,
|
|
3465
|
+
AudioToTextControllerAudioTranscriptionBodyTargetTranslationLanguage: () => AudioToTextControllerAudioTranscriptionBodyTargetTranslationLanguage,
|
|
3466
|
+
CallbackLiveAudioChunkAckMessageEvent: () => CallbackLiveAudioChunkAckMessageEvent,
|
|
3467
|
+
CallbackLiveEndRecordingMessageEvent: () => CallbackLiveEndRecordingMessageEvent,
|
|
3468
|
+
CallbackLiveEndSessionMessageEvent: () => CallbackLiveEndSessionMessageEvent,
|
|
3469
|
+
CallbackLiveNamedEntityRecognitionMessageEvent: () => CallbackLiveNamedEntityRecognitionMessageEvent,
|
|
3470
|
+
CallbackLivePostChapterizationMessageEvent: () => CallbackLivePostChapterizationMessageEvent,
|
|
3471
|
+
CallbackLivePostFinalTranscriptMessageEvent: () => CallbackLivePostFinalTranscriptMessageEvent,
|
|
3472
|
+
CallbackLivePostSummarizationMessageEvent: () => CallbackLivePostSummarizationMessageEvent,
|
|
3473
|
+
CallbackLivePostTranscriptMessageEvent: () => CallbackLivePostTranscriptMessageEvent,
|
|
3474
|
+
CallbackLiveSentimentAnalysisMessageEvent: () => CallbackLiveSentimentAnalysisMessageEvent,
|
|
3475
|
+
CallbackLiveSpeechEndMessageEvent: () => CallbackLiveSpeechEndMessageEvent,
|
|
3476
|
+
CallbackLiveSpeechStartMessageEvent: () => CallbackLiveSpeechStartMessageEvent,
|
|
3477
|
+
CallbackLiveStartRecordingMessageEvent: () => CallbackLiveStartRecordingMessageEvent,
|
|
3478
|
+
CallbackLiveStartSessionMessageEvent: () => CallbackLiveStartSessionMessageEvent,
|
|
3479
|
+
CallbackLiveStopRecordingAckMessageEvent: () => CallbackLiveStopRecordingAckMessageEvent,
|
|
3480
|
+
CallbackLiveTranscriptMessageEvent: () => CallbackLiveTranscriptMessageEvent,
|
|
3481
|
+
CallbackLiveTranslationMessageEvent: () => CallbackLiveTranslationMessageEvent,
|
|
3482
|
+
CallbackMethodEnum: () => CallbackMethodEnum,
|
|
3483
|
+
CallbackTranscriptionErrorPayloadEvent: () => CallbackTranscriptionErrorPayloadEvent,
|
|
3484
|
+
CallbackTranscriptionSuccessPayloadEvent: () => CallbackTranscriptionSuccessPayloadEvent,
|
|
3485
|
+
EndRecordingMessageType: () => EndRecordingMessageType,
|
|
3486
|
+
EndSessionMessageType: () => EndSessionMessageType,
|
|
3487
|
+
HistoryControllerGetListV1KindItem: () => HistoryControllerGetListV1KindItem,
|
|
3488
|
+
HistoryControllerGetListV1StatusItem: () => HistoryControllerGetListV1StatusItem,
|
|
3489
|
+
NamedEntityRecognitionMessageType: () => NamedEntityRecognitionMessageType,
|
|
3490
|
+
PostChapterizationMessageType: () => PostChapterizationMessageType,
|
|
3491
|
+
PostFinalTranscriptMessageType: () => PostFinalTranscriptMessageType,
|
|
3492
|
+
PostSummarizationMessageType: () => PostSummarizationMessageType,
|
|
3493
|
+
PostTranscriptMessageType: () => PostTranscriptMessageType,
|
|
3494
|
+
PreRecordedControllerGetPreRecordedJobsV2StatusItem: () => PreRecordedControllerGetPreRecordedJobsV2StatusItem,
|
|
3495
|
+
PreRecordedResponseKind: () => PreRecordedResponseKind,
|
|
3496
|
+
PreRecordedResponseStatus: () => PreRecordedResponseStatus,
|
|
3497
|
+
SentimentAnalysisMessageType: () => SentimentAnalysisMessageType,
|
|
3498
|
+
SpeechEndMessageType: () => SpeechEndMessageType,
|
|
3499
|
+
SpeechStartMessageType: () => SpeechStartMessageType,
|
|
3500
|
+
StartRecordingMessageType: () => StartRecordingMessageType,
|
|
3501
|
+
StartSessionMessageType: () => StartSessionMessageType,
|
|
3502
|
+
StopRecordingAckMessageType: () => StopRecordingAckMessageType,
|
|
3503
|
+
StopRecordingActionType: () => StopRecordingActionType,
|
|
3504
|
+
StreamingControllerGetStreamingJobsV2StatusItem: () => StreamingControllerGetStreamingJobsV2StatusItem,
|
|
3505
|
+
StreamingResponseKind: () => StreamingResponseKind,
|
|
3506
|
+
StreamingResponseStatus: () => StreamingResponseStatus,
|
|
3507
|
+
StreamingSupportedBitDepthEnum: () => StreamingSupportedBitDepthEnum,
|
|
3508
|
+
StreamingSupportedEncodingEnum: () => StreamingSupportedEncodingEnum,
|
|
3509
|
+
StreamingSupportedModels: () => StreamingSupportedModels,
|
|
3510
|
+
StreamingSupportedRegions: () => StreamingSupportedRegions,
|
|
3511
|
+
StreamingSupportedSampleRateEnum: () => StreamingSupportedSampleRateEnum,
|
|
3512
|
+
SubtitlesFormatEnum: () => SubtitlesFormatEnum,
|
|
3513
|
+
SubtitlesStyleEnum: () => SubtitlesStyleEnum,
|
|
3514
|
+
SummaryTypesEnum: () => SummaryTypesEnum,
|
|
3515
|
+
TranscriptMessageType: () => TranscriptMessageType,
|
|
3516
|
+
TranscriptionControllerListV2KindItem: () => TranscriptionControllerListV2KindItem,
|
|
3517
|
+
TranscriptionControllerListV2StatusItem: () => TranscriptionControllerListV2StatusItem,
|
|
3518
|
+
TranscriptionLanguageCodeEnum: () => TranscriptionLanguageCodeEnum,
|
|
3519
|
+
TranslationLanguageCodeEnum: () => TranslationLanguageCodeEnum,
|
|
3520
|
+
TranslationMessageType: () => TranslationMessageType,
|
|
3521
|
+
TranslationModelEnum: () => TranslationModelEnum,
|
|
3522
|
+
VideoToTextControllerVideoTranscriptionBodyLanguage: () => VideoToTextControllerVideoTranscriptionBodyLanguage,
|
|
3523
|
+
VideoToTextControllerVideoTranscriptionBodyLanguageBehaviour: () => VideoToTextControllerVideoTranscriptionBodyLanguageBehaviour,
|
|
3524
|
+
VideoToTextControllerVideoTranscriptionBodyOutputFormat: () => VideoToTextControllerVideoTranscriptionBodyOutputFormat,
|
|
3525
|
+
VideoToTextControllerVideoTranscriptionBodyTargetTranslationLanguage: () => VideoToTextControllerVideoTranscriptionBodyTargetTranslationLanguage,
|
|
3526
|
+
WebhookLiveEndRecordingPayloadEvent: () => WebhookLiveEndRecordingPayloadEvent,
|
|
3527
|
+
WebhookLiveEndSessionPayloadEvent: () => WebhookLiveEndSessionPayloadEvent,
|
|
3528
|
+
WebhookLiveStartRecordingPayloadEvent: () => WebhookLiveStartRecordingPayloadEvent,
|
|
3529
|
+
WebhookLiveStartSessionPayloadEvent: () => WebhookLiveStartSessionPayloadEvent,
|
|
3530
|
+
WebhookTranscriptionCreatedPayloadEvent: () => WebhookTranscriptionCreatedPayloadEvent,
|
|
3531
|
+
WebhookTranscriptionErrorPayloadEvent: () => WebhookTranscriptionErrorPayloadEvent,
|
|
3532
|
+
WebhookTranscriptionSuccessPayloadEvent: () => WebhookTranscriptionSuccessPayloadEvent
|
|
3533
|
+
});
|
|
3534
|
+
|
|
3535
|
+
// src/generated/gladia/schema/audioChunkAckMessageType.ts
|
|
3536
|
+
var AudioChunkAckMessageType = {
|
|
3537
|
+
audio_chunk: "audio_chunk"
|
|
3538
|
+
};
|
|
3539
|
+
|
|
3540
|
+
// src/generated/gladia/schema/audioChunkActionType.ts
|
|
3541
|
+
var AudioChunkActionType = {
|
|
3542
|
+
audio_chunk: "audio_chunk"
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
// src/generated/gladia/schema/audioToTextControllerAudioTranscriptionBodyLanguage.ts
|
|
3546
|
+
var AudioToTextControllerAudioTranscriptionBodyLanguage = {
|
|
3547
|
+
afrikaans: "afrikaans",
|
|
3548
|
+
albanian: "albanian",
|
|
3549
|
+
amharic: "amharic",
|
|
3550
|
+
arabic: "arabic",
|
|
3551
|
+
armenian: "armenian",
|
|
3552
|
+
assamese: "assamese",
|
|
3553
|
+
azerbaijani: "azerbaijani",
|
|
3554
|
+
bashkir: "bashkir",
|
|
3555
|
+
basque: "basque",
|
|
3556
|
+
belarusian: "belarusian",
|
|
3557
|
+
bengali: "bengali",
|
|
3558
|
+
bosnian: "bosnian",
|
|
3559
|
+
breton: "breton",
|
|
3560
|
+
bulgarian: "bulgarian",
|
|
3561
|
+
catalan: "catalan",
|
|
3562
|
+
chinese: "chinese",
|
|
3563
|
+
croatian: "croatian",
|
|
3564
|
+
czech: "czech",
|
|
3565
|
+
danish: "danish",
|
|
3566
|
+
dutch: "dutch",
|
|
3567
|
+
english: "english",
|
|
3568
|
+
estonian: "estonian",
|
|
3569
|
+
faroese: "faroese",
|
|
3570
|
+
finnish: "finnish",
|
|
3571
|
+
french: "french",
|
|
3572
|
+
galician: "galician",
|
|
3573
|
+
georgian: "georgian",
|
|
3574
|
+
german: "german",
|
|
3575
|
+
greek: "greek",
|
|
3576
|
+
gujarati: "gujarati",
|
|
3577
|
+
haitian_creole: "haitian creole",
|
|
3578
|
+
hausa: "hausa",
|
|
3579
|
+
hawaiian: "hawaiian",
|
|
3580
|
+
hebrew: "hebrew",
|
|
3581
|
+
hindi: "hindi",
|
|
3582
|
+
hungarian: "hungarian",
|
|
3583
|
+
icelandic: "icelandic",
|
|
3584
|
+
indonesian: "indonesian",
|
|
3585
|
+
italian: "italian",
|
|
3586
|
+
japanese: "japanese",
|
|
3587
|
+
javanese: "javanese",
|
|
3588
|
+
kannada: "kannada",
|
|
3589
|
+
kazakh: "kazakh",
|
|
3590
|
+
khmer: "khmer",
|
|
3591
|
+
korean: "korean",
|
|
3592
|
+
lao: "lao",
|
|
3593
|
+
latin: "latin",
|
|
3594
|
+
latvian: "latvian",
|
|
3595
|
+
lingala: "lingala",
|
|
3596
|
+
lithuanian: "lithuanian",
|
|
3597
|
+
luxembourgish: "luxembourgish",
|
|
3598
|
+
macedonian: "macedonian",
|
|
3599
|
+
malagasy: "malagasy",
|
|
3600
|
+
malay: "malay",
|
|
3601
|
+
malayalam: "malayalam",
|
|
3602
|
+
maltese: "maltese",
|
|
3603
|
+
maori: "maori",
|
|
3604
|
+
marathi: "marathi",
|
|
3605
|
+
mongolian: "mongolian",
|
|
3606
|
+
myanmar: "myanmar",
|
|
3607
|
+
nepali: "nepali",
|
|
3608
|
+
norwegian: "norwegian",
|
|
3609
|
+
nynorsk: "nynorsk",
|
|
3610
|
+
occitan: "occitan",
|
|
3611
|
+
pashto: "pashto",
|
|
3612
|
+
persian: "persian",
|
|
3613
|
+
polish: "polish",
|
|
3614
|
+
portuguese: "portuguese",
|
|
3615
|
+
punjabi: "punjabi",
|
|
3616
|
+
romanian: "romanian",
|
|
3617
|
+
russian: "russian",
|
|
3618
|
+
sanskrit: "sanskrit",
|
|
3619
|
+
serbian: "serbian",
|
|
3620
|
+
shona: "shona",
|
|
3621
|
+
sindhi: "sindhi",
|
|
3622
|
+
sinhala: "sinhala",
|
|
3623
|
+
slovak: "slovak",
|
|
3624
|
+
slovenian: "slovenian",
|
|
3625
|
+
somali: "somali",
|
|
3626
|
+
spanish: "spanish",
|
|
3627
|
+
sundanese: "sundanese",
|
|
3628
|
+
swahili: "swahili",
|
|
3629
|
+
swedish: "swedish",
|
|
3630
|
+
tagalog: "tagalog",
|
|
3631
|
+
tajik: "tajik",
|
|
3632
|
+
tamil: "tamil",
|
|
3633
|
+
tatar: "tatar",
|
|
3634
|
+
telugu: "telugu",
|
|
3635
|
+
thai: "thai",
|
|
3636
|
+
tibetan: "tibetan",
|
|
3637
|
+
turkish: "turkish",
|
|
3638
|
+
turkmen: "turkmen",
|
|
3639
|
+
ukrainian: "ukrainian",
|
|
3640
|
+
urdu: "urdu",
|
|
3641
|
+
uzbek: "uzbek",
|
|
3642
|
+
vietnamese: "vietnamese",
|
|
3643
|
+
welsh: "welsh",
|
|
3644
|
+
yiddish: "yiddish",
|
|
3645
|
+
yoruba: "yoruba"
|
|
3646
|
+
};
|
|
3647
|
+
|
|
3648
|
+
// src/generated/gladia/schema/audioToTextControllerAudioTranscriptionBodyLanguageBehaviour.ts
|
|
3649
|
+
var AudioToTextControllerAudioTranscriptionBodyLanguageBehaviour = {
|
|
3650
|
+
automatic_single_language: "automatic single language",
|
|
3651
|
+
automatic_multiple_languages: "automatic multiple languages",
|
|
3652
|
+
manual: "manual"
|
|
3653
|
+
};
|
|
3654
|
+
|
|
3655
|
+
// src/generated/gladia/schema/audioToTextControllerAudioTranscriptionBodyOutputFormat.ts
|
|
3656
|
+
var AudioToTextControllerAudioTranscriptionBodyOutputFormat = {
|
|
3657
|
+
json: "json",
|
|
3658
|
+
srt: "srt",
|
|
3659
|
+
vtt: "vtt",
|
|
3660
|
+
plain: "plain",
|
|
3661
|
+
txt: "txt"
|
|
3662
|
+
};
|
|
3663
|
+
|
|
3664
|
+
// src/generated/gladia/schema/audioToTextControllerAudioTranscriptionBodyTargetTranslationLanguage.ts
|
|
3665
|
+
var AudioToTextControllerAudioTranscriptionBodyTargetTranslationLanguage = {
|
|
3666
|
+
afrikaans: "afrikaans",
|
|
3667
|
+
albanian: "albanian",
|
|
3668
|
+
amharic: "amharic",
|
|
3669
|
+
arabic: "arabic",
|
|
3670
|
+
armenian: "armenian",
|
|
3671
|
+
assamese: "assamese",
|
|
3672
|
+
azerbaijani: "azerbaijani",
|
|
3673
|
+
bashkir: "bashkir",
|
|
3674
|
+
basque: "basque",
|
|
3675
|
+
belarusian: "belarusian",
|
|
3676
|
+
bengali: "bengali",
|
|
3677
|
+
bosnian: "bosnian",
|
|
3678
|
+
breton: "breton",
|
|
3679
|
+
bulgarian: "bulgarian",
|
|
3680
|
+
catalan: "catalan",
|
|
3681
|
+
chinese: "chinese",
|
|
3682
|
+
croatian: "croatian",
|
|
3683
|
+
czech: "czech",
|
|
3684
|
+
danish: "danish",
|
|
3685
|
+
dutch: "dutch",
|
|
3686
|
+
english: "english",
|
|
3687
|
+
estonian: "estonian",
|
|
3688
|
+
faroese: "faroese",
|
|
3689
|
+
finnish: "finnish",
|
|
3690
|
+
french: "french",
|
|
3691
|
+
galician: "galician",
|
|
3692
|
+
georgian: "georgian",
|
|
3693
|
+
german: "german",
|
|
3694
|
+
greek: "greek",
|
|
3695
|
+
gujarati: "gujarati",
|
|
3696
|
+
haitian_creole: "haitian creole",
|
|
3697
|
+
hausa: "hausa",
|
|
3698
|
+
hawaiian: "hawaiian",
|
|
3699
|
+
hebrew: "hebrew",
|
|
3700
|
+
hindi: "hindi",
|
|
3701
|
+
hungarian: "hungarian",
|
|
3702
|
+
icelandic: "icelandic",
|
|
3703
|
+
indonesian: "indonesian",
|
|
3704
|
+
italian: "italian",
|
|
3705
|
+
japanese: "japanese",
|
|
3706
|
+
javanese: "javanese",
|
|
3707
|
+
kannada: "kannada",
|
|
3708
|
+
kazakh: "kazakh",
|
|
3709
|
+
khmer: "khmer",
|
|
3710
|
+
korean: "korean",
|
|
3711
|
+
lao: "lao",
|
|
3712
|
+
latin: "latin",
|
|
3713
|
+
latvian: "latvian",
|
|
3714
|
+
lingala: "lingala",
|
|
3715
|
+
lithuanian: "lithuanian",
|
|
3716
|
+
luxembourgish: "luxembourgish",
|
|
3717
|
+
macedonian: "macedonian",
|
|
3718
|
+
malagasy: "malagasy",
|
|
3719
|
+
malay: "malay",
|
|
3720
|
+
malayalam: "malayalam",
|
|
3721
|
+
maltese: "maltese",
|
|
3722
|
+
maori: "maori",
|
|
3723
|
+
marathi: "marathi",
|
|
3724
|
+
mongolian: "mongolian",
|
|
3725
|
+
myanmar: "myanmar",
|
|
3726
|
+
nepali: "nepali",
|
|
3727
|
+
norwegian: "norwegian",
|
|
3728
|
+
nynorsk: "nynorsk",
|
|
3729
|
+
occitan: "occitan",
|
|
3730
|
+
pashto: "pashto",
|
|
3731
|
+
persian: "persian",
|
|
3732
|
+
polish: "polish",
|
|
3733
|
+
portuguese: "portuguese",
|
|
3734
|
+
punjabi: "punjabi",
|
|
3735
|
+
romanian: "romanian",
|
|
3736
|
+
russian: "russian",
|
|
3737
|
+
sanskrit: "sanskrit",
|
|
3738
|
+
serbian: "serbian",
|
|
3739
|
+
shona: "shona",
|
|
3740
|
+
sindhi: "sindhi",
|
|
3741
|
+
sinhala: "sinhala",
|
|
3742
|
+
slovak: "slovak",
|
|
3743
|
+
slovenian: "slovenian",
|
|
3744
|
+
somali: "somali",
|
|
3745
|
+
spanish: "spanish",
|
|
3746
|
+
sundanese: "sundanese",
|
|
3747
|
+
swahili: "swahili",
|
|
3748
|
+
swedish: "swedish",
|
|
3749
|
+
tagalog: "tagalog",
|
|
3750
|
+
tajik: "tajik",
|
|
3751
|
+
tamil: "tamil",
|
|
3752
|
+
tatar: "tatar",
|
|
3753
|
+
telugu: "telugu",
|
|
3754
|
+
thai: "thai",
|
|
3755
|
+
tibetan: "tibetan",
|
|
3756
|
+
turkish: "turkish",
|
|
3757
|
+
turkmen: "turkmen",
|
|
3758
|
+
ukrainian: "ukrainian",
|
|
3759
|
+
urdu: "urdu",
|
|
3760
|
+
uzbek: "uzbek",
|
|
3761
|
+
vietnamese: "vietnamese",
|
|
3762
|
+
welsh: "welsh",
|
|
3763
|
+
wolof: "wolof",
|
|
3764
|
+
yiddish: "yiddish",
|
|
3765
|
+
yoruba: "yoruba"
|
|
3766
|
+
};
|
|
3767
|
+
|
|
3768
|
+
// src/generated/gladia/schema/callbackLiveAudioChunkAckMessageEvent.ts
|
|
3769
|
+
var CallbackLiveAudioChunkAckMessageEvent = {
|
|
3770
|
+
liveaudio_chunk: "live.audio_chunk"
|
|
3771
|
+
};
|
|
3772
|
+
|
|
3773
|
+
// src/generated/gladia/schema/callbackLiveEndRecordingMessageEvent.ts
|
|
3774
|
+
var CallbackLiveEndRecordingMessageEvent = {
|
|
3775
|
+
liveend_recording: "live.end_recording"
|
|
3776
|
+
};
|
|
3777
|
+
|
|
3778
|
+
// src/generated/gladia/schema/callbackLiveEndSessionMessageEvent.ts
|
|
3779
|
+
var CallbackLiveEndSessionMessageEvent = {
|
|
3780
|
+
liveend_session: "live.end_session"
|
|
3781
|
+
};
|
|
3782
|
+
|
|
3783
|
+
// src/generated/gladia/schema/callbackLiveNamedEntityRecognitionMessageEvent.ts
|
|
3784
|
+
var CallbackLiveNamedEntityRecognitionMessageEvent = {
|
|
3785
|
+
livenamed_entity_recognition: "live.named_entity_recognition"
|
|
3786
|
+
};
|
|
3787
|
+
|
|
3788
|
+
// src/generated/gladia/schema/callbackLivePostChapterizationMessageEvent.ts
|
|
3789
|
+
var CallbackLivePostChapterizationMessageEvent = {
|
|
3790
|
+
livepost_chapterization: "live.post_chapterization"
|
|
3791
|
+
};
|
|
3792
|
+
|
|
3793
|
+
// src/generated/gladia/schema/callbackLivePostFinalTranscriptMessageEvent.ts
|
|
3794
|
+
var CallbackLivePostFinalTranscriptMessageEvent = {
|
|
3795
|
+
livepost_final_transcript: "live.post_final_transcript"
|
|
3796
|
+
};
|
|
3797
|
+
|
|
3798
|
+
// src/generated/gladia/schema/callbackLivePostSummarizationMessageEvent.ts
|
|
3799
|
+
var CallbackLivePostSummarizationMessageEvent = {
|
|
3800
|
+
livepost_summarization: "live.post_summarization"
|
|
3801
|
+
};
|
|
3802
|
+
|
|
3803
|
+
// src/generated/gladia/schema/callbackLivePostTranscriptMessageEvent.ts
|
|
3804
|
+
var CallbackLivePostTranscriptMessageEvent = {
|
|
3805
|
+
livepost_transcript: "live.post_transcript"
|
|
3806
|
+
};
|
|
3807
|
+
|
|
3808
|
+
// src/generated/gladia/schema/callbackLiveSentimentAnalysisMessageEvent.ts
|
|
3809
|
+
var CallbackLiveSentimentAnalysisMessageEvent = {
|
|
3810
|
+
livesentiment_analysis: "live.sentiment_analysis"
|
|
3811
|
+
};
|
|
3812
|
+
|
|
3813
|
+
// src/generated/gladia/schema/callbackLiveSpeechEndMessageEvent.ts
|
|
3814
|
+
var CallbackLiveSpeechEndMessageEvent = {
|
|
3815
|
+
livespeech_end: "live.speech_end"
|
|
3816
|
+
};
|
|
3817
|
+
|
|
3818
|
+
// src/generated/gladia/schema/callbackLiveSpeechStartMessageEvent.ts
|
|
3819
|
+
var CallbackLiveSpeechStartMessageEvent = {
|
|
3820
|
+
livespeech_start: "live.speech_start"
|
|
3821
|
+
};
|
|
3822
|
+
|
|
3823
|
+
// src/generated/gladia/schema/callbackLiveStartRecordingMessageEvent.ts
|
|
3824
|
+
var CallbackLiveStartRecordingMessageEvent = {
|
|
3825
|
+
livestart_recording: "live.start_recording"
|
|
3826
|
+
};
|
|
3827
|
+
|
|
3828
|
+
// src/generated/gladia/schema/callbackLiveStartSessionMessageEvent.ts
|
|
3829
|
+
var CallbackLiveStartSessionMessageEvent = {
|
|
3830
|
+
livestart_session: "live.start_session"
|
|
3831
|
+
};
|
|
3832
|
+
|
|
3833
|
+
// src/generated/gladia/schema/callbackLiveStopRecordingAckMessageEvent.ts
|
|
3834
|
+
var CallbackLiveStopRecordingAckMessageEvent = {
|
|
3835
|
+
livestop_recording: "live.stop_recording"
|
|
3836
|
+
};
|
|
3837
|
+
|
|
3838
|
+
// src/generated/gladia/schema/callbackLiveTranscriptMessageEvent.ts
|
|
3839
|
+
var CallbackLiveTranscriptMessageEvent = {
|
|
3840
|
+
livetranscript: "live.transcript"
|
|
3841
|
+
};
|
|
3842
|
+
|
|
3843
|
+
// src/generated/gladia/schema/callbackLiveTranslationMessageEvent.ts
|
|
3844
|
+
var CallbackLiveTranslationMessageEvent = {
|
|
3845
|
+
livetranslation: "live.translation"
|
|
3846
|
+
};
|
|
3847
|
+
|
|
3848
|
+
// src/generated/gladia/schema/callbackMethodEnum.ts
|
|
3849
|
+
var CallbackMethodEnum = {
|
|
3850
|
+
POST: "POST",
|
|
3851
|
+
PUT: "PUT"
|
|
3852
|
+
};
|
|
3853
|
+
|
|
3854
|
+
// src/generated/gladia/schema/callbackTranscriptionErrorPayloadEvent.ts
|
|
3855
|
+
var CallbackTranscriptionErrorPayloadEvent = {
|
|
3856
|
+
transcriptionerror: "transcription.error"
|
|
3857
|
+
};
|
|
3858
|
+
|
|
3859
|
+
// src/generated/gladia/schema/callbackTranscriptionSuccessPayloadEvent.ts
|
|
3860
|
+
var CallbackTranscriptionSuccessPayloadEvent = {
|
|
3861
|
+
transcriptionsuccess: "transcription.success"
|
|
3862
|
+
};
|
|
3863
|
+
|
|
3864
|
+
// src/generated/gladia/schema/endRecordingMessageType.ts
|
|
3865
|
+
var EndRecordingMessageType = {
|
|
3866
|
+
end_recording: "end_recording"
|
|
3867
|
+
};
|
|
3868
|
+
|
|
3869
|
+
// src/generated/gladia/schema/endSessionMessageType.ts
|
|
3870
|
+
var EndSessionMessageType = {
|
|
3871
|
+
end_session: "end_session"
|
|
3872
|
+
};
|
|
3873
|
+
|
|
3874
|
+
// src/generated/gladia/schema/historyControllerGetListV1KindItem.ts
|
|
3875
|
+
var HistoryControllerGetListV1KindItem = {
|
|
3876
|
+
"pre-recorded": "pre-recorded",
|
|
3877
|
+
live: "live"
|
|
3878
|
+
};
|
|
3879
|
+
|
|
3880
|
+
// src/generated/gladia/schema/historyControllerGetListV1StatusItem.ts
|
|
3881
|
+
var HistoryControllerGetListV1StatusItem = {
|
|
3882
|
+
queued: "queued",
|
|
3883
|
+
processing: "processing",
|
|
3884
|
+
done: "done",
|
|
3885
|
+
error: "error"
|
|
3886
|
+
};
|
|
3887
|
+
|
|
3888
|
+
// src/generated/gladia/schema/namedEntityRecognitionMessageType.ts
|
|
3889
|
+
var NamedEntityRecognitionMessageType = {
|
|
3890
|
+
named_entity_recognition: "named_entity_recognition"
|
|
3891
|
+
};
|
|
3892
|
+
|
|
3893
|
+
// src/generated/gladia/schema/postChapterizationMessageType.ts
|
|
3894
|
+
var PostChapterizationMessageType = {
|
|
3895
|
+
post_chapterization: "post_chapterization"
|
|
3896
|
+
};
|
|
3897
|
+
|
|
3898
|
+
// src/generated/gladia/schema/postFinalTranscriptMessageType.ts
|
|
3899
|
+
var PostFinalTranscriptMessageType = {
|
|
3900
|
+
post_final_transcript: "post_final_transcript"
|
|
3901
|
+
};
|
|
3902
|
+
|
|
3903
|
+
// src/generated/gladia/schema/postSummarizationMessageType.ts
|
|
3904
|
+
var PostSummarizationMessageType = {
|
|
3905
|
+
post_summarization: "post_summarization"
|
|
3906
|
+
};
|
|
3907
|
+
|
|
3908
|
+
// src/generated/gladia/schema/postTranscriptMessageType.ts
|
|
3909
|
+
var PostTranscriptMessageType = {
|
|
3910
|
+
post_transcript: "post_transcript"
|
|
3911
|
+
};
|
|
3912
|
+
|
|
3913
|
+
// src/generated/gladia/schema/preRecordedControllerGetPreRecordedJobsV2StatusItem.ts
|
|
3914
|
+
var PreRecordedControllerGetPreRecordedJobsV2StatusItem = {
|
|
3915
|
+
queued: "queued",
|
|
3916
|
+
processing: "processing",
|
|
3917
|
+
done: "done",
|
|
3918
|
+
error: "error"
|
|
3919
|
+
};
|
|
3920
|
+
|
|
3921
|
+
// src/generated/gladia/schema/preRecordedResponseKind.ts
|
|
3922
|
+
var PreRecordedResponseKind = {
|
|
3923
|
+
"pre-recorded": "pre-recorded"
|
|
3924
|
+
};
|
|
3925
|
+
|
|
3926
|
+
// src/generated/gladia/schema/preRecordedResponseStatus.ts
|
|
3927
|
+
var PreRecordedResponseStatus = {
|
|
3928
|
+
queued: "queued",
|
|
3929
|
+
processing: "processing",
|
|
3930
|
+
done: "done",
|
|
3931
|
+
error: "error"
|
|
3932
|
+
};
|
|
3933
|
+
|
|
3934
|
+
// src/generated/gladia/schema/sentimentAnalysisMessageType.ts
|
|
3935
|
+
var SentimentAnalysisMessageType = {
|
|
3936
|
+
sentiment_analysis: "sentiment_analysis"
|
|
3937
|
+
};
|
|
3938
|
+
|
|
3939
|
+
// src/generated/gladia/schema/speechEndMessageType.ts
|
|
3940
|
+
var SpeechEndMessageType = {
|
|
3941
|
+
speech_end: "speech_end"
|
|
3942
|
+
};
|
|
3943
|
+
|
|
3944
|
+
// src/generated/gladia/schema/speechStartMessageType.ts
|
|
3945
|
+
var SpeechStartMessageType = {
|
|
3946
|
+
speech_start: "speech_start"
|
|
3947
|
+
};
|
|
3948
|
+
|
|
3949
|
+
// src/generated/gladia/schema/startRecordingMessageType.ts
|
|
3950
|
+
var StartRecordingMessageType = {
|
|
3951
|
+
start_recording: "start_recording"
|
|
3952
|
+
};
|
|
3953
|
+
|
|
3954
|
+
// src/generated/gladia/schema/startSessionMessageType.ts
|
|
3955
|
+
var StartSessionMessageType = {
|
|
3956
|
+
start_session: "start_session"
|
|
3957
|
+
};
|
|
3958
|
+
|
|
3959
|
+
// src/generated/gladia/schema/stopRecordingAckMessageType.ts
|
|
3960
|
+
var StopRecordingAckMessageType = {
|
|
3961
|
+
stop_recording: "stop_recording"
|
|
3962
|
+
};
|
|
3963
|
+
|
|
3964
|
+
// src/generated/gladia/schema/stopRecordingActionType.ts
|
|
3965
|
+
var StopRecordingActionType = {
|
|
3966
|
+
stop_recording: "stop_recording"
|
|
3967
|
+
};
|
|
3968
|
+
|
|
3969
|
+
// src/generated/gladia/schema/streamingControllerGetStreamingJobsV2StatusItem.ts
|
|
3970
|
+
var StreamingControllerGetStreamingJobsV2StatusItem = {
|
|
3971
|
+
queued: "queued",
|
|
3972
|
+
processing: "processing",
|
|
3973
|
+
done: "done",
|
|
3974
|
+
error: "error"
|
|
3975
|
+
};
|
|
3976
|
+
|
|
3977
|
+
// src/generated/gladia/schema/streamingResponseKind.ts
|
|
3978
|
+
var StreamingResponseKind = {
|
|
3979
|
+
live: "live"
|
|
3980
|
+
};
|
|
3981
|
+
|
|
3982
|
+
// src/generated/gladia/schema/streamingResponseStatus.ts
|
|
3983
|
+
var StreamingResponseStatus = {
|
|
3984
|
+
queued: "queued",
|
|
3985
|
+
processing: "processing",
|
|
3986
|
+
done: "done",
|
|
3987
|
+
error: "error"
|
|
3988
|
+
};
|
|
3989
|
+
|
|
3990
|
+
// src/generated/gladia/schema/streamingSupportedBitDepthEnum.ts
|
|
3991
|
+
var StreamingSupportedBitDepthEnum = {
|
|
3992
|
+
NUMBER_8: 8,
|
|
3993
|
+
NUMBER_16: 16,
|
|
3994
|
+
NUMBER_24: 24,
|
|
3995
|
+
NUMBER_32: 32
|
|
3996
|
+
};
|
|
3997
|
+
|
|
3998
|
+
// src/generated/gladia/schema/streamingSupportedEncodingEnum.ts
|
|
3999
|
+
var StreamingSupportedEncodingEnum = {
|
|
4000
|
+
"wav/pcm": "wav/pcm",
|
|
4001
|
+
"wav/alaw": "wav/alaw",
|
|
4002
|
+
"wav/ulaw": "wav/ulaw"
|
|
4003
|
+
};
|
|
4004
|
+
|
|
4005
|
+
// src/generated/gladia/schema/streamingSupportedModels.ts
|
|
4006
|
+
var StreamingSupportedModels = {
|
|
4007
|
+
"solaria-1": "solaria-1"
|
|
4008
|
+
};
|
|
4009
|
+
|
|
4010
|
+
// src/generated/gladia/schema/streamingSupportedRegions.ts
|
|
4011
|
+
var StreamingSupportedRegions = {
|
|
4012
|
+
"us-west": "us-west",
|
|
4013
|
+
"eu-west": "eu-west"
|
|
4014
|
+
};
|
|
4015
|
+
|
|
4016
|
+
// src/generated/gladia/schema/streamingSupportedSampleRateEnum.ts
|
|
4017
|
+
var StreamingSupportedSampleRateEnum = {
|
|
4018
|
+
NUMBER_8000: 8e3,
|
|
4019
|
+
NUMBER_16000: 16e3,
|
|
4020
|
+
NUMBER_32000: 32e3,
|
|
4021
|
+
NUMBER_44100: 44100,
|
|
4022
|
+
NUMBER_48000: 48e3
|
|
4023
|
+
};
|
|
4024
|
+
|
|
4025
|
+
// src/generated/gladia/schema/subtitlesFormatEnum.ts
|
|
4026
|
+
var SubtitlesFormatEnum = {
|
|
4027
|
+
srt: "srt",
|
|
4028
|
+
vtt: "vtt"
|
|
4029
|
+
};
|
|
4030
|
+
|
|
4031
|
+
// src/generated/gladia/schema/subtitlesStyleEnum.ts
|
|
4032
|
+
var SubtitlesStyleEnum = {
|
|
4033
|
+
default: "default",
|
|
4034
|
+
compliance: "compliance"
|
|
4035
|
+
};
|
|
4036
|
+
|
|
4037
|
+
// src/generated/gladia/schema/summaryTypesEnum.ts
|
|
4038
|
+
var SummaryTypesEnum = {
|
|
4039
|
+
general: "general",
|
|
4040
|
+
bullet_points: "bullet_points",
|
|
4041
|
+
concise: "concise"
|
|
4042
|
+
};
|
|
4043
|
+
|
|
4044
|
+
// src/generated/gladia/schema/transcriptMessageType.ts
|
|
4045
|
+
var TranscriptMessageType = {
|
|
4046
|
+
transcript: "transcript"
|
|
4047
|
+
};
|
|
4048
|
+
|
|
4049
|
+
// src/generated/gladia/schema/transcriptionControllerListV2KindItem.ts
|
|
4050
|
+
var TranscriptionControllerListV2KindItem = {
|
|
4051
|
+
"pre-recorded": "pre-recorded",
|
|
4052
|
+
live: "live"
|
|
4053
|
+
};
|
|
4054
|
+
|
|
4055
|
+
// src/generated/gladia/schema/transcriptionControllerListV2StatusItem.ts
|
|
4056
|
+
var TranscriptionControllerListV2StatusItem = {
|
|
4057
|
+
queued: "queued",
|
|
4058
|
+
processing: "processing",
|
|
4059
|
+
done: "done",
|
|
4060
|
+
error: "error"
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
// src/generated/gladia/schema/transcriptionLanguageCodeEnum.ts
|
|
4064
|
+
var TranscriptionLanguageCodeEnum = {
|
|
4065
|
+
af: "af",
|
|
4066
|
+
am: "am",
|
|
4067
|
+
ar: "ar",
|
|
4068
|
+
as: "as",
|
|
4069
|
+
az: "az",
|
|
4070
|
+
ba: "ba",
|
|
4071
|
+
be: "be",
|
|
4072
|
+
bg: "bg",
|
|
4073
|
+
bn: "bn",
|
|
4074
|
+
bo: "bo",
|
|
4075
|
+
br: "br",
|
|
4076
|
+
bs: "bs",
|
|
4077
|
+
ca: "ca",
|
|
4078
|
+
cs: "cs",
|
|
4079
|
+
cy: "cy",
|
|
4080
|
+
da: "da",
|
|
4081
|
+
de: "de",
|
|
4082
|
+
el: "el",
|
|
4083
|
+
en: "en",
|
|
4084
|
+
es: "es",
|
|
4085
|
+
et: "et",
|
|
4086
|
+
eu: "eu",
|
|
4087
|
+
fa: "fa",
|
|
4088
|
+
fi: "fi",
|
|
4089
|
+
fo: "fo",
|
|
4090
|
+
fr: "fr",
|
|
4091
|
+
gl: "gl",
|
|
4092
|
+
gu: "gu",
|
|
4093
|
+
ha: "ha",
|
|
4094
|
+
haw: "haw",
|
|
4095
|
+
he: "he",
|
|
4096
|
+
hi: "hi",
|
|
4097
|
+
hr: "hr",
|
|
4098
|
+
ht: "ht",
|
|
4099
|
+
hu: "hu",
|
|
4100
|
+
hy: "hy",
|
|
4101
|
+
id: "id",
|
|
4102
|
+
is: "is",
|
|
4103
|
+
it: "it",
|
|
4104
|
+
ja: "ja",
|
|
4105
|
+
jw: "jw",
|
|
4106
|
+
ka: "ka",
|
|
4107
|
+
kk: "kk",
|
|
4108
|
+
km: "km",
|
|
4109
|
+
kn: "kn",
|
|
4110
|
+
ko: "ko",
|
|
4111
|
+
la: "la",
|
|
4112
|
+
lb: "lb",
|
|
4113
|
+
ln: "ln",
|
|
4114
|
+
lo: "lo",
|
|
4115
|
+
lt: "lt",
|
|
4116
|
+
lv: "lv",
|
|
4117
|
+
mg: "mg",
|
|
4118
|
+
mi: "mi",
|
|
4119
|
+
mk: "mk",
|
|
4120
|
+
ml: "ml",
|
|
4121
|
+
mn: "mn",
|
|
4122
|
+
mr: "mr",
|
|
4123
|
+
ms: "ms",
|
|
4124
|
+
mt: "mt",
|
|
4125
|
+
my: "my",
|
|
4126
|
+
ne: "ne",
|
|
4127
|
+
nl: "nl",
|
|
4128
|
+
nn: "nn",
|
|
4129
|
+
no: "no",
|
|
4130
|
+
oc: "oc",
|
|
4131
|
+
pa: "pa",
|
|
4132
|
+
pl: "pl",
|
|
4133
|
+
ps: "ps",
|
|
4134
|
+
pt: "pt",
|
|
4135
|
+
ro: "ro",
|
|
4136
|
+
ru: "ru",
|
|
4137
|
+
sa: "sa",
|
|
4138
|
+
sd: "sd",
|
|
4139
|
+
si: "si",
|
|
4140
|
+
sk: "sk",
|
|
4141
|
+
sl: "sl",
|
|
4142
|
+
sn: "sn",
|
|
4143
|
+
so: "so",
|
|
4144
|
+
sq: "sq",
|
|
4145
|
+
sr: "sr",
|
|
4146
|
+
su: "su",
|
|
4147
|
+
sv: "sv",
|
|
4148
|
+
sw: "sw",
|
|
4149
|
+
ta: "ta",
|
|
4150
|
+
te: "te",
|
|
4151
|
+
tg: "tg",
|
|
4152
|
+
th: "th",
|
|
4153
|
+
tk: "tk",
|
|
4154
|
+
tl: "tl",
|
|
4155
|
+
tr: "tr",
|
|
4156
|
+
tt: "tt",
|
|
4157
|
+
uk: "uk",
|
|
4158
|
+
ur: "ur",
|
|
4159
|
+
uz: "uz",
|
|
4160
|
+
vi: "vi",
|
|
4161
|
+
yi: "yi",
|
|
4162
|
+
yo: "yo",
|
|
4163
|
+
zh: "zh"
|
|
4164
|
+
};
|
|
4165
|
+
|
|
4166
|
+
// src/generated/gladia/schema/translationLanguageCodeEnum.ts
|
|
4167
|
+
var TranslationLanguageCodeEnum = {
|
|
4168
|
+
af: "af",
|
|
4169
|
+
am: "am",
|
|
4170
|
+
ar: "ar",
|
|
4171
|
+
as: "as",
|
|
4172
|
+
az: "az",
|
|
4173
|
+
ba: "ba",
|
|
4174
|
+
be: "be",
|
|
4175
|
+
bg: "bg",
|
|
4176
|
+
bn: "bn",
|
|
4177
|
+
bo: "bo",
|
|
4178
|
+
br: "br",
|
|
4179
|
+
bs: "bs",
|
|
4180
|
+
ca: "ca",
|
|
4181
|
+
cs: "cs",
|
|
4182
|
+
cy: "cy",
|
|
4183
|
+
da: "da",
|
|
4184
|
+
de: "de",
|
|
4185
|
+
el: "el",
|
|
4186
|
+
en: "en",
|
|
4187
|
+
es: "es",
|
|
4188
|
+
et: "et",
|
|
4189
|
+
eu: "eu",
|
|
4190
|
+
fa: "fa",
|
|
4191
|
+
fi: "fi",
|
|
4192
|
+
fo: "fo",
|
|
4193
|
+
fr: "fr",
|
|
4194
|
+
gl: "gl",
|
|
4195
|
+
gu: "gu",
|
|
4196
|
+
ha: "ha",
|
|
4197
|
+
haw: "haw",
|
|
4198
|
+
he: "he",
|
|
4199
|
+
hi: "hi",
|
|
4200
|
+
hr: "hr",
|
|
4201
|
+
ht: "ht",
|
|
4202
|
+
hu: "hu",
|
|
4203
|
+
hy: "hy",
|
|
4204
|
+
id: "id",
|
|
4205
|
+
is: "is",
|
|
4206
|
+
it: "it",
|
|
4207
|
+
ja: "ja",
|
|
4208
|
+
jw: "jw",
|
|
4209
|
+
ka: "ka",
|
|
4210
|
+
kk: "kk",
|
|
4211
|
+
km: "km",
|
|
4212
|
+
kn: "kn",
|
|
4213
|
+
ko: "ko",
|
|
4214
|
+
la: "la",
|
|
4215
|
+
lb: "lb",
|
|
4216
|
+
ln: "ln",
|
|
4217
|
+
lo: "lo",
|
|
4218
|
+
lt: "lt",
|
|
4219
|
+
lv: "lv",
|
|
4220
|
+
mg: "mg",
|
|
4221
|
+
mi: "mi",
|
|
4222
|
+
mk: "mk",
|
|
4223
|
+
ml: "ml",
|
|
4224
|
+
mn: "mn",
|
|
4225
|
+
mr: "mr",
|
|
4226
|
+
ms: "ms",
|
|
4227
|
+
mt: "mt",
|
|
4228
|
+
my: "my",
|
|
4229
|
+
ne: "ne",
|
|
4230
|
+
nl: "nl",
|
|
4231
|
+
nn: "nn",
|
|
4232
|
+
no: "no",
|
|
4233
|
+
oc: "oc",
|
|
4234
|
+
pa: "pa",
|
|
4235
|
+
pl: "pl",
|
|
4236
|
+
ps: "ps",
|
|
4237
|
+
pt: "pt",
|
|
4238
|
+
ro: "ro",
|
|
4239
|
+
ru: "ru",
|
|
4240
|
+
sa: "sa",
|
|
4241
|
+
sd: "sd",
|
|
4242
|
+
si: "si",
|
|
4243
|
+
sk: "sk",
|
|
4244
|
+
sl: "sl",
|
|
4245
|
+
sn: "sn",
|
|
4246
|
+
so: "so",
|
|
4247
|
+
sq: "sq",
|
|
4248
|
+
sr: "sr",
|
|
4249
|
+
su: "su",
|
|
4250
|
+
sv: "sv",
|
|
4251
|
+
sw: "sw",
|
|
4252
|
+
ta: "ta",
|
|
4253
|
+
te: "te",
|
|
4254
|
+
tg: "tg",
|
|
4255
|
+
th: "th",
|
|
4256
|
+
tk: "tk",
|
|
4257
|
+
tl: "tl",
|
|
4258
|
+
tr: "tr",
|
|
4259
|
+
tt: "tt",
|
|
4260
|
+
uk: "uk",
|
|
4261
|
+
ur: "ur",
|
|
4262
|
+
uz: "uz",
|
|
4263
|
+
vi: "vi",
|
|
4264
|
+
wo: "wo",
|
|
4265
|
+
yi: "yi",
|
|
4266
|
+
yo: "yo",
|
|
4267
|
+
zh: "zh"
|
|
4268
|
+
};
|
|
4269
|
+
|
|
4270
|
+
// src/generated/gladia/schema/translationMessageType.ts
|
|
4271
|
+
var TranslationMessageType = {
|
|
4272
|
+
translation: "translation"
|
|
4273
|
+
};
|
|
4274
|
+
|
|
4275
|
+
// src/generated/gladia/schema/translationModelEnum.ts
|
|
4276
|
+
var TranslationModelEnum = {
|
|
4277
|
+
base: "base",
|
|
4278
|
+
enhanced: "enhanced"
|
|
4279
|
+
};
|
|
4280
|
+
|
|
4281
|
+
// src/generated/gladia/schema/videoToTextControllerVideoTranscriptionBodyLanguage.ts
|
|
4282
|
+
var VideoToTextControllerVideoTranscriptionBodyLanguage = {
|
|
4283
|
+
afrikaans: "afrikaans",
|
|
4284
|
+
albanian: "albanian",
|
|
4285
|
+
amharic: "amharic",
|
|
4286
|
+
arabic: "arabic",
|
|
4287
|
+
armenian: "armenian",
|
|
4288
|
+
assamese: "assamese",
|
|
4289
|
+
azerbaijani: "azerbaijani",
|
|
4290
|
+
bashkir: "bashkir",
|
|
4291
|
+
basque: "basque",
|
|
4292
|
+
belarusian: "belarusian",
|
|
4293
|
+
bengali: "bengali",
|
|
4294
|
+
bosnian: "bosnian",
|
|
4295
|
+
breton: "breton",
|
|
4296
|
+
bulgarian: "bulgarian",
|
|
4297
|
+
catalan: "catalan",
|
|
4298
|
+
chinese: "chinese",
|
|
4299
|
+
croatian: "croatian",
|
|
4300
|
+
czech: "czech",
|
|
4301
|
+
danish: "danish",
|
|
4302
|
+
dutch: "dutch",
|
|
4303
|
+
english: "english",
|
|
4304
|
+
estonian: "estonian",
|
|
4305
|
+
faroese: "faroese",
|
|
4306
|
+
finnish: "finnish",
|
|
4307
|
+
french: "french",
|
|
4308
|
+
galician: "galician",
|
|
4309
|
+
georgian: "georgian",
|
|
4310
|
+
german: "german",
|
|
4311
|
+
greek: "greek",
|
|
4312
|
+
gujarati: "gujarati",
|
|
4313
|
+
haitian_creole: "haitian creole",
|
|
4314
|
+
hausa: "hausa",
|
|
4315
|
+
hawaiian: "hawaiian",
|
|
4316
|
+
hebrew: "hebrew",
|
|
4317
|
+
hindi: "hindi",
|
|
4318
|
+
hungarian: "hungarian",
|
|
4319
|
+
icelandic: "icelandic",
|
|
4320
|
+
indonesian: "indonesian",
|
|
4321
|
+
italian: "italian",
|
|
4322
|
+
japanese: "japanese",
|
|
4323
|
+
javanese: "javanese",
|
|
4324
|
+
kannada: "kannada",
|
|
4325
|
+
kazakh: "kazakh",
|
|
4326
|
+
khmer: "khmer",
|
|
4327
|
+
korean: "korean",
|
|
4328
|
+
lao: "lao",
|
|
4329
|
+
latin: "latin",
|
|
4330
|
+
latvian: "latvian",
|
|
4331
|
+
lingala: "lingala",
|
|
4332
|
+
lithuanian: "lithuanian",
|
|
4333
|
+
luxembourgish: "luxembourgish",
|
|
4334
|
+
macedonian: "macedonian",
|
|
4335
|
+
malagasy: "malagasy",
|
|
4336
|
+
malay: "malay",
|
|
4337
|
+
malayalam: "malayalam",
|
|
4338
|
+
maltese: "maltese",
|
|
4339
|
+
maori: "maori",
|
|
4340
|
+
marathi: "marathi",
|
|
4341
|
+
mongolian: "mongolian",
|
|
4342
|
+
myanmar: "myanmar",
|
|
4343
|
+
nepali: "nepali",
|
|
4344
|
+
norwegian: "norwegian",
|
|
4345
|
+
nynorsk: "nynorsk",
|
|
4346
|
+
occitan: "occitan",
|
|
4347
|
+
pashto: "pashto",
|
|
4348
|
+
persian: "persian",
|
|
4349
|
+
polish: "polish",
|
|
4350
|
+
portuguese: "portuguese",
|
|
4351
|
+
punjabi: "punjabi",
|
|
4352
|
+
romanian: "romanian",
|
|
4353
|
+
russian: "russian",
|
|
4354
|
+
sanskrit: "sanskrit",
|
|
4355
|
+
serbian: "serbian",
|
|
4356
|
+
shona: "shona",
|
|
4357
|
+
sindhi: "sindhi",
|
|
4358
|
+
sinhala: "sinhala",
|
|
4359
|
+
slovak: "slovak",
|
|
4360
|
+
slovenian: "slovenian",
|
|
4361
|
+
somali: "somali",
|
|
4362
|
+
spanish: "spanish",
|
|
4363
|
+
sundanese: "sundanese",
|
|
4364
|
+
swahili: "swahili",
|
|
4365
|
+
swedish: "swedish",
|
|
4366
|
+
tagalog: "tagalog",
|
|
4367
|
+
tajik: "tajik",
|
|
4368
|
+
tamil: "tamil",
|
|
4369
|
+
tatar: "tatar",
|
|
4370
|
+
telugu: "telugu",
|
|
4371
|
+
thai: "thai",
|
|
4372
|
+
tibetan: "tibetan",
|
|
4373
|
+
turkish: "turkish",
|
|
4374
|
+
turkmen: "turkmen",
|
|
4375
|
+
ukrainian: "ukrainian",
|
|
4376
|
+
urdu: "urdu",
|
|
4377
|
+
uzbek: "uzbek",
|
|
4378
|
+
vietnamese: "vietnamese",
|
|
4379
|
+
welsh: "welsh",
|
|
4380
|
+
yiddish: "yiddish",
|
|
4381
|
+
yoruba: "yoruba"
|
|
4382
|
+
};
|
|
4383
|
+
|
|
4384
|
+
// src/generated/gladia/schema/videoToTextControllerVideoTranscriptionBodyLanguageBehaviour.ts
|
|
4385
|
+
var VideoToTextControllerVideoTranscriptionBodyLanguageBehaviour = {
|
|
4386
|
+
automatic_single_language: "automatic single language",
|
|
4387
|
+
automatic_multiple_languages: "automatic multiple languages",
|
|
4388
|
+
manual: "manual"
|
|
4389
|
+
};
|
|
4390
|
+
|
|
4391
|
+
// src/generated/gladia/schema/videoToTextControllerVideoTranscriptionBodyOutputFormat.ts
|
|
4392
|
+
var VideoToTextControllerVideoTranscriptionBodyOutputFormat = {
|
|
4393
|
+
json: "json",
|
|
4394
|
+
srt: "srt",
|
|
4395
|
+
vtt: "vtt",
|
|
4396
|
+
plain: "plain",
|
|
4397
|
+
txt: "txt"
|
|
4398
|
+
};
|
|
4399
|
+
|
|
4400
|
+
// src/generated/gladia/schema/videoToTextControllerVideoTranscriptionBodyTargetTranslationLanguage.ts
|
|
4401
|
+
var VideoToTextControllerVideoTranscriptionBodyTargetTranslationLanguage = {
|
|
4402
|
+
afrikaans: "afrikaans",
|
|
4403
|
+
albanian: "albanian",
|
|
4404
|
+
amharic: "amharic",
|
|
4405
|
+
arabic: "arabic",
|
|
4406
|
+
armenian: "armenian",
|
|
4407
|
+
assamese: "assamese",
|
|
4408
|
+
azerbaijani: "azerbaijani",
|
|
4409
|
+
bashkir: "bashkir",
|
|
4410
|
+
basque: "basque",
|
|
4411
|
+
belarusian: "belarusian",
|
|
4412
|
+
bengali: "bengali",
|
|
4413
|
+
bosnian: "bosnian",
|
|
4414
|
+
breton: "breton",
|
|
4415
|
+
bulgarian: "bulgarian",
|
|
4416
|
+
catalan: "catalan",
|
|
4417
|
+
chinese: "chinese",
|
|
4418
|
+
croatian: "croatian",
|
|
4419
|
+
czech: "czech",
|
|
4420
|
+
danish: "danish",
|
|
4421
|
+
dutch: "dutch",
|
|
4422
|
+
english: "english",
|
|
4423
|
+
estonian: "estonian",
|
|
4424
|
+
faroese: "faroese",
|
|
4425
|
+
finnish: "finnish",
|
|
4426
|
+
french: "french",
|
|
4427
|
+
galician: "galician",
|
|
4428
|
+
georgian: "georgian",
|
|
4429
|
+
german: "german",
|
|
4430
|
+
greek: "greek",
|
|
4431
|
+
gujarati: "gujarati",
|
|
4432
|
+
haitian_creole: "haitian creole",
|
|
4433
|
+
hausa: "hausa",
|
|
4434
|
+
hawaiian: "hawaiian",
|
|
4435
|
+
hebrew: "hebrew",
|
|
4436
|
+
hindi: "hindi",
|
|
4437
|
+
hungarian: "hungarian",
|
|
4438
|
+
icelandic: "icelandic",
|
|
4439
|
+
indonesian: "indonesian",
|
|
4440
|
+
italian: "italian",
|
|
4441
|
+
japanese: "japanese",
|
|
4442
|
+
javanese: "javanese",
|
|
4443
|
+
kannada: "kannada",
|
|
4444
|
+
kazakh: "kazakh",
|
|
4445
|
+
khmer: "khmer",
|
|
4446
|
+
korean: "korean",
|
|
4447
|
+
lao: "lao",
|
|
4448
|
+
latin: "latin",
|
|
4449
|
+
latvian: "latvian",
|
|
4450
|
+
lingala: "lingala",
|
|
4451
|
+
lithuanian: "lithuanian",
|
|
4452
|
+
luxembourgish: "luxembourgish",
|
|
4453
|
+
macedonian: "macedonian",
|
|
4454
|
+
malagasy: "malagasy",
|
|
4455
|
+
malay: "malay",
|
|
4456
|
+
malayalam: "malayalam",
|
|
4457
|
+
maltese: "maltese",
|
|
4458
|
+
maori: "maori",
|
|
4459
|
+
marathi: "marathi",
|
|
4460
|
+
mongolian: "mongolian",
|
|
4461
|
+
myanmar: "myanmar",
|
|
4462
|
+
nepali: "nepali",
|
|
4463
|
+
norwegian: "norwegian",
|
|
4464
|
+
nynorsk: "nynorsk",
|
|
4465
|
+
occitan: "occitan",
|
|
4466
|
+
pashto: "pashto",
|
|
4467
|
+
persian: "persian",
|
|
4468
|
+
polish: "polish",
|
|
4469
|
+
portuguese: "portuguese",
|
|
4470
|
+
punjabi: "punjabi",
|
|
4471
|
+
romanian: "romanian",
|
|
4472
|
+
russian: "russian",
|
|
4473
|
+
sanskrit: "sanskrit",
|
|
4474
|
+
serbian: "serbian",
|
|
4475
|
+
shona: "shona",
|
|
4476
|
+
sindhi: "sindhi",
|
|
4477
|
+
sinhala: "sinhala",
|
|
4478
|
+
slovak: "slovak",
|
|
4479
|
+
slovenian: "slovenian",
|
|
4480
|
+
somali: "somali",
|
|
4481
|
+
spanish: "spanish",
|
|
4482
|
+
sundanese: "sundanese",
|
|
4483
|
+
swahili: "swahili",
|
|
4484
|
+
swedish: "swedish",
|
|
4485
|
+
tagalog: "tagalog",
|
|
4486
|
+
tajik: "tajik",
|
|
4487
|
+
tamil: "tamil",
|
|
4488
|
+
tatar: "tatar",
|
|
4489
|
+
telugu: "telugu",
|
|
4490
|
+
thai: "thai",
|
|
4491
|
+
tibetan: "tibetan",
|
|
4492
|
+
turkish: "turkish",
|
|
4493
|
+
turkmen: "turkmen",
|
|
4494
|
+
ukrainian: "ukrainian",
|
|
4495
|
+
urdu: "urdu",
|
|
4496
|
+
uzbek: "uzbek",
|
|
4497
|
+
vietnamese: "vietnamese",
|
|
4498
|
+
welsh: "welsh",
|
|
4499
|
+
wolof: "wolof",
|
|
4500
|
+
yiddish: "yiddish",
|
|
4501
|
+
yoruba: "yoruba"
|
|
4502
|
+
};
|
|
4503
|
+
|
|
4504
|
+
// src/generated/gladia/schema/webhookLiveEndRecordingPayloadEvent.ts
|
|
4505
|
+
var WebhookLiveEndRecordingPayloadEvent = {
|
|
4506
|
+
liveend_recording: "live.end_recording"
|
|
4507
|
+
};
|
|
4508
|
+
|
|
4509
|
+
// src/generated/gladia/schema/webhookLiveEndSessionPayloadEvent.ts
|
|
4510
|
+
var WebhookLiveEndSessionPayloadEvent = {
|
|
4511
|
+
liveend_session: "live.end_session"
|
|
4512
|
+
};
|
|
4513
|
+
|
|
4514
|
+
// src/generated/gladia/schema/webhookLiveStartRecordingPayloadEvent.ts
|
|
4515
|
+
var WebhookLiveStartRecordingPayloadEvent = {
|
|
4516
|
+
livestart_recording: "live.start_recording"
|
|
4517
|
+
};
|
|
4518
|
+
|
|
4519
|
+
// src/generated/gladia/schema/webhookLiveStartSessionPayloadEvent.ts
|
|
4520
|
+
var WebhookLiveStartSessionPayloadEvent = {
|
|
4521
|
+
livestart_session: "live.start_session"
|
|
4522
|
+
};
|
|
4523
|
+
|
|
4524
|
+
// src/generated/gladia/schema/webhookTranscriptionCreatedPayloadEvent.ts
|
|
4525
|
+
var WebhookTranscriptionCreatedPayloadEvent = {
|
|
4526
|
+
transcriptioncreated: "transcription.created"
|
|
4527
|
+
};
|
|
4528
|
+
|
|
4529
|
+
// src/generated/gladia/schema/webhookTranscriptionErrorPayloadEvent.ts
|
|
4530
|
+
var WebhookTranscriptionErrorPayloadEvent = {
|
|
4531
|
+
transcriptionerror: "transcription.error"
|
|
4532
|
+
};
|
|
4533
|
+
|
|
4534
|
+
// src/generated/gladia/schema/webhookTranscriptionSuccessPayloadEvent.ts
|
|
4535
|
+
var WebhookTranscriptionSuccessPayloadEvent = {
|
|
4536
|
+
transcriptionsuccess: "transcription.success"
|
|
4537
|
+
};
|
|
4538
|
+
|
|
4539
|
+
// src/generated/assemblyai/schema/index.ts
|
|
4540
|
+
var schema_exports2 = {};
|
|
4541
|
+
__export(schema_exports2, {
|
|
4542
|
+
AudioIntelligenceModelStatus: () => AudioIntelligenceModelStatus,
|
|
4543
|
+
EntityType: () => EntityType,
|
|
4544
|
+
LemurModel: () => LemurModel,
|
|
4545
|
+
PiiPolicy: () => PiiPolicy,
|
|
4546
|
+
RedactPiiAudioQuality: () => RedactPiiAudioQuality,
|
|
4547
|
+
RedactedAudioStatus: () => RedactedAudioStatus,
|
|
4548
|
+
Sentiment: () => Sentiment,
|
|
4549
|
+
SpeechModel: () => SpeechModel,
|
|
4550
|
+
SubstitutionPolicy: () => SubstitutionPolicy,
|
|
4551
|
+
SubtitleFormat: () => SubtitleFormat,
|
|
4552
|
+
SummaryModel: () => SummaryModel,
|
|
4553
|
+
SummaryType: () => SummaryType,
|
|
4554
|
+
TranscriptBoostParam: () => TranscriptBoostParam,
|
|
4555
|
+
TranscriptLanguageCode: () => TranscriptLanguageCode,
|
|
4556
|
+
TranscriptReadyStatus: () => TranscriptReadyStatus,
|
|
4557
|
+
TranscriptStatus: () => TranscriptStatus
|
|
4558
|
+
});
|
|
4559
|
+
|
|
4560
|
+
// src/generated/assemblyai/schema/audioIntelligenceModelStatus.ts
|
|
4561
|
+
var AudioIntelligenceModelStatus = {
|
|
4562
|
+
success: "success",
|
|
4563
|
+
unavailable: "unavailable"
|
|
4564
|
+
};
|
|
4565
|
+
|
|
4566
|
+
// src/generated/assemblyai/schema/entityType.ts
|
|
4567
|
+
var EntityType = {
|
|
4568
|
+
account_number: "account_number",
|
|
4569
|
+
banking_information: "banking_information",
|
|
4570
|
+
blood_type: "blood_type",
|
|
4571
|
+
credit_card_cvv: "credit_card_cvv",
|
|
4572
|
+
credit_card_expiration: "credit_card_expiration",
|
|
4573
|
+
credit_card_number: "credit_card_number",
|
|
4574
|
+
date: "date",
|
|
4575
|
+
date_interval: "date_interval",
|
|
4576
|
+
date_of_birth: "date_of_birth",
|
|
4577
|
+
drivers_license: "drivers_license",
|
|
4578
|
+
drug: "drug",
|
|
4579
|
+
duration: "duration",
|
|
4580
|
+
email_address: "email_address",
|
|
4581
|
+
event: "event",
|
|
4582
|
+
filename: "filename",
|
|
4583
|
+
gender_sexuality: "gender_sexuality",
|
|
4584
|
+
healthcare_number: "healthcare_number",
|
|
4585
|
+
injury: "injury",
|
|
4586
|
+
ip_address: "ip_address",
|
|
4587
|
+
language: "language",
|
|
4588
|
+
location: "location",
|
|
4589
|
+
marital_status: "marital_status",
|
|
4590
|
+
medical_condition: "medical_condition",
|
|
4591
|
+
medical_process: "medical_process",
|
|
4592
|
+
money_amount: "money_amount",
|
|
4593
|
+
nationality: "nationality",
|
|
4594
|
+
number_sequence: "number_sequence",
|
|
4595
|
+
occupation: "occupation",
|
|
4596
|
+
organization: "organization",
|
|
4597
|
+
passport_number: "passport_number",
|
|
4598
|
+
password: "password",
|
|
4599
|
+
person_age: "person_age",
|
|
4600
|
+
person_name: "person_name",
|
|
4601
|
+
phone_number: "phone_number",
|
|
4602
|
+
physical_attribute: "physical_attribute",
|
|
4603
|
+
political_affiliation: "political_affiliation",
|
|
4604
|
+
religion: "religion",
|
|
4605
|
+
statistics: "statistics",
|
|
4606
|
+
time: "time",
|
|
4607
|
+
url: "url",
|
|
4608
|
+
us_social_security_number: "us_social_security_number",
|
|
4609
|
+
username: "username",
|
|
4610
|
+
vehicle_id: "vehicle_id",
|
|
4611
|
+
zodiac_sign: "zodiac_sign"
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
// src/generated/assemblyai/schema/lemurModel.ts
|
|
4615
|
+
var LemurModel = {
|
|
4616
|
+
"anthropic/claude-3-5-sonnet": "anthropic/claude-3-5-sonnet",
|
|
4617
|
+
"anthropic/claude-3-opus": "anthropic/claude-3-opus",
|
|
4618
|
+
"anthropic/claude-3-haiku": "anthropic/claude-3-haiku"
|
|
4619
|
+
};
|
|
4620
|
+
|
|
4621
|
+
// src/generated/assemblyai/schema/piiPolicy.ts
|
|
4622
|
+
var PiiPolicy = {
|
|
4623
|
+
account_number: "account_number",
|
|
4624
|
+
banking_information: "banking_information",
|
|
4625
|
+
blood_type: "blood_type",
|
|
4626
|
+
credit_card_cvv: "credit_card_cvv",
|
|
4627
|
+
credit_card_expiration: "credit_card_expiration",
|
|
4628
|
+
credit_card_number: "credit_card_number",
|
|
4629
|
+
date: "date",
|
|
4630
|
+
date_interval: "date_interval",
|
|
4631
|
+
date_of_birth: "date_of_birth",
|
|
4632
|
+
drivers_license: "drivers_license",
|
|
4633
|
+
drug: "drug",
|
|
4634
|
+
duration: "duration",
|
|
4635
|
+
email_address: "email_address",
|
|
4636
|
+
event: "event",
|
|
4637
|
+
filename: "filename",
|
|
4638
|
+
gender_sexuality: "gender_sexuality",
|
|
4639
|
+
healthcare_number: "healthcare_number",
|
|
4640
|
+
injury: "injury",
|
|
4641
|
+
ip_address: "ip_address",
|
|
4642
|
+
language: "language",
|
|
4643
|
+
location: "location",
|
|
4644
|
+
marital_status: "marital_status",
|
|
4645
|
+
medical_condition: "medical_condition",
|
|
4646
|
+
medical_process: "medical_process",
|
|
4647
|
+
money_amount: "money_amount",
|
|
4648
|
+
nationality: "nationality",
|
|
4649
|
+
number_sequence: "number_sequence",
|
|
4650
|
+
occupation: "occupation",
|
|
4651
|
+
organization: "organization",
|
|
4652
|
+
passport_number: "passport_number",
|
|
4653
|
+
password: "password",
|
|
4654
|
+
person_age: "person_age",
|
|
4655
|
+
person_name: "person_name",
|
|
4656
|
+
phone_number: "phone_number",
|
|
4657
|
+
physical_attribute: "physical_attribute",
|
|
4658
|
+
political_affiliation: "political_affiliation",
|
|
4659
|
+
religion: "religion",
|
|
4660
|
+
statistics: "statistics",
|
|
4661
|
+
time: "time",
|
|
4662
|
+
url: "url",
|
|
4663
|
+
us_social_security_number: "us_social_security_number",
|
|
4664
|
+
username: "username",
|
|
4665
|
+
vehicle_id: "vehicle_id",
|
|
4666
|
+
zodiac_sign: "zodiac_sign"
|
|
4667
|
+
};
|
|
4668
|
+
|
|
4669
|
+
// src/generated/assemblyai/schema/redactPiiAudioQuality.ts
|
|
4670
|
+
var RedactPiiAudioQuality = {
|
|
4671
|
+
mp3: "mp3",
|
|
4672
|
+
wav: "wav"
|
|
4673
|
+
};
|
|
4674
|
+
|
|
4675
|
+
// src/generated/assemblyai/schema/redactedAudioStatus.ts
|
|
4676
|
+
var RedactedAudioStatus = {
|
|
4677
|
+
redacted_audio_ready: "redacted_audio_ready"
|
|
4678
|
+
};
|
|
4679
|
+
|
|
4680
|
+
// src/generated/assemblyai/schema/sentiment.ts
|
|
4681
|
+
var Sentiment = {
|
|
4682
|
+
POSITIVE: "POSITIVE",
|
|
4683
|
+
NEUTRAL: "NEUTRAL",
|
|
4684
|
+
NEGATIVE: "NEGATIVE"
|
|
4685
|
+
};
|
|
4686
|
+
|
|
4687
|
+
// src/generated/assemblyai/schema/speechModel.ts
|
|
4688
|
+
var SpeechModel = {
|
|
4689
|
+
best: "best",
|
|
4690
|
+
"slam-1": "slam-1",
|
|
4691
|
+
universal: "universal"
|
|
4692
|
+
};
|
|
4693
|
+
|
|
4694
|
+
// src/generated/assemblyai/schema/substitutionPolicy.ts
|
|
4695
|
+
var SubstitutionPolicy = {
|
|
4696
|
+
entity_name: "entity_name",
|
|
4697
|
+
hash: "hash"
|
|
4698
|
+
};
|
|
4699
|
+
|
|
4700
|
+
// src/generated/assemblyai/schema/subtitleFormat.ts
|
|
4701
|
+
var SubtitleFormat = {
|
|
4702
|
+
srt: "srt",
|
|
4703
|
+
vtt: "vtt"
|
|
4704
|
+
};
|
|
4705
|
+
|
|
4706
|
+
// src/generated/assemblyai/schema/summaryModel.ts
|
|
4707
|
+
var SummaryModel = {
|
|
4708
|
+
informative: "informative",
|
|
4709
|
+
conversational: "conversational",
|
|
4710
|
+
catchy: "catchy"
|
|
4711
|
+
};
|
|
4712
|
+
|
|
4713
|
+
// src/generated/assemblyai/schema/summaryType.ts
|
|
4714
|
+
var SummaryType = {
|
|
4715
|
+
bullets: "bullets",
|
|
4716
|
+
bullets_verbose: "bullets_verbose",
|
|
4717
|
+
gist: "gist",
|
|
4718
|
+
headline: "headline",
|
|
4719
|
+
paragraph: "paragraph"
|
|
4720
|
+
};
|
|
4721
|
+
|
|
4722
|
+
// src/generated/assemblyai/schema/transcriptBoostParam.ts
|
|
4723
|
+
var TranscriptBoostParam = {
|
|
4724
|
+
low: "low",
|
|
4725
|
+
default: "default",
|
|
4726
|
+
high: "high"
|
|
4727
|
+
};
|
|
4728
|
+
|
|
4729
|
+
// src/generated/assemblyai/schema/transcriptLanguageCode.ts
|
|
4730
|
+
var TranscriptLanguageCode = {
|
|
4731
|
+
en: "en",
|
|
4732
|
+
en_au: "en_au",
|
|
4733
|
+
en_uk: "en_uk",
|
|
4734
|
+
en_us: "en_us",
|
|
4735
|
+
es: "es",
|
|
4736
|
+
fr: "fr",
|
|
4737
|
+
de: "de",
|
|
4738
|
+
it: "it",
|
|
4739
|
+
pt: "pt",
|
|
4740
|
+
nl: "nl",
|
|
4741
|
+
af: "af",
|
|
4742
|
+
sq: "sq",
|
|
4743
|
+
am: "am",
|
|
4744
|
+
ar: "ar",
|
|
4745
|
+
hy: "hy",
|
|
4746
|
+
as: "as",
|
|
4747
|
+
az: "az",
|
|
4748
|
+
ba: "ba",
|
|
4749
|
+
eu: "eu",
|
|
4750
|
+
be: "be",
|
|
4751
|
+
bn: "bn",
|
|
4752
|
+
bs: "bs",
|
|
4753
|
+
br: "br",
|
|
4754
|
+
bg: "bg",
|
|
4755
|
+
my: "my",
|
|
4756
|
+
ca: "ca",
|
|
4757
|
+
zh: "zh",
|
|
4758
|
+
hr: "hr",
|
|
4759
|
+
cs: "cs",
|
|
4760
|
+
da: "da",
|
|
4761
|
+
et: "et",
|
|
4762
|
+
fo: "fo",
|
|
4763
|
+
fi: "fi",
|
|
4764
|
+
gl: "gl",
|
|
4765
|
+
ka: "ka",
|
|
4766
|
+
el: "el",
|
|
4767
|
+
gu: "gu",
|
|
4768
|
+
ht: "ht",
|
|
4769
|
+
ha: "ha",
|
|
4770
|
+
haw: "haw",
|
|
4771
|
+
he: "he",
|
|
4772
|
+
hi: "hi",
|
|
4773
|
+
hu: "hu",
|
|
4774
|
+
is: "is",
|
|
4775
|
+
id: "id",
|
|
4776
|
+
ja: "ja",
|
|
4777
|
+
jw: "jw",
|
|
4778
|
+
kn: "kn",
|
|
4779
|
+
kk: "kk",
|
|
4780
|
+
km: "km",
|
|
4781
|
+
ko: "ko",
|
|
4782
|
+
lo: "lo",
|
|
4783
|
+
la: "la",
|
|
4784
|
+
lv: "lv",
|
|
4785
|
+
ln: "ln",
|
|
4786
|
+
lt: "lt",
|
|
4787
|
+
lb: "lb",
|
|
4788
|
+
mk: "mk",
|
|
4789
|
+
mg: "mg",
|
|
4790
|
+
ms: "ms",
|
|
4791
|
+
ml: "ml",
|
|
4792
|
+
mt: "mt",
|
|
4793
|
+
mi: "mi",
|
|
4794
|
+
mr: "mr",
|
|
4795
|
+
mn: "mn",
|
|
4796
|
+
ne: "ne",
|
|
4797
|
+
no: "no",
|
|
4798
|
+
nn: "nn",
|
|
4799
|
+
oc: "oc",
|
|
4800
|
+
pa: "pa",
|
|
4801
|
+
ps: "ps",
|
|
4802
|
+
fa: "fa",
|
|
4803
|
+
pl: "pl",
|
|
4804
|
+
ro: "ro",
|
|
4805
|
+
ru: "ru",
|
|
4806
|
+
sa: "sa",
|
|
4807
|
+
sr: "sr",
|
|
4808
|
+
sn: "sn",
|
|
4809
|
+
sd: "sd",
|
|
4810
|
+
si: "si",
|
|
4811
|
+
sk: "sk",
|
|
4812
|
+
sl: "sl",
|
|
4813
|
+
so: "so",
|
|
4814
|
+
su: "su",
|
|
4815
|
+
sw: "sw",
|
|
4816
|
+
sv: "sv",
|
|
4817
|
+
tl: "tl",
|
|
4818
|
+
tg: "tg",
|
|
4819
|
+
ta: "ta",
|
|
4820
|
+
tt: "tt",
|
|
4821
|
+
te: "te",
|
|
4822
|
+
th: "th",
|
|
4823
|
+
bo: "bo",
|
|
4824
|
+
tr: "tr",
|
|
4825
|
+
tk: "tk",
|
|
4826
|
+
uk: "uk",
|
|
4827
|
+
ur: "ur",
|
|
4828
|
+
uz: "uz",
|
|
4829
|
+
vi: "vi",
|
|
4830
|
+
cy: "cy",
|
|
4831
|
+
yi: "yi",
|
|
4832
|
+
yo: "yo"
|
|
4833
|
+
};
|
|
4834
|
+
|
|
4835
|
+
// src/generated/assemblyai/schema/transcriptReadyStatus.ts
|
|
4836
|
+
var TranscriptReadyStatus = {
|
|
4837
|
+
completed: "completed",
|
|
4838
|
+
error: "error"
|
|
4839
|
+
};
|
|
4840
|
+
|
|
4841
|
+
// src/generated/assemblyai/schema/transcriptStatus.ts
|
|
4842
|
+
var TranscriptStatus = {
|
|
4843
|
+
queued: "queued",
|
|
4844
|
+
processing: "processing",
|
|
4845
|
+
completed: "completed",
|
|
4846
|
+
error: "error"
|
|
4847
|
+
};
|
|
4848
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4849
|
+
0 && (module.exports = {
|
|
4850
|
+
AssemblyAIAdapter,
|
|
4851
|
+
AssemblyAITypes,
|
|
4852
|
+
AssemblyAIWebhookHandler,
|
|
4853
|
+
AzureSTTAdapter,
|
|
4854
|
+
AzureWebhookHandler,
|
|
4855
|
+
BaseAdapter,
|
|
4856
|
+
BaseWebhookHandler,
|
|
4857
|
+
DeepgramAdapter,
|
|
4858
|
+
DeepgramWebhookHandler,
|
|
4859
|
+
GladiaAdapter,
|
|
4860
|
+
GladiaTypes,
|
|
4861
|
+
GladiaWebhookHandler,
|
|
4862
|
+
OpenAIWhisperAdapter,
|
|
4863
|
+
SpeechmaticsAdapter,
|
|
4864
|
+
SpeechmaticsWebhookHandler,
|
|
4865
|
+
VoiceRouter,
|
|
4866
|
+
WebhookRouter,
|
|
4867
|
+
createAssemblyAIAdapter,
|
|
4868
|
+
createAssemblyAIWebhookHandler,
|
|
4869
|
+
createAzureSTTAdapter,
|
|
4870
|
+
createAzureWebhookHandler,
|
|
4871
|
+
createDeepgramAdapter,
|
|
4872
|
+
createDeepgramWebhookHandler,
|
|
4873
|
+
createGladiaAdapter,
|
|
4874
|
+
createGladiaWebhookHandler,
|
|
4875
|
+
createOpenAIWhisperAdapter,
|
|
4876
|
+
createSpeechmaticsAdapter,
|
|
4877
|
+
createVoiceRouter,
|
|
4878
|
+
createWebhookRouter
|
|
4879
|
+
});
|
|
4880
|
+
//# sourceMappingURL=index.js.map
|