@mux/ai 0.30.0 → 0.31.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/dist/{index-D3cB2ltG.d.ts → index-ooikuED7.d.ts} +11 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +108 -6
- package/dist/index.js.map +1 -1
- package/dist/workflows/index.d.ts +1 -1
- package/dist/workflows/index.js +107 -5
- package/dist/workflows/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1255,6 +1255,10 @@ interface AudioTranslationResult {
|
|
|
1255
1255
|
dubbingId: string;
|
|
1256
1256
|
uploadedTrackId?: string;
|
|
1257
1257
|
presignedUrl?: string;
|
|
1258
|
+
/** Mux text track ID for the dubbed captions, present when `uploadCaptionsToMux` is true and the upload succeeded. */
|
|
1259
|
+
captionsTrackId?: string;
|
|
1260
|
+
/** Presigned URL for the dub's translated transcript (WebVTT) staged to S3. */
|
|
1261
|
+
captionsPresignedUrl?: string;
|
|
1258
1262
|
/** Workflow usage metadata (asset duration, thumbnails, etc.). */
|
|
1259
1263
|
usage?: TokenUsage;
|
|
1260
1264
|
}
|
|
@@ -1290,6 +1294,13 @@ interface AudioTranslationOptions extends MuxAIOptions {
|
|
|
1290
1294
|
* required for track creation.
|
|
1291
1295
|
*/
|
|
1292
1296
|
uploadToMux?: boolean;
|
|
1297
|
+
/**
|
|
1298
|
+
* When true the dub's translated transcript (the same translation that was
|
|
1299
|
+
* voiced) is attached as a subtitles text track on the Mux asset. Implies
|
|
1300
|
+
* `uploadToS3: true`. Defaults to false. The SDK does not check for existing
|
|
1301
|
+
* text tracks — callers decide conflict semantics before enabling this.
|
|
1302
|
+
*/
|
|
1303
|
+
uploadCaptionsToMux?: boolean;
|
|
1293
1304
|
/** Optional storage adapter override for upload + presign operations. */
|
|
1294
1305
|
storageAdapter?: StorageAdapter;
|
|
1295
1306
|
/** Expiry duration in seconds for S3 presigned GET URLs. Defaults to 86400 (24 hours). */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { I as ISO639_1, a as ISO639_3, L as LanguageCodePair, S as SupportedISO639_1, b as SupportedISO639_3, g as getLanguageCodePair, c as getLanguageName, i as isUndeterminedLanguageCode, d as isValidISO639_1, e as isValidISO639_3, t as toISO639_1, f as toISO639_3, h as workflows } from './index-
|
|
1
|
+
export { I as ISO639_1, a as ISO639_3, L as LanguageCodePair, S as SupportedISO639_1, b as SupportedISO639_3, g as getLanguageCodePair, c as getLanguageName, i as isUndeterminedLanguageCode, d as isValidISO639_1, e as isValidISO639_3, t as toISO639_1, f as toISO639_3, h as workflows } from './index-ooikuED7.js';
|
|
2
2
|
import { W as WorkflowCredentials, S as StoragePutObjectInput, a as StoragePresignGetObjectInput } from './shots-Bh0GrvLx.js';
|
|
3
3
|
export { A as AssetTextTrack, C as ChunkEmbedding, b as ChunkingStrategy, E as Encrypted, c as EncryptedPayload, I as ImageSubmissionMode, M as MuxAIOptions, d as MuxAsset, P as PlaybackAsset, e as PlaybackPolicy, f as ScopedMuxAIOptions, g as StorageAdapter, T as TextChunk, h as TokenChunkingConfig, i as TokenUsage, j as ToneType, U as UsageMetadata, V as VTTChunkingConfig, k as VideoEmbeddingsResult, l as WorkflowCredentialsInput, m as WorkflowMuxClient, n as WorkflowScope, o as decryptFromWorkflow, p as encryptForWorkflow } from './shots-Bh0GrvLx.js';
|
|
4
4
|
import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
|
|
@@ -9,7 +9,7 @@ import '@ai-sdk/google';
|
|
|
9
9
|
import '@ai-sdk/openai';
|
|
10
10
|
import '@mux/mux-node';
|
|
11
11
|
|
|
12
|
-
var version = "0.
|
|
12
|
+
var version = "0.31.0";
|
|
13
13
|
|
|
14
14
|
type MuxAiErrorType = "validation_error" | "processing_error" | "timeout_error" | "content_policy_error";
|
|
15
15
|
/**
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// package.json
|
|
8
|
-
var version = "0.
|
|
8
|
+
var version = "0.31.0";
|
|
9
9
|
|
|
10
10
|
// src/lib/language-codes.ts
|
|
11
11
|
var ISO639_1_TO_3 = {
|
|
@@ -3167,13 +3167,23 @@ function createLanguageSection(languageName) {
|
|
|
3167
3167
|
}
|
|
3168
3168
|
|
|
3169
3169
|
// src/lib/retry.ts
|
|
3170
|
+
import { DownloadError } from "ai";
|
|
3170
3171
|
var DEFAULT_RETRY_OPTIONS = {
|
|
3171
3172
|
maxRetries: 3,
|
|
3172
3173
|
baseDelay: 2e3,
|
|
3173
3174
|
maxDelay: 1e4
|
|
3174
3175
|
};
|
|
3175
3176
|
function defaultShouldRetry(error, _attempt) {
|
|
3176
|
-
|
|
3177
|
+
if (error.message.includes("Timeout while downloading")) {
|
|
3178
|
+
return true;
|
|
3179
|
+
}
|
|
3180
|
+
const isDownloadError = DownloadError.isInstance(error);
|
|
3181
|
+
const isSerializedDownloadError = error.name === "AI_DownloadError";
|
|
3182
|
+
if (!isDownloadError && !isSerializedDownloadError) {
|
|
3183
|
+
return false;
|
|
3184
|
+
}
|
|
3185
|
+
const statusCode = error.statusCode;
|
|
3186
|
+
return statusCode === void 0 || statusCode === 408 || statusCode === 425 || statusCode === 429 || statusCode >= 500;
|
|
3177
3187
|
}
|
|
3178
3188
|
function calculateDelay(attempt, baseDelay, maxDelay) {
|
|
3179
3189
|
const exponentialDelay = baseDelay * 2 ** (attempt - 1);
|
|
@@ -4098,14 +4108,14 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
|
|
|
4098
4108
|
credentials
|
|
4099
4109
|
});
|
|
4100
4110
|
} else {
|
|
4101
|
-
analysisResponse = await analyzeStoryboard({
|
|
4111
|
+
analysisResponse = await withRetry(() => analyzeStoryboard({
|
|
4102
4112
|
imageDataUrl: imageUrl,
|
|
4103
4113
|
provider: modelConfig.provider,
|
|
4104
4114
|
modelId: modelConfig.modelId,
|
|
4105
4115
|
userPrompt,
|
|
4106
4116
|
systemPrompt: SYSTEM_PROMPT2,
|
|
4107
4117
|
credentials
|
|
4108
|
-
});
|
|
4118
|
+
}));
|
|
4109
4119
|
}
|
|
4110
4120
|
collectedUsage.push(analysisResponse.usage);
|
|
4111
4121
|
if (!analysisResponse.result) {
|
|
@@ -7158,6 +7168,59 @@ async function downloadAndUploadDubbedAudio({
|
|
|
7158
7168
|
console.warn(`\u{1F517} Generated presigned URL (expires in ${expiryHours} hour${expiryHours === 1 ? "" : "s"})`);
|
|
7159
7169
|
return presignedUrl;
|
|
7160
7170
|
}
|
|
7171
|
+
async function downloadAndUploadDubTranscript({
|
|
7172
|
+
dubbingId,
|
|
7173
|
+
languageCode,
|
|
7174
|
+
assetId,
|
|
7175
|
+
toLanguageCode,
|
|
7176
|
+
s3Endpoint,
|
|
7177
|
+
s3Region,
|
|
7178
|
+
s3Bucket,
|
|
7179
|
+
storageAdapter,
|
|
7180
|
+
s3SignedUrlExpirySeconds,
|
|
7181
|
+
credentials
|
|
7182
|
+
}) {
|
|
7183
|
+
"use step";
|
|
7184
|
+
const elevenLabsApiKey = await getApiKeyFromEnv("elevenlabs", credentials);
|
|
7185
|
+
const transcriptUrl = `https://api.elevenlabs.io/v1/dubbing/${dubbingId}/transcripts/${languageCode}/format/webvtt`;
|
|
7186
|
+
const transcriptResponse = await fetch(transcriptUrl, {
|
|
7187
|
+
headers: {
|
|
7188
|
+
"xi-api-key": elevenLabsApiKey
|
|
7189
|
+
}
|
|
7190
|
+
});
|
|
7191
|
+
if (!transcriptResponse.ok) {
|
|
7192
|
+
throw new Error(`Failed to fetch dub transcript: ${transcriptResponse.statusText}`);
|
|
7193
|
+
}
|
|
7194
|
+
const transcriptBody = await transcriptResponse.json();
|
|
7195
|
+
const transcriptVtt = transcriptBody.webvtt;
|
|
7196
|
+
if (!transcriptVtt) {
|
|
7197
|
+
throw new Error("Dub transcript response did not include webvtt content");
|
|
7198
|
+
}
|
|
7199
|
+
const s3AccessKeyId = env_default.S3_ACCESS_KEY_ID;
|
|
7200
|
+
const s3SecretAccessKey = env_default.S3_SECRET_ACCESS_KEY;
|
|
7201
|
+
const vttKey = `audio-translations/${assetId}/auto-to-${toLanguageCode}-${Date.now()}.vtt`;
|
|
7202
|
+
await putObjectWithStorageAdapter({
|
|
7203
|
+
accessKeyId: s3AccessKeyId,
|
|
7204
|
+
secretAccessKey: s3SecretAccessKey,
|
|
7205
|
+
endpoint: s3Endpoint,
|
|
7206
|
+
region: s3Region,
|
|
7207
|
+
bucket: s3Bucket,
|
|
7208
|
+
key: vttKey,
|
|
7209
|
+
body: transcriptVtt,
|
|
7210
|
+
contentType: "text/vtt"
|
|
7211
|
+
}, storageAdapter);
|
|
7212
|
+
const presignedUrl = await createPresignedGetUrlWithStorageAdapter({
|
|
7213
|
+
accessKeyId: s3AccessKeyId,
|
|
7214
|
+
secretAccessKey: s3SecretAccessKey,
|
|
7215
|
+
endpoint: s3Endpoint,
|
|
7216
|
+
region: s3Region,
|
|
7217
|
+
bucket: s3Bucket,
|
|
7218
|
+
key: vttKey,
|
|
7219
|
+
expiresInSeconds: s3SignedUrlExpirySeconds ?? 86400
|
|
7220
|
+
}, storageAdapter);
|
|
7221
|
+
console.warn(`\u2705 Dub transcript uploaded successfully to: ${vttKey}`);
|
|
7222
|
+
return presignedUrl;
|
|
7223
|
+
}
|
|
7161
7224
|
async function createAudioTrackOnMux(assetId, languageCode, presignedUrl, credentials) {
|
|
7162
7225
|
"use step";
|
|
7163
7226
|
const muxClient = await resolveMuxClient(credentials);
|
|
@@ -7184,6 +7247,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7184
7247
|
// 0 = auto-detect
|
|
7185
7248
|
uploadToS3: uploadToS3Option,
|
|
7186
7249
|
uploadToMux: uploadToMuxOption,
|
|
7250
|
+
uploadCaptionsToMux = false,
|
|
7187
7251
|
storageAdapter,
|
|
7188
7252
|
credentials: providedCredentials
|
|
7189
7253
|
} = options;
|
|
@@ -7193,7 +7257,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7193
7257
|
const credentials = providedCredentials;
|
|
7194
7258
|
const effectiveStorageAdapter = storageAdapter;
|
|
7195
7259
|
const uploadToMux = uploadToMuxOption !== false;
|
|
7196
|
-
const uploadToS3 = uploadToS3Option || uploadToMux;
|
|
7260
|
+
const uploadToS3 = uploadToS3Option || uploadToMux || uploadCaptionsToMux;
|
|
7197
7261
|
const s3Endpoint = options.s3Endpoint ?? env_default.S3_ENDPOINT;
|
|
7198
7262
|
const s3Region = options.s3Region ?? env_default.S3_REGION ?? "auto";
|
|
7199
7263
|
const s3Bucket = options.s3Bucket ?? env_default.S3_BUCKET;
|
|
@@ -7274,10 +7338,12 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7274
7338
|
console.warn("\u2705 Dubbing completed successfully!");
|
|
7275
7339
|
let presignedUrl;
|
|
7276
7340
|
let uploadedTrackId;
|
|
7341
|
+
let captionsPresignedUrl;
|
|
7342
|
+
let captionsTrackId;
|
|
7277
7343
|
if (uploadToS3) {
|
|
7278
7344
|
console.warn("\u{1F4E5} Downloading dubbed audio from ElevenLabs and staging to S3...");
|
|
7345
|
+
const downloadLangCode = targetLanguages[0] ?? toISO639_1(toLanguageCode);
|
|
7279
7346
|
try {
|
|
7280
|
-
const downloadLangCode = targetLanguages[0] ?? toISO639_1(toLanguageCode);
|
|
7281
7347
|
presignedUrl = await downloadAndUploadDubbedAudio({
|
|
7282
7348
|
dubbingId,
|
|
7283
7349
|
languageCode: downloadLangCode,
|
|
@@ -7309,6 +7375,40 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7309
7375
|
console.warn(presignedUrl);
|
|
7310
7376
|
}
|
|
7311
7377
|
}
|
|
7378
|
+
try {
|
|
7379
|
+
console.warn("\u{1F4E5} Downloading dub transcript from ElevenLabs and staging to S3...");
|
|
7380
|
+
captionsPresignedUrl = await downloadAndUploadDubTranscript({
|
|
7381
|
+
dubbingId,
|
|
7382
|
+
languageCode: downloadLangCode,
|
|
7383
|
+
assetId,
|
|
7384
|
+
toLanguageCode,
|
|
7385
|
+
s3Endpoint,
|
|
7386
|
+
s3Region,
|
|
7387
|
+
s3Bucket,
|
|
7388
|
+
storageAdapter: effectiveStorageAdapter,
|
|
7389
|
+
s3SignedUrlExpirySeconds: options.s3SignedUrlExpirySeconds,
|
|
7390
|
+
credentials
|
|
7391
|
+
});
|
|
7392
|
+
if (uploadCaptionsToMux) {
|
|
7393
|
+
console.warn("\u{1F4F9} Adding dubbed captions track to Mux asset...");
|
|
7394
|
+
const muxLangCode = toISO639_1(toLanguageCode);
|
|
7395
|
+
const languageName = new Intl.DisplayNames(["en"], { type: "language" }).of(muxLangCode) || muxLangCode.toUpperCase();
|
|
7396
|
+
captionsTrackId = await createTextTrackOnMux(
|
|
7397
|
+
assetId,
|
|
7398
|
+
muxLangCode,
|
|
7399
|
+
`${languageName} (auto-dubbed)`,
|
|
7400
|
+
captionsPresignedUrl,
|
|
7401
|
+
credentials
|
|
7402
|
+
);
|
|
7403
|
+
console.warn(`\u2705 Captions track added to Mux asset with ID: ${captionsTrackId}`);
|
|
7404
|
+
}
|
|
7405
|
+
} catch (error) {
|
|
7406
|
+
console.warn(`\u26A0\uFE0F Failed to attach dubbed captions: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
7407
|
+
if (captionsPresignedUrl) {
|
|
7408
|
+
console.warn("\u{1F517} You can manually add the captions track using this presigned URL:");
|
|
7409
|
+
console.warn(captionsPresignedUrl);
|
|
7410
|
+
}
|
|
7411
|
+
}
|
|
7312
7412
|
}
|
|
7313
7413
|
const targetLanguage = getLanguageCodePair(toLanguageCode);
|
|
7314
7414
|
return {
|
|
@@ -7318,6 +7418,8 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7318
7418
|
dubbingId,
|
|
7319
7419
|
uploadedTrackId,
|
|
7320
7420
|
presignedUrl,
|
|
7421
|
+
captionsTrackId,
|
|
7422
|
+
captionsPresignedUrl,
|
|
7321
7423
|
usage: {
|
|
7322
7424
|
metadata: {
|
|
7323
7425
|
assetDurationSeconds
|