@mux/ai 0.7.3 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -390
- package/dist/{index-BMqnP1RV.d.ts → index-B0U9upb4.d.ts} +13 -3
- package/dist/{index-DZlygsvb.d.ts → index-Nxf6BaBO.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +133 -22
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.d.ts +2 -2
- package/dist/primitives/index.js +96 -8
- package/dist/primitives/index.js.map +1 -1
- package/dist/{types-BQVi_wnh.d.ts → types-BRbaGW3t.d.ts} +2 -0
- package/dist/workflows/index.d.ts +2 -2
- package/dist/workflows/index.js +132 -21
- package/dist/workflows/index.js.map +1 -1
- package/package.json +3 -3
package/dist/workflows/index.js
CHANGED
|
@@ -156,6 +156,9 @@ var EnvSchema = z.object({
|
|
|
156
156
|
),
|
|
157
157
|
MUX_TEST_ASSET_ID_AUDIO_ONLY: optionalString("Mux test asset ID for audio-only assets.", "Mux test asset id for audio-only assets for testing"),
|
|
158
158
|
MUX_TEST_ASSET_ID_VIOLENT_AUDIO_ONLY: optionalString("Mux test asset ID for audio-only assets with violent content.", "Mux test asset id for audio-only assets with violent content for testing"),
|
|
159
|
+
// Eval config
|
|
160
|
+
MUX_AI_EVAL_MODEL_SET: optionalString("Eval model selection mode.", "Choose between 'default' (provider defaults only) or 'all' (all configured models)"),
|
|
161
|
+
MUX_AI_EVAL_MODELS: optionalString("Comma-separated eval model pairs.", "Comma-separated provider:model pairs (e.g. 'openai:gpt-5.1,anthropic:claude-sonnet-4-5,google:gemini-3-flash-preview')"),
|
|
159
162
|
// AI Providers
|
|
160
163
|
OPENAI_API_KEY: optionalString("OpenAI API key for OpenAI-backed workflows.", "OpenAI API key"),
|
|
161
164
|
ANTHROPIC_API_KEY: optionalString("Anthropic API key for Claude-backed workflows.", "Anthropic API key"),
|
|
@@ -421,12 +424,13 @@ function readString(record, key) {
|
|
|
421
424
|
function resolveDirectMuxCredentials(record) {
|
|
422
425
|
const tokenId = readString(record, "muxTokenId");
|
|
423
426
|
const tokenSecret = readString(record, "muxTokenSecret");
|
|
427
|
+
const authorizationToken = readString(record, "muxAuthorizationToken");
|
|
424
428
|
const signingKey = readString(record, "muxSigningKey");
|
|
425
429
|
const privateKey = readString(record, "muxPrivateKey");
|
|
426
|
-
if (!tokenId && !tokenSecret && !signingKey && !privateKey) {
|
|
430
|
+
if (!tokenId && !tokenSecret && !authorizationToken && !signingKey && !privateKey) {
|
|
427
431
|
return void 0;
|
|
428
432
|
}
|
|
429
|
-
if (!tokenId || !tokenSecret) {
|
|
433
|
+
if ((!tokenId || !tokenSecret) && !authorizationToken) {
|
|
430
434
|
throw new Error(
|
|
431
435
|
"Both muxTokenId and muxTokenSecret are required when passing direct Mux workflow credentials."
|
|
432
436
|
);
|
|
@@ -434,6 +438,7 @@ function resolveDirectMuxCredentials(record) {
|
|
|
434
438
|
return {
|
|
435
439
|
tokenId,
|
|
436
440
|
tokenSecret,
|
|
441
|
+
authorizationToken,
|
|
437
442
|
signingKey,
|
|
438
443
|
privateKey
|
|
439
444
|
};
|
|
@@ -444,7 +449,8 @@ function createWorkflowMuxClient(options) {
|
|
|
444
449
|
const { default: MuxClient } = await import("@mux/mux-node");
|
|
445
450
|
return new MuxClient({
|
|
446
451
|
tokenId: options.tokenId,
|
|
447
|
-
tokenSecret: options.tokenSecret
|
|
452
|
+
tokenSecret: options.tokenSecret,
|
|
453
|
+
authorizationToken: options.authorizationToken
|
|
448
454
|
});
|
|
449
455
|
},
|
|
450
456
|
getSigningKey() {
|
|
@@ -530,6 +536,81 @@ var DEFAULT_EMBEDDING_MODELS = {
|
|
|
530
536
|
openai: "text-embedding-3-small",
|
|
531
537
|
google: "gemini-embedding-001"
|
|
532
538
|
};
|
|
539
|
+
var LANGUAGE_MODELS = {
|
|
540
|
+
openai: ["gpt-5.1", "gpt-5-mini"],
|
|
541
|
+
anthropic: ["claude-sonnet-4-5"],
|
|
542
|
+
google: ["gemini-3-flash-preview", "gemini-2.5-flash"]
|
|
543
|
+
};
|
|
544
|
+
function getDefaultEvalModelConfigs() {
|
|
545
|
+
return Object.entries(DEFAULT_LANGUAGE_MODELS).map(([provider, modelId]) => ({ provider, modelId }));
|
|
546
|
+
}
|
|
547
|
+
function getAllEvalModelConfigs() {
|
|
548
|
+
return Object.entries(LANGUAGE_MODELS).flatMap(([provider, models]) => models.map((modelId) => ({ provider, modelId })));
|
|
549
|
+
}
|
|
550
|
+
function isSupportedProvider(value) {
|
|
551
|
+
return value === "openai" || value === "anthropic" || value === "google";
|
|
552
|
+
}
|
|
553
|
+
function parseEvalModelPair(value) {
|
|
554
|
+
const trimmed = value.trim();
|
|
555
|
+
const [providerRaw, modelIdRaw] = trimmed.split(":", 2);
|
|
556
|
+
const provider = providerRaw?.trim();
|
|
557
|
+
const modelId = modelIdRaw?.trim();
|
|
558
|
+
if (!provider || !modelId) {
|
|
559
|
+
throw new Error(
|
|
560
|
+
`Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.1").`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
if (!isSupportedProvider(provider)) {
|
|
564
|
+
throw new Error(
|
|
565
|
+
`Unsupported eval provider "${provider}" in "${value}". Supported providers: ${Object.keys(LANGUAGE_MODELS).join(", ")}.`
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
const supportedModels = LANGUAGE_MODELS[provider];
|
|
569
|
+
if (!supportedModels.includes(modelId)) {
|
|
570
|
+
throw new Error(
|
|
571
|
+
`Unsupported eval model "${modelId}" for provider "${provider}". Supported models: ${supportedModels.join(", ")}.`
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
return {
|
|
575
|
+
provider,
|
|
576
|
+
modelId
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
function resolveEvalModelConfigs(options = {}) {
|
|
580
|
+
const explicitPairs = options.modelPairs?.map((value) => value.trim()).filter(Boolean) ?? [];
|
|
581
|
+
if (explicitPairs.length > 0) {
|
|
582
|
+
const dedupedPairs = Array.from(new Set(explicitPairs));
|
|
583
|
+
return dedupedPairs.map(parseEvalModelPair);
|
|
584
|
+
}
|
|
585
|
+
const selection = options.selection ?? "default";
|
|
586
|
+
if (selection === "all") {
|
|
587
|
+
return getAllEvalModelConfigs();
|
|
588
|
+
}
|
|
589
|
+
return getDefaultEvalModelConfigs();
|
|
590
|
+
}
|
|
591
|
+
function resolveEvalModelConfigsFromEnv(environment = env_default) {
|
|
592
|
+
const rawSelection = environment.MUX_AI_EVAL_MODEL_SET?.trim();
|
|
593
|
+
const rawModelPairs = environment.MUX_AI_EVAL_MODELS?.trim();
|
|
594
|
+
let selection;
|
|
595
|
+
if (!rawSelection || rawSelection === "default") {
|
|
596
|
+
selection = "default";
|
|
597
|
+
} else if (rawSelection === "all") {
|
|
598
|
+
selection = "all";
|
|
599
|
+
} else {
|
|
600
|
+
throw new Error(
|
|
601
|
+
`Invalid MUX_AI_EVAL_MODEL_SET="${rawSelection}". Expected "default" or "all".`
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
let modelPairs;
|
|
605
|
+
if (rawModelPairs) {
|
|
606
|
+
modelPairs = rawModelPairs.split(",").map((value) => value.trim()).filter(Boolean);
|
|
607
|
+
}
|
|
608
|
+
return resolveEvalModelConfigs({
|
|
609
|
+
selection,
|
|
610
|
+
modelPairs
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
var EVAL_MODEL_CONFIGS = resolveEvalModelConfigsFromEnv();
|
|
533
614
|
function resolveLanguageModelConfig(options = {}) {
|
|
534
615
|
const provider = options.provider || "openai";
|
|
535
616
|
const modelId = options.model || DEFAULT_LANGUAGE_MODELS[provider];
|
|
@@ -778,9 +859,9 @@ async function signPlaybackId(playbackId, context, type = "video", params) {
|
|
|
778
859
|
params: stringParams
|
|
779
860
|
});
|
|
780
861
|
}
|
|
781
|
-
async function signUrl(url, playbackId,
|
|
862
|
+
async function signUrl(url, playbackId, type = "video", params, credentials) {
|
|
782
863
|
"use step";
|
|
783
|
-
const resolvedContext =
|
|
864
|
+
const resolvedContext = await resolveMuxSigningContext(credentials);
|
|
784
865
|
if (!resolvedContext) {
|
|
785
866
|
throw new Error(
|
|
786
867
|
"Signed playback ID requires signing credentials. Provide muxSigningKey and muxPrivateKey via workflow credentials or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables."
|
|
@@ -797,7 +878,7 @@ async function getStoryboardUrl(playbackId, width = DEFAULT_STORYBOARD_WIDTH, sh
|
|
|
797
878
|
"use step";
|
|
798
879
|
const baseUrl = `https://image.mux.com/${playbackId}/storyboard.png`;
|
|
799
880
|
if (shouldSign) {
|
|
800
|
-
return signUrl(baseUrl, playbackId,
|
|
881
|
+
return signUrl(baseUrl, playbackId, "storyboard", { width }, credentials);
|
|
801
882
|
}
|
|
802
883
|
return `${baseUrl}?width=${width}`;
|
|
803
884
|
}
|
|
@@ -914,7 +995,7 @@ async function buildTranscriptUrl(playbackId, trackId, shouldSign = false, crede
|
|
|
914
995
|
"use step";
|
|
915
996
|
const baseUrl = `https://stream.mux.com/${playbackId}/text/${trackId}.vtt`;
|
|
916
997
|
if (shouldSign) {
|
|
917
|
-
return signUrl(baseUrl, playbackId,
|
|
998
|
+
return signUrl(baseUrl, playbackId, "video", void 0, credentials);
|
|
918
999
|
}
|
|
919
1000
|
return baseUrl;
|
|
920
1001
|
}
|
|
@@ -2007,7 +2088,7 @@ async function getThumbnailUrls(playbackId, duration, options = {}) {
|
|
|
2007
2088
|
const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;
|
|
2008
2089
|
const urlPromises = timestamps.map(async (time) => {
|
|
2009
2090
|
if (shouldSign) {
|
|
2010
|
-
return signUrl(baseUrl, playbackId,
|
|
2091
|
+
return signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials);
|
|
2011
2092
|
}
|
|
2012
2093
|
return `${baseUrl}?time=${time}&width=${width}`;
|
|
2013
2094
|
});
|
|
@@ -2023,11 +2104,10 @@ var DEFAULT_PROVIDER2 = "openai";
|
|
|
2023
2104
|
var HIVE_ENDPOINT = "https://api.thehive.ai/api/v2/task/sync";
|
|
2024
2105
|
var HIVE_SEXUAL_CATEGORIES = [
|
|
2025
2106
|
"general_nsfw",
|
|
2026
|
-
"general_suggestive",
|
|
2027
2107
|
"yes_sexual_activity",
|
|
2028
|
-
"
|
|
2029
|
-
"
|
|
2030
|
-
"
|
|
2108
|
+
"yes_sex_toy",
|
|
2109
|
+
"yes_female_nudity",
|
|
2110
|
+
"yes_male_nudity"
|
|
2031
2111
|
];
|
|
2032
2112
|
var HIVE_VIOLENCE_CATEGORIES = [
|
|
2033
2113
|
"gun_in_hand",
|
|
@@ -2038,10 +2118,8 @@ var HIVE_VIOLENCE_CATEGORIES = [
|
|
|
2038
2118
|
"hanging",
|
|
2039
2119
|
"noose",
|
|
2040
2120
|
"human_corpse",
|
|
2041
|
-
"
|
|
2042
|
-
"
|
|
2043
|
-
"animal_abuse",
|
|
2044
|
-
"fights",
|
|
2121
|
+
"yes_emaciated_body",
|
|
2122
|
+
"yes_self_harm",
|
|
2045
2123
|
"garm_death_injury_or_military_conflict"
|
|
2046
2124
|
];
|
|
2047
2125
|
async function processConcurrently(items, processor, maxConcurrent = 5) {
|
|
@@ -2185,6 +2263,12 @@ function getHiveCategoryScores(classes, categoryNames) {
|
|
|
2185
2263
|
const scoreMap = Object.fromEntries(
|
|
2186
2264
|
classes.map((c) => [c.class, c.score])
|
|
2187
2265
|
);
|
|
2266
|
+
const missingCategories = categoryNames.filter((category) => !(category in scoreMap));
|
|
2267
|
+
if (missingCategories.length > 0) {
|
|
2268
|
+
console.warn(
|
|
2269
|
+
`Hive response missing expected categories: ${missingCategories.join(", ")}`
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2188
2272
|
const scores = categoryNames.map((category) => scoreMap[category] || 0);
|
|
2189
2273
|
return Math.max(...scores, 0);
|
|
2190
2274
|
}
|
|
@@ -2282,7 +2366,7 @@ async function getThumbnailUrlsFromTimestamps(playbackId, timestampsMs, options)
|
|
|
2282
2366
|
const urlPromises = timestampsMs.map(async (tsMs) => {
|
|
2283
2367
|
const time = Number((tsMs / 1e3).toFixed(2));
|
|
2284
2368
|
if (shouldSign) {
|
|
2285
|
-
return signUrl(baseUrl, playbackId,
|
|
2369
|
+
return signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials);
|
|
2286
2370
|
}
|
|
2287
2371
|
return `${baseUrl}?time=${time}&width=${width}`;
|
|
2288
2372
|
});
|
|
@@ -3307,6 +3391,18 @@ function getReadyAudioStaticRendition(asset) {
|
|
|
3307
3391
|
);
|
|
3308
3392
|
}
|
|
3309
3393
|
var hasReadyAudioStaticRendition = (asset) => Boolean(getReadyAudioStaticRendition(asset));
|
|
3394
|
+
function getAudioStaticRenditionStatus(asset) {
|
|
3395
|
+
const files = asset.static_renditions?.files;
|
|
3396
|
+
const audioRendition = files?.find((rendition) => rendition.name === "audio.m4a");
|
|
3397
|
+
if (typeof audioRendition?.status === "string" && audioRendition.status.length > 0) {
|
|
3398
|
+
return audioRendition.status;
|
|
3399
|
+
}
|
|
3400
|
+
const aggregateStatus = asset.static_renditions?.status;
|
|
3401
|
+
if (typeof aggregateStatus === "string" && aggregateStatus.length > 0) {
|
|
3402
|
+
return aggregateStatus;
|
|
3403
|
+
}
|
|
3404
|
+
return asset.static_renditions ? "requested" : "not_requested";
|
|
3405
|
+
}
|
|
3310
3406
|
async function requestStaticRenditionCreation(assetId, credentials) {
|
|
3311
3407
|
"use step";
|
|
3312
3408
|
const muxClient = await resolveMuxClient(credentials);
|
|
@@ -3352,7 +3448,7 @@ async function waitForAudioStaticRendition({
|
|
|
3352
3448
|
if (hasReadyAudioStaticRendition(currentAsset)) {
|
|
3353
3449
|
return currentAsset;
|
|
3354
3450
|
}
|
|
3355
|
-
const currentStatus = currentAsset
|
|
3451
|
+
const currentStatus = getAudioStaticRenditionStatus(currentAsset);
|
|
3356
3452
|
console.warn(
|
|
3357
3453
|
`\u231B Waiting for static rendition (attempt ${attempt}/${STATIC_RENDITION_MAX_ATTEMPTS}) \u2192 ${currentStatus}`
|
|
3358
3454
|
);
|
|
@@ -3378,6 +3474,7 @@ async function createElevenLabsDubbingJob({
|
|
|
3378
3474
|
audioBuffer,
|
|
3379
3475
|
assetId,
|
|
3380
3476
|
elevenLabsLangCode,
|
|
3477
|
+
elevenLabsSourceLangCode,
|
|
3381
3478
|
numSpeakers,
|
|
3382
3479
|
credentials
|
|
3383
3480
|
}) {
|
|
@@ -3387,8 +3484,14 @@ async function createElevenLabsDubbingJob({
|
|
|
3387
3484
|
const formData = new FormData();
|
|
3388
3485
|
formData.append("file", audioBlob);
|
|
3389
3486
|
formData.append("target_lang", elevenLabsLangCode);
|
|
3487
|
+
if (elevenLabsSourceLangCode) {
|
|
3488
|
+
formData.append("source_lang", elevenLabsSourceLangCode);
|
|
3489
|
+
}
|
|
3390
3490
|
formData.append("num_speakers", numSpeakers.toString());
|
|
3391
|
-
formData.append(
|
|
3491
|
+
formData.append(
|
|
3492
|
+
"name",
|
|
3493
|
+
`Mux Asset ${assetId} - ${elevenLabsSourceLangCode ?? "auto"} to ${elevenLabsLangCode}`
|
|
3494
|
+
);
|
|
3392
3495
|
const dubbingResponse = await fetch("https://api.elevenlabs.io/v1/dubbing", {
|
|
3393
3496
|
method: "POST",
|
|
3394
3497
|
headers: {
|
|
@@ -3497,6 +3600,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
3497
3600
|
"use workflow";
|
|
3498
3601
|
const {
|
|
3499
3602
|
provider = "elevenlabs",
|
|
3603
|
+
fromLanguageCode,
|
|
3500
3604
|
numSpeakers = 0,
|
|
3501
3605
|
// 0 = auto-detect
|
|
3502
3606
|
uploadToMux = true,
|
|
@@ -3535,7 +3639,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
3535
3639
|
}
|
|
3536
3640
|
let audioUrl = `https://stream.mux.com/${playbackId}/audio.m4a`;
|
|
3537
3641
|
if (policy === "signed") {
|
|
3538
|
-
audioUrl = await signUrl(audioUrl, playbackId,
|
|
3642
|
+
audioUrl = await signUrl(audioUrl, playbackId, "video", void 0, credentials);
|
|
3539
3643
|
}
|
|
3540
3644
|
console.warn("\u{1F399}\uFE0F Fetching audio from Mux...");
|
|
3541
3645
|
let audioBuffer;
|
|
@@ -3546,13 +3650,18 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
3546
3650
|
}
|
|
3547
3651
|
console.warn("\u{1F399}\uFE0F Creating dubbing job in ElevenLabs...");
|
|
3548
3652
|
const elevenLabsLangCode = toISO639_3(toLanguageCode);
|
|
3549
|
-
|
|
3653
|
+
const normalizedFromLanguageCode = fromLanguageCode?.trim();
|
|
3654
|
+
const elevenLabsSourceLangCode = normalizedFromLanguageCode ? toISO639_3(normalizedFromLanguageCode) : void 0;
|
|
3655
|
+
console.warn(
|
|
3656
|
+
`\u{1F50D} Creating dubbing job for asset ${assetId}: ${elevenLabsSourceLangCode ?? "auto"} -> ${elevenLabsLangCode}`
|
|
3657
|
+
);
|
|
3550
3658
|
let dubbingId;
|
|
3551
3659
|
try {
|
|
3552
3660
|
dubbingId = await createElevenLabsDubbingJob({
|
|
3553
3661
|
audioBuffer,
|
|
3554
3662
|
assetId,
|
|
3555
3663
|
elevenLabsLangCode,
|
|
3664
|
+
elevenLabsSourceLangCode,
|
|
3556
3665
|
numSpeakers,
|
|
3557
3666
|
credentials
|
|
3558
3667
|
});
|
|
@@ -3910,6 +4019,8 @@ async function translateCaptions(assetId, fromLanguageCode, toLanguageCode, opti
|
|
|
3910
4019
|
};
|
|
3911
4020
|
}
|
|
3912
4021
|
export {
|
|
4022
|
+
HIVE_SEXUAL_CATEGORIES,
|
|
4023
|
+
HIVE_VIOLENCE_CATEGORIES,
|
|
3913
4024
|
SUMMARY_KEYWORD_LIMIT,
|
|
3914
4025
|
askQuestions,
|
|
3915
4026
|
burnedInCaptionsSchema,
|