@ai-sdk/assemblyai 2.0.41 → 2.0.43
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/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/dist/index.d.mts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +242 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +242 -25
- package/dist/index.mjs.map +1 -1
- package/docs/100-assemblyai.mdx +134 -9
- package/package.json +2 -2
- package/src/assemblyai-api-types.ts +84 -1
- package/src/assemblyai-provider.ts +1 -1
- package/src/assemblyai-transcription-model.ts +326 -19
- package/src/assemblyai-transcription-settings.ts +15 -1
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
TranscriptionModelV3,
|
|
3
|
+
SharedV3Warning,
|
|
4
|
+
SharedV3ProviderMetadata,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
2
6
|
import {
|
|
3
7
|
combineHeaders,
|
|
4
8
|
createJsonResponseHandler,
|
|
@@ -32,8 +36,12 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
32
36
|
*/
|
|
33
37
|
autoHighlights: z.boolean().nullish(),
|
|
34
38
|
/**
|
|
35
|
-
* Boost parameter for
|
|
39
|
+
* Boost parameter for word boost (used with `wordBoost`).
|
|
36
40
|
* Allowed values: 'low', 'default', 'high'.
|
|
41
|
+
*
|
|
42
|
+
* @deprecated Only applies to the deprecated `wordBoost` option. Use
|
|
43
|
+
* `keytermsPrompt` instead, which works with the recommended `universal-*`
|
|
44
|
+
* models.
|
|
37
45
|
*/
|
|
38
46
|
boostParam: z.string().nullish(),
|
|
39
47
|
/**
|
|
@@ -59,6 +67,11 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
59
67
|
* Whether to include filler words (um, uh, etc.) in the transcription.
|
|
60
68
|
*/
|
|
61
69
|
disfluencies: z.boolean().nullish(),
|
|
70
|
+
/**
|
|
71
|
+
* Enable a domain-specific model to improve accuracy for specialized
|
|
72
|
+
* terminology. Currently supports `'medical-v1'` (Medical Mode).
|
|
73
|
+
*/
|
|
74
|
+
domain: z.string().nullish(),
|
|
62
75
|
/**
|
|
63
76
|
* Whether to enable entity detection.
|
|
64
77
|
*/
|
|
@@ -75,6 +88,13 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
75
88
|
* Whether to enable IAB categories detection.
|
|
76
89
|
*/
|
|
77
90
|
iabCategories: z.boolean().nullish(),
|
|
91
|
+
/**
|
|
92
|
+
* Domain-specific keyterms to boost recognition for (max 6 words per phrase).
|
|
93
|
+
* Replaces `wordBoost` for newer models: supported by `universal-3-pro` /
|
|
94
|
+
* `universal-3-5-pro` and `slam-1` (and `universal-2` when metaphone is
|
|
95
|
+
* enabled for the account).
|
|
96
|
+
*/
|
|
97
|
+
keytermsPrompt: z.array(z.string()).nullish(),
|
|
78
98
|
/**
|
|
79
99
|
* Language code for the transcription.
|
|
80
100
|
*/
|
|
@@ -87,10 +107,30 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
87
107
|
* Whether to enable language detection.
|
|
88
108
|
*/
|
|
89
109
|
languageDetection: z.boolean().nullish(),
|
|
110
|
+
/**
|
|
111
|
+
* Options for automatic language detection.
|
|
112
|
+
*/
|
|
113
|
+
languageDetectionOptions: z
|
|
114
|
+
.object({
|
|
115
|
+
/** List of languages expected in the audio file. */
|
|
116
|
+
expectedLanguages: z.array(z.string()).nullish(),
|
|
117
|
+
/** Fallback language if the detected language is not expected. */
|
|
118
|
+
fallbackLanguage: z.string().nullish(),
|
|
119
|
+
/** Whether code switching should be detected. */
|
|
120
|
+
codeSwitching: z.boolean().nullish(),
|
|
121
|
+
/** Confidence threshold for code switching detection (0-1). */
|
|
122
|
+
codeSwitchingConfidenceThreshold: z.number().min(0).max(1).nullish(),
|
|
123
|
+
})
|
|
124
|
+
.nullish(),
|
|
90
125
|
/**
|
|
91
126
|
* Whether to process audio as multichannel.
|
|
92
127
|
*/
|
|
93
128
|
multichannel: z.boolean().nullish(),
|
|
129
|
+
/**
|
|
130
|
+
* Provide natural-language context (up to 1,500 words) to steer the model.
|
|
131
|
+
* Only supported by `universal-3-pro` / `universal-3-5-pro` and `slam-1`.
|
|
132
|
+
*/
|
|
133
|
+
prompt: z.string().nullish(),
|
|
94
134
|
/**
|
|
95
135
|
* Whether to add punctuation to the transcription.
|
|
96
136
|
*/
|
|
@@ -103,6 +143,17 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
103
143
|
* Whether to redact PII in the audio file.
|
|
104
144
|
*/
|
|
105
145
|
redactPiiAudio: z.boolean().nullish(),
|
|
146
|
+
/**
|
|
147
|
+
* Options for PII-redacted audio files. Requires `redactPiiAudio`.
|
|
148
|
+
*/
|
|
149
|
+
redactPiiAudioOptions: z
|
|
150
|
+
.object({
|
|
151
|
+
/** Return redacted audio even for files without detected speech. */
|
|
152
|
+
returnRedactedNoSpeechAudio: z.boolean().nullish(),
|
|
153
|
+
/** Redaction method; set to `'silence'` to replace PII with silence. */
|
|
154
|
+
overrideAudioRedactionMethod: z.enum(['silence']).nullish(),
|
|
155
|
+
})
|
|
156
|
+
.nullish(),
|
|
106
157
|
/**
|
|
107
158
|
* Audio format for PII redaction.
|
|
108
159
|
*/
|
|
@@ -111,10 +162,26 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
111
162
|
* List of PII types to redact.
|
|
112
163
|
*/
|
|
113
164
|
redactPiiPolicies: z.array(z.string()).nullish(),
|
|
165
|
+
/**
|
|
166
|
+
* Return the original unredacted transcript alongside the redacted one.
|
|
167
|
+
* Requires `redactPii`.
|
|
168
|
+
*/
|
|
169
|
+
redactPiiReturnUnredacted: z.boolean().nullish(),
|
|
114
170
|
/**
|
|
115
171
|
* Substitution method for redacted PII.
|
|
116
172
|
*/
|
|
117
173
|
redactPiiSub: z.string().nullish(),
|
|
174
|
+
/**
|
|
175
|
+
* Map of user-defined labels to exact terms to redact, e.g.
|
|
176
|
+
* `{ INTERNAL_TOOL: ['Bearclaw'] }`. Applied on top of standard PII redaction
|
|
177
|
+
* using `redactPiiSub`. Requires `redactPii`.
|
|
178
|
+
*/
|
|
179
|
+
redactStaticEntities: z.record(z.string(), z.array(z.string())).nullish(),
|
|
180
|
+
/**
|
|
181
|
+
* Remove inline annotations from rich transcripts. `'all'` removes all inline
|
|
182
|
+
* annotations; `'speaker'` removes only speaker cues. Universal-3 Pro models.
|
|
183
|
+
*/
|
|
184
|
+
removeAudioTags: z.enum(['all', 'speaker']).nullish(),
|
|
118
185
|
/**
|
|
119
186
|
* Whether to enable sentiment analysis.
|
|
120
187
|
*/
|
|
@@ -123,6 +190,17 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
123
190
|
* Whether to identify different speakers in the audio.
|
|
124
191
|
*/
|
|
125
192
|
speakerLabels: z.boolean().nullish(),
|
|
193
|
+
/**
|
|
194
|
+
* Options for speaker diarization, e.g. a range of possible speakers.
|
|
195
|
+
*/
|
|
196
|
+
speakerOptions: z
|
|
197
|
+
.object({
|
|
198
|
+
/** Minimum number of speakers expected in the audio file. */
|
|
199
|
+
minSpeakersExpected: z.number().int().nullish(),
|
|
200
|
+
/** Maximum number of speakers expected in the audio file. */
|
|
201
|
+
maxSpeakersExpected: z.number().int().nullish(),
|
|
202
|
+
})
|
|
203
|
+
.nullish(),
|
|
126
204
|
/**
|
|
127
205
|
* Number of speakers expected in the audio.
|
|
128
206
|
*/
|
|
@@ -143,6 +221,10 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
143
221
|
* Type of summary to generate.
|
|
144
222
|
*/
|
|
145
223
|
summaryType: z.string().nullish(),
|
|
224
|
+
/**
|
|
225
|
+
* Sampling temperature (0-1) controlling randomness. Universal-3 Pro models.
|
|
226
|
+
*/
|
|
227
|
+
temperature: z.number().min(0).max(1).nullish(),
|
|
146
228
|
/**
|
|
147
229
|
* Name of the authentication header for webhook requests.
|
|
148
230
|
*/
|
|
@@ -157,6 +239,10 @@ const assemblyaiTranscriptionModelOptionsSchema = z.object({
|
|
|
157
239
|
webhookUrl: z.string().nullish(),
|
|
158
240
|
/**
|
|
159
241
|
* List of words to boost recognition for.
|
|
242
|
+
*
|
|
243
|
+
* @deprecated `wordBoost` is rejected by `universal-3-pro` /
|
|
244
|
+
* `universal-3-5-pro` and `slam-1` (it only works on `universal-2`/`best`).
|
|
245
|
+
* Use `keytermsPrompt` instead.
|
|
160
246
|
*/
|
|
161
247
|
wordBoost: z.array(z.string()).nullish(),
|
|
162
248
|
});
|
|
@@ -200,9 +286,41 @@ export class AssemblyAITranscriptionModel implements TranscriptionModelV3 {
|
|
|
200
286
|
schema: assemblyaiTranscriptionModelOptionsSchema,
|
|
201
287
|
});
|
|
202
288
|
|
|
203
|
-
const body: Omit<AssemblyAITranscriptionAPITypes, 'audio_url'> = {
|
|
204
|
-
|
|
205
|
-
|
|
289
|
+
const body: Omit<AssemblyAITranscriptionAPITypes, 'audio_url'> = {};
|
|
290
|
+
|
|
291
|
+
// The legacy `best` model is selected via the deprecated singular
|
|
292
|
+
// `speech_model` parameter. All other models (e.g. `universal-2`,
|
|
293
|
+
// `universal-3-pro`, `universal-3-5-pro`) are only accessible via the
|
|
294
|
+
// `speech_models` array and are rejected by `speech_model`.
|
|
295
|
+
// See https://www.assemblyai.com/docs/pre-recorded-audio/select-the-speech-model
|
|
296
|
+
if (this.modelId === 'best') {
|
|
297
|
+
body.speech_model = this.modelId as 'best';
|
|
298
|
+
warnings.push({
|
|
299
|
+
type: 'other',
|
|
300
|
+
message:
|
|
301
|
+
"The 'best' model is a legacy AssemblyAI model. Use 'universal-3-5-pro' instead. See documentation: https://www.assemblyai.com/docs/pre-recorded-audio/select-the-speech-model",
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
body.speech_models = [this.modelId];
|
|
305
|
+
|
|
306
|
+
// Forward-looking nudge: universal-3-5-pro is AssemblyAI's latest
|
|
307
|
+
// flagship and is set to replace universal-3-pro. Not a deprecation —
|
|
308
|
+
// both models still work — so this is an informational warning only.
|
|
309
|
+
if (
|
|
310
|
+
this.modelId === 'universal-3-pro' ||
|
|
311
|
+
this.modelId === 'universal-2'
|
|
312
|
+
) {
|
|
313
|
+
const docsUrl =
|
|
314
|
+
'https://www.assemblyai.com/docs/pre-recorded-audio/select-the-speech-model';
|
|
315
|
+
warnings.push({
|
|
316
|
+
type: 'other',
|
|
317
|
+
message:
|
|
318
|
+
this.modelId === 'universal-3-pro'
|
|
319
|
+
? `'universal-3-5-pro' is AssemblyAI's latest flagship model and is set to replace 'universal-3-pro'. See ${docsUrl}`
|
|
320
|
+
: `'universal-3-5-pro' is AssemblyAI's latest flagship model. See ${docsUrl}`,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
206
324
|
|
|
207
325
|
// Add provider-specific options
|
|
208
326
|
if (assemblyaiOptions) {
|
|
@@ -252,6 +370,103 @@ export class AssemblyAITranscriptionModel implements TranscriptionModelV3 {
|
|
|
252
370
|
assemblyaiOptions.webhookAuthHeaderValue ?? undefined;
|
|
253
371
|
body.webhook_url = assemblyaiOptions.webhookUrl ?? undefined;
|
|
254
372
|
body.word_boost = assemblyaiOptions.wordBoost ?? undefined;
|
|
373
|
+
body.keyterms_prompt = assemblyaiOptions.keytermsPrompt ?? undefined;
|
|
374
|
+
body.prompt = assemblyaiOptions.prompt ?? undefined;
|
|
375
|
+
body.temperature = assemblyaiOptions.temperature ?? undefined;
|
|
376
|
+
body.remove_audio_tags = assemblyaiOptions.removeAudioTags ?? undefined;
|
|
377
|
+
body.domain = assemblyaiOptions.domain ?? undefined;
|
|
378
|
+
body.redact_pii_return_unredacted =
|
|
379
|
+
assemblyaiOptions.redactPiiReturnUnredacted ?? undefined;
|
|
380
|
+
body.redact_static_entities =
|
|
381
|
+
assemblyaiOptions.redactStaticEntities ?? undefined;
|
|
382
|
+
|
|
383
|
+
if (assemblyaiOptions.speakerOptions) {
|
|
384
|
+
body.speaker_options = {
|
|
385
|
+
min_speakers_expected:
|
|
386
|
+
assemblyaiOptions.speakerOptions.minSpeakersExpected ?? undefined,
|
|
387
|
+
max_speakers_expected:
|
|
388
|
+
assemblyaiOptions.speakerOptions.maxSpeakersExpected ?? undefined,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (assemblyaiOptions.languageDetectionOptions) {
|
|
393
|
+
body.language_detection_options = {
|
|
394
|
+
expected_languages:
|
|
395
|
+
assemblyaiOptions.languageDetectionOptions.expectedLanguages ??
|
|
396
|
+
undefined,
|
|
397
|
+
fallback_language:
|
|
398
|
+
assemblyaiOptions.languageDetectionOptions.fallbackLanguage ??
|
|
399
|
+
undefined,
|
|
400
|
+
code_switching:
|
|
401
|
+
assemblyaiOptions.languageDetectionOptions.codeSwitching ??
|
|
402
|
+
undefined,
|
|
403
|
+
code_switching_confidence_threshold:
|
|
404
|
+
assemblyaiOptions.languageDetectionOptions
|
|
405
|
+
.codeSwitchingConfidenceThreshold ?? undefined,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (assemblyaiOptions.redactPiiAudioOptions) {
|
|
410
|
+
body.redact_pii_audio_options = {
|
|
411
|
+
return_redacted_no_speech_audio:
|
|
412
|
+
assemblyaiOptions.redactPiiAudioOptions
|
|
413
|
+
.returnRedactedNoSpeechAudio ?? undefined,
|
|
414
|
+
override_audio_redaction_method:
|
|
415
|
+
assemblyaiOptions.redactPiiAudioOptions
|
|
416
|
+
.overrideAudioRedactionMethod ?? undefined,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const deprecatedBoostOptions: string[] = [];
|
|
421
|
+
if (assemblyaiOptions.wordBoost != null) {
|
|
422
|
+
deprecatedBoostOptions.push('wordBoost');
|
|
423
|
+
}
|
|
424
|
+
if (assemblyaiOptions.boostParam != null) {
|
|
425
|
+
deprecatedBoostOptions.push('boostParam');
|
|
426
|
+
}
|
|
427
|
+
if (deprecatedBoostOptions.length > 0) {
|
|
428
|
+
warnings.push({
|
|
429
|
+
type: 'other',
|
|
430
|
+
message: `${deprecatedBoostOptions.join(', ')} ${
|
|
431
|
+
deprecatedBoostOptions.length > 1 ? 'are' : 'is'
|
|
432
|
+
} deprecated and rejected by 'universal-3-pro' / 'universal-3-5-pro' and 'slam-1'. Use 'keytermsPrompt' instead.`,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// The following options only take effect alongside a prerequisite
|
|
437
|
+
// option; without it AssemblyAI either rejects the request (400) or
|
|
438
|
+
// silently ignores the option. Warn rather than mutate user input.
|
|
439
|
+
if (
|
|
440
|
+
(assemblyaiOptions.redactPiiReturnUnredacted != null ||
|
|
441
|
+
assemblyaiOptions.redactStaticEntities != null) &&
|
|
442
|
+
!assemblyaiOptions.redactPii
|
|
443
|
+
) {
|
|
444
|
+
warnings.push({
|
|
445
|
+
type: 'other',
|
|
446
|
+
message:
|
|
447
|
+
"'redactPiiReturnUnredacted' and 'redactStaticEntities' require 'redactPii' to be enabled; AssemblyAI rejects the request otherwise.",
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
if (
|
|
451
|
+
assemblyaiOptions.redactPiiAudioOptions != null &&
|
|
452
|
+
!assemblyaiOptions.redactPiiAudio
|
|
453
|
+
) {
|
|
454
|
+
warnings.push({
|
|
455
|
+
type: 'other',
|
|
456
|
+
message:
|
|
457
|
+
"'redactPiiAudioOptions' only applies when 'redactPiiAudio' is enabled; it is otherwise ignored.",
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
if (
|
|
461
|
+
assemblyaiOptions.languageCode != null &&
|
|
462
|
+
assemblyaiOptions.languageDetection
|
|
463
|
+
) {
|
|
464
|
+
warnings.push({
|
|
465
|
+
type: 'other',
|
|
466
|
+
message:
|
|
467
|
+
"'languageDetection' cannot be combined with an explicit 'languageCode'; AssemblyAI rejects requests that set both.",
|
|
468
|
+
});
|
|
469
|
+
}
|
|
255
470
|
}
|
|
256
471
|
|
|
257
472
|
return {
|
|
@@ -271,17 +486,22 @@ export class AssemblyAITranscriptionModel implements TranscriptionModelV3 {
|
|
|
271
486
|
abortSignal?: AbortSignal,
|
|
272
487
|
): Promise<{
|
|
273
488
|
transcript: z.infer<typeof assemblyaiTranscriptionResponseSchema>;
|
|
489
|
+
rawTranscript: unknown;
|
|
274
490
|
responseHeaders: Record<string, string>;
|
|
275
491
|
}> {
|
|
276
492
|
const pollingInterval =
|
|
277
493
|
this.config.pollingInterval ?? this.POLLING_INTERVAL_MS;
|
|
278
494
|
|
|
495
|
+
// Honor a caller-provided fetch (proxy, auth injection, tests) for the
|
|
496
|
+
// polling GETs, matching the upload/submit calls that use config.fetch.
|
|
497
|
+
const fetchImpl = this.config.fetch ?? globalThis.fetch;
|
|
498
|
+
|
|
279
499
|
while (true) {
|
|
280
500
|
if (abortSignal?.aborted) {
|
|
281
501
|
throw new Error('Transcription request was aborted');
|
|
282
502
|
}
|
|
283
503
|
|
|
284
|
-
const response = await
|
|
504
|
+
const response = await fetchImpl(
|
|
285
505
|
this.config.url({
|
|
286
506
|
path: `/v2/transcript/${transcriptId}`,
|
|
287
507
|
modelId: this.modelId,
|
|
@@ -307,13 +527,14 @@ export class AssemblyAITranscriptionModel implements TranscriptionModelV3 {
|
|
|
307
527
|
});
|
|
308
528
|
}
|
|
309
529
|
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
530
|
+
const rawTranscript = await response.json();
|
|
531
|
+
const transcript =
|
|
532
|
+
assemblyaiTranscriptionResponseSchema.parse(rawTranscript);
|
|
313
533
|
|
|
314
534
|
if (transcript.status === 'completed') {
|
|
315
535
|
return {
|
|
316
536
|
transcript,
|
|
537
|
+
rawTranscript,
|
|
317
538
|
responseHeaders: extractResponseHeaders(response),
|
|
318
539
|
};
|
|
319
540
|
}
|
|
@@ -374,29 +595,70 @@ export class AssemblyAITranscriptionModel implements TranscriptionModelV3 {
|
|
|
374
595
|
fetch: this.config.fetch,
|
|
375
596
|
});
|
|
376
597
|
|
|
377
|
-
const { transcript, responseHeaders } =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
598
|
+
const { transcript, rawTranscript, responseHeaders } =
|
|
599
|
+
await this.waitForCompletion(
|
|
600
|
+
submitResponse.id,
|
|
601
|
+
options.headers,
|
|
602
|
+
options.abortSignal,
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
// Surface diarization and audio-intelligence results that the AI SDK's
|
|
606
|
+
// `segments` shape can't represent, keyed under `assemblyai`. Presence is
|
|
607
|
+
// gated on the parsed transcript, but values are taken from the raw
|
|
608
|
+
// response so no fields are stripped by the schema.
|
|
609
|
+
//
|
|
610
|
+
// NOTE: timings inside these objects (e.g. `utterances[].start`) are in
|
|
611
|
+
// milliseconds, matching the AssemblyAI API — unlike the top-level
|
|
612
|
+
// `segments`, whose `startSecond`/`endSecond` are in seconds.
|
|
613
|
+
const raw = (rawTranscript ?? {}) as Record<string, unknown>;
|
|
614
|
+
const assemblyaiMetadata: Record<string, unknown> = {};
|
|
615
|
+
if (transcript.utterances != null) {
|
|
616
|
+
assemblyaiMetadata.utterances = raw.utterances;
|
|
617
|
+
}
|
|
618
|
+
if (transcript.sentiment_analysis_results != null) {
|
|
619
|
+
assemblyaiMetadata.sentimentAnalysisResults =
|
|
620
|
+
raw.sentiment_analysis_results;
|
|
621
|
+
}
|
|
622
|
+
if (transcript.entities != null) {
|
|
623
|
+
assemblyaiMetadata.entities = raw.entities;
|
|
624
|
+
}
|
|
625
|
+
if (transcript.content_safety_labels != null) {
|
|
626
|
+
assemblyaiMetadata.contentSafetyLabels = raw.content_safety_labels;
|
|
627
|
+
}
|
|
628
|
+
if (transcript.iab_categories_result != null) {
|
|
629
|
+
assemblyaiMetadata.iabCategoriesResult = raw.iab_categories_result;
|
|
630
|
+
}
|
|
631
|
+
if (transcript.auto_highlights_result != null) {
|
|
632
|
+
assemblyaiMetadata.autoHighlightsResult = raw.auto_highlights_result;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const lastWordEndMs = transcript.words?.at(-1)?.end;
|
|
382
636
|
|
|
383
637
|
return {
|
|
384
638
|
text: transcript.text ?? '',
|
|
639
|
+
// AssemblyAI returns word timings in milliseconds; the AI SDK reports
|
|
640
|
+
// segment timings in seconds.
|
|
385
641
|
segments:
|
|
386
642
|
transcript.words?.map(word => ({
|
|
387
643
|
text: word.text,
|
|
388
|
-
startSecond: word.start,
|
|
389
|
-
endSecond: word.end,
|
|
644
|
+
startSecond: word.start / 1000,
|
|
645
|
+
endSecond: word.end / 1000,
|
|
390
646
|
})) ?? [],
|
|
391
647
|
language: transcript.language_code ?? undefined,
|
|
392
648
|
durationInSeconds:
|
|
393
|
-
transcript.audio_duration ??
|
|
649
|
+
transcript.audio_duration ??
|
|
650
|
+
(lastWordEndMs != null ? lastWordEndMs / 1000 : undefined),
|
|
394
651
|
warnings,
|
|
652
|
+
...(Object.keys(assemblyaiMetadata).length > 0 && {
|
|
653
|
+
providerMetadata: {
|
|
654
|
+
assemblyai: assemblyaiMetadata,
|
|
655
|
+
} as SharedV3ProviderMetadata,
|
|
656
|
+
}),
|
|
395
657
|
response: {
|
|
396
658
|
timestamp: currentDate,
|
|
397
659
|
modelId: this.modelId,
|
|
398
660
|
headers: responseHeaders, // Headers from final GET request
|
|
399
|
-
body:
|
|
661
|
+
body: rawTranscript, // Full raw response from final GET request
|
|
400
662
|
},
|
|
401
663
|
};
|
|
402
664
|
}
|
|
@@ -411,20 +673,65 @@ const assemblyaiSubmitResponseSchema = z.object({
|
|
|
411
673
|
status: z.enum(['queued', 'processing', 'completed', 'error']),
|
|
412
674
|
});
|
|
413
675
|
|
|
676
|
+
const assemblyaiWordSchema = z.object({
|
|
677
|
+
start: z.number(),
|
|
678
|
+
end: z.number(),
|
|
679
|
+
text: z.string(),
|
|
680
|
+
confidence: z.number().nullish(),
|
|
681
|
+
// Speaker label (e.g. 'A', 'B') when speaker diarization is enabled, else null.
|
|
682
|
+
speaker: z.string().nullish(),
|
|
683
|
+
channel: z.string().nullish(),
|
|
684
|
+
});
|
|
685
|
+
|
|
414
686
|
const assemblyaiTranscriptionResponseSchema = z.object({
|
|
415
687
|
id: z.string(),
|
|
416
688
|
status: z.enum(['queued', 'processing', 'completed', 'error']),
|
|
417
689
|
text: z.string().nullish(),
|
|
418
690
|
language_code: z.string().nullish(),
|
|
419
|
-
|
|
691
|
+
speech_model_used: z.string().nullish(),
|
|
692
|
+
words: z.array(assemblyaiWordSchema).nullish(),
|
|
693
|
+
// Speaker-diarized utterances (present when `speaker_labels` is enabled).
|
|
694
|
+
utterances: z
|
|
420
695
|
.array(
|
|
421
696
|
z.object({
|
|
422
697
|
start: z.number(),
|
|
423
698
|
end: z.number(),
|
|
424
699
|
text: z.string(),
|
|
700
|
+
confidence: z.number().nullish(),
|
|
701
|
+
speaker: z.string().nullish(),
|
|
702
|
+
channel: z.string().nullish(),
|
|
703
|
+
words: z.array(assemblyaiWordSchema).nullish(),
|
|
704
|
+
}),
|
|
705
|
+
)
|
|
706
|
+
.nullish(),
|
|
707
|
+
// Audio-intelligence results, present only when the matching feature is
|
|
708
|
+
// enabled. Kept intentionally permissive (the full structures are also
|
|
709
|
+
// available on the raw `response.body`).
|
|
710
|
+
sentiment_analysis_results: z
|
|
711
|
+
.array(
|
|
712
|
+
z.object({
|
|
713
|
+
text: z.string(),
|
|
714
|
+
start: z.number().nullish(),
|
|
715
|
+
end: z.number().nullish(),
|
|
716
|
+
sentiment: z.string(),
|
|
717
|
+
confidence: z.number().nullish(),
|
|
718
|
+
speaker: z.string().nullish(),
|
|
719
|
+
}),
|
|
720
|
+
)
|
|
721
|
+
.nullish(),
|
|
722
|
+
entities: z
|
|
723
|
+
.array(
|
|
724
|
+
z.object({
|
|
725
|
+
entity_type: z.string(),
|
|
726
|
+
text: z.string(),
|
|
727
|
+
start: z.number().nullish(),
|
|
728
|
+
end: z.number().nullish(),
|
|
425
729
|
}),
|
|
426
730
|
)
|
|
427
731
|
.nullish(),
|
|
732
|
+
content_safety_labels: z.record(z.string(), z.any()).nullish(),
|
|
733
|
+
iab_categories_result: z.record(z.string(), z.any()).nullish(),
|
|
734
|
+
auto_highlights_result: z.record(z.string(), z.any()).nullish(),
|
|
428
735
|
audio_duration: z.number().nullish(),
|
|
429
736
|
error: z.string().nullish(),
|
|
430
737
|
});
|
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Legacy AssemblyAI speech model, sent via the deprecated singular
|
|
3
|
+
* `speech_model` request parameter.
|
|
4
|
+
*
|
|
5
|
+
* @deprecated Use `universal-3-5-pro` instead.
|
|
6
|
+
* @see https://www.assemblyai.com/docs/pre-recorded-audio/select-the-speech-model
|
|
7
|
+
*/
|
|
8
|
+
export type AssemblyAIDeprecatedTranscriptionModelId = 'best';
|
|
9
|
+
|
|
10
|
+
export type AssemblyAITranscriptionModelId =
|
|
11
|
+
| 'universal-2'
|
|
12
|
+
| 'universal-3-pro'
|
|
13
|
+
| 'universal-3-5-pro'
|
|
14
|
+
| AssemblyAIDeprecatedTranscriptionModelId
|
|
15
|
+
| (string & {});
|