@mux/ai 0.47.0 → 0.49.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.
@@ -358,7 +358,16 @@ interface CompletedShotsResult {
358
358
  createdAt: string;
359
359
  shots: Shot[];
360
360
  }
361
- type ShotsResult = PendingShotsResult | ErroredShotsResult | CompletedShotsResult;
361
+ /** Mux declined to run shot detection, e.g. the asset has no video track. */
362
+ interface SkippedShotsResult {
363
+ status: "skipped";
364
+ createdAt: string;
365
+ }
366
+ interface DeletedShotsResult {
367
+ status: "deleted";
368
+ createdAt: string;
369
+ }
370
+ type ShotsResult = PendingShotsResult | ErroredShotsResult | CompletedShotsResult | SkippedShotsResult | DeletedShotsResult;
362
371
  interface ShotRequestOptions {
363
372
  /** Optional workflow credentials */
364
373
  credentials?: WorkflowCredentialsInput;
@@ -396,4 +405,4 @@ declare function getShotsForAsset(assetId: string, options?: ShotRequestOptions)
396
405
  */
397
406
  declare function waitForShotsForAsset(assetId: string, options?: WaitForShotsOptions): Promise<CompletedShotsResult>;
398
407
 
399
- export { type AssetTextTrack as A, getHotspotsForPlaybackId as B, type ChunkEmbedding as C, getHotspotsForVideo as D, type Encrypted as E, getShotsForAsset as F, requestShotsForAsset as G, type Hotspot as H, type ImageSubmissionMode as I, waitForShotsForAsset as J, type MuxAIOptions as M, type PlaybackAsset as P, type StoragePutObjectInput as S, type TextChunk as T, type UsageMetadata as U, type VTTChunkingConfig as V, type WorkflowCredentials as W, type StoragePresignGetObjectInput as a, type ChunkingStrategy as b, type EncryptedPayload as c, type MuxAsset as d, type PlaybackPolicy as e, type ScopedMuxAIOptions as f, type StorageAdapter as g, type TokenChunkingConfig as h, type TokenUsage as i, type ToneType as j, type VideoEmbeddingsResult as k, type WorkflowCredentialsInput as l, type WorkflowMuxClient as m, type WorkflowScope as n, decryptFromWorkflow as o, encryptForWorkflow as p, type CompletedShotsResult as q, type ErroredShotsResult as r, type HotspotOptions as s, type HotspotResponse as t, type PendingShotsResult as u, type Shot as v, type ShotRequestOptions as w, type ShotsResult as x, type WaitForShotsOptions as y, getHotspotsForAsset as z };
408
+ export { type AssetTextTrack as A, getHotspotsForAsset as B, type ChunkEmbedding as C, type DeletedShotsResult as D, type Encrypted as E, getHotspotsForPlaybackId as F, getHotspotsForVideo as G, type Hotspot as H, type ImageSubmissionMode as I, getShotsForAsset as J, requestShotsForAsset as K, waitForShotsForAsset as L, type MuxAsset as M, type PlaybackAsset as P, type StoragePutObjectInput as S, type TextChunk as T, type UsageMetadata as U, type VTTChunkingConfig as V, type WorkflowCredentials as W, type StoragePresignGetObjectInput as a, type ChunkingStrategy as b, type EncryptedPayload as c, type MuxAIOptions as d, type PlaybackPolicy as e, type ScopedMuxAIOptions as f, type StorageAdapter as g, type TokenChunkingConfig as h, type TokenUsage as i, type ToneType as j, type VideoEmbeddingsResult as k, type WorkflowCredentialsInput as l, type WorkflowMuxClient as m, type WorkflowScope as n, decryptFromWorkflow as o, encryptForWorkflow as p, type CompletedShotsResult as q, type ErroredShotsResult as r, type HotspotOptions as s, type HotspotResponse as t, type PendingShotsResult as u, type Shot as v, type ShotRequestOptions as w, type ShotsResult as x, type SkippedShotsResult as y, type WaitForShotsOptions as z };
@@ -1,8 +1,8 @@
1
- export { J as ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH, K as ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH, N as ASK_QUESTIONS_MAX_QUESTIONS_PER_CALL, O as ASK_QUESTIONS_MAX_QUESTION_LENGTH, P as AskQuestionsOptions, Q as AskQuestionsResult, U as AskQuestionsType, V as AudioTranslationOptions, W as AudioTranslationResult, X as AutoCensorProfanityOptions, Y as BurnedInCaptionsAnalysis, Z as BurnedInCaptionsOptions, _ as BurnedInCaptionsPromptOverrides, $ as BurnedInCaptionsPromptSections, a0 as BurnedInCaptionsResult, a1 as CaptionReplacement, a2 as CensorMode, a3 as Chapter, a4 as ChapterSystemPromptSections, a5 as ChaptersOptions, a6 as ChaptersPromptOverrides, a7 as ChaptersPromptSections, a8 as ChaptersResult, a9 as ChaptersType, aa as EditCaptionsOptions, ab as EditCaptionsResult, ac as EmbeddingsOptions, ad as EmbeddingsResult, ae as EngagementInsightsOptions, af as EngagementInsightsResult, ag as GENERATE_TEXT_CALLS_TO_ACTION, ah as GENERATE_TEXT_CHANNELS, ai as GENERATE_TEXT_CHANNEL_CEILINGS, aj as GENERATE_TEXT_FORMATS, ak as GENERATE_TEXT_LENGTH_BOUNDS, al as GENERATE_TEXT_MAX_ARTIFACTS, am as GENERATE_TEXT_MAX_AUDIENCE_CHARS, an as GENERATE_TEXT_MAX_BRAND_TERMS, ao as GENERATE_TEXT_MAX_BRAND_TERMS_TOTAL_CHARS, ap as GENERATE_TEXT_MAX_BRAND_TERM_CHARS, aq as GENERATE_TEXT_MAX_CONCURRENT_GENERATIONS, ar as GENERATE_TEXT_MAX_INSTRUCTIONS_CHARS, as as GENERATE_TEXT_MAX_SHOT_FRAMES, at as GENERATE_TEXT_MAX_VARIANTS, au as GENERATE_TEXT_VOICES, av as GOOGLE_VISION_LIKELIHOOD_TO_SCORE, aw as GenerateTextArtifact, ax as GenerateTextCallToAction, ay as GenerateTextChannel, az as GenerateTextFormat, aA as GenerateTextKeyedItem, aB as GenerateTextLengthLimit, aC as GenerateTextOptions, aD as GenerateTextResult, aE as GenerateTextVariant, aF as GenerateTextVoice, aG as GeneratedTextArtifact, aH as GeneratedTextVariant, aI as HIVE_SEXUAL_CATEGORIES, aJ as HIVE_VIOLENCE_CATEGORIES, aK as HiveModerationOutput, aL as HiveModerationSource, aM as ModerationOptions, aN as ModerationProvider, aO as ModerationResult, aP as MomentInsight, aQ as OverallInsight, aR as ProfanityDetectionPayload, aS as Question, aT as QuestionAnswer, aU as QuestionAnswerType, aV as ReplacementRecord, aW as SpeakerReplacement, aX as StaticRenditionCleanupOutcome, aY as SummarizationOptions, aZ as SummarizationPromptOverrides, a_ as SummarizationPromptSections, a$ as SummaryAndTagsResult, b0 as SummaryType, b1 as ThumbnailModerationScore, b2 as TranslationChunkingOptions, b3 as TranslationOptions, b4 as TranslationPayload, b5 as TranslationResult, b6 as aggregateTokenUsage, b7 as applyOverrideLists, b8 as applyReplacements, b9 as applySpeakerReplacements, ba as askQuestions, bb as buildReplacementRegex, bc as burnedInCaptionsSchema, bd as censorVttContent, be as chapterSchema, bf as chaptersSchema, bg as createReplacer, bh as editCaptions, bi as extractTranscriptSegmentsForHotspots, bj as findGenerateTextLengthViolation, bk as generateChapters, bl as generateEmbeddings, bm as generateEngagementInsights, bn as generateText, bo as generateVideoEmbeddings, bp as getModerationScores, bq as getSummaryAndTags, br as hasBurnedInCaptions, bs as mapShotsToHotspots, bt as measureGenerateTextLength, bu as normalizeTranslatedVtt, bv as profanityDetectionSchema, bw as questionAnswerSchema, bx as resolveGenerateTextLengthLimit, by as resolveGenerateTextLengthLimits, bz as resolveGenerateTextOptions, bA as selectGenerateTextShotFrames, bB as shouldSplitChunkTranslationError, bC as summarySchema, bD as transformCueText, bE as translateAudio, bF as translateCaptions, bG as translationSchema, bH as validateNeverTranslateTerms, bI as verifyNeverTranslateTerms } from '../index-DxAt9Jq8.js';
1
+ export { J as ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH, K as ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH, N as ASK_QUESTIONS_MAX_QUESTIONS_PER_CALL, O as ASK_QUESTIONS_MAX_QUESTION_LENGTH, P as AskQuestionsOptions, Q as AskQuestionsResult, U as AskQuestionsType, V as AudioTranslationOptions, W as AudioTranslationResult, X as AutoCensorProfanityOptions, Y as BurnedInCaptionsAnalysis, Z as BurnedInCaptionsOptions, _ as BurnedInCaptionsPromptOverrides, $ as BurnedInCaptionsPromptSections, a0 as BurnedInCaptionsResult, a1 as CaptionReplacement, a2 as CensorMode, a3 as Chapter, a4 as ChapterSystemPromptSections, a5 as ChaptersOptions, a6 as ChaptersPromptOverrides, a7 as ChaptersPromptSections, a8 as ChaptersResult, a9 as ChaptersType, aa as EditCaptionsOptions, ab as EditCaptionsResult, ac as EmbeddingsOptions, ad as EmbeddingsResult, ae as EngagementInsightsOptions, af as EngagementInsightsResult, ag as GENERATE_TEXT_CALLS_TO_ACTION, ah as GENERATE_TEXT_CHANNELS, ai as GENERATE_TEXT_CHANNEL_CEILINGS, aj as GENERATE_TEXT_FORMATS, ak as GENERATE_TEXT_LENGTH_BOUNDS, al as GENERATE_TEXT_MAX_ARTIFACTS, am as GENERATE_TEXT_MAX_AUDIENCE_CHARS, an as GENERATE_TEXT_MAX_BRAND_TERMS, ao as GENERATE_TEXT_MAX_BRAND_TERMS_TOTAL_CHARS, ap as GENERATE_TEXT_MAX_BRAND_TERM_CHARS, aq as GENERATE_TEXT_MAX_CONCURRENT_GENERATIONS, ar as GENERATE_TEXT_MAX_INSTRUCTIONS_CHARS, as as GENERATE_TEXT_MAX_SHOT_FRAMES, at as GENERATE_TEXT_MAX_VARIANTS, au as GENERATE_TEXT_VOICES, av as GOOGLE_VISION_LIKELIHOOD_TO_SCORE, aw as GenerateTextArtifact, ax as GenerateTextCallToAction, ay as GenerateTextChannel, az as GenerateTextFormat, aA as GenerateTextKeyedItem, aB as GenerateTextLengthLimit, aC as GenerateTextOptions, aD as GenerateTextResult, aE as GenerateTextVariant, aF as GenerateTextVoice, aG as GeneratedTextArtifact, aH as GeneratedTextVariant, aI as HIVE_SEXUAL_CATEGORIES, aJ as HIVE_VIOLENCE_CATEGORIES, aK as HiveModerationOutput, aL as HiveModerationSource, aM as ModerationOptions, aN as ModerationProvider, aO as ModerationResult, aP as MomentInsight, aQ as OverallInsight, aR as ProfanityDetectionPayload, aS as Question, aT as QuestionAnswer, aU as QuestionAnswerType, aV as ReplacementRecord, aW as SpeakerReplacement, aX as StaticRenditionCleanupOutcome, aY as SummarizationOptions, aZ as SummarizationPromptOverrides, a_ as SummarizationPromptSections, a$ as SummaryAndTagsResult, b0 as SummaryType, b1 as ThumbnailModerationScore, b2 as TranslationChunkingOptions, b3 as TranslationOptions, b4 as TranslationPayload, b5 as TranslationResult, b6 as aggregateTokenUsage, b7 as applyOverrideLists, b8 as applyReplacements, b9 as applySpeakerReplacements, ba as askQuestions, bb as buildReplacementRegex, bc as burnedInCaptionsSchema, bd as censorVttContent, be as chapterSchema, bf as chaptersSchema, bg as createReplacer, bh as editCaptions, bi as extractTranscriptSegmentsForHotspots, bj as findGenerateTextLengthViolation, bk as generateChapters, bl as generateEmbeddings, bm as generateEngagementInsights, bn as generateText, bo as generateVideoEmbeddings, bp as getModerationScores, bq as getSummaryAndTags, br as hasBurnedInCaptions, bs as mapShotsToHotspots, bt as measureGenerateTextLength, bu as normalizeTranslatedVtt, bv as profanityDetectionSchema, bw as questionAnswerSchema, bx as resolveGenerateTextLengthLimit, by as resolveGenerateTextLengthLimits, bz as resolveGenerateTextOptions, bA as selectGenerateTextShotFrames, bB as shouldSplitChunkTranslationError, bC as summarySchema, bD as transformCueText, bE as translateAudio, bF as translateCaptions, bG as translationSchema, bH as validateNeverTranslateTerms, bI as verifyNeverTranslateTerms } from '../index-BotaPu5M.js';
2
2
  export { D as DEFAULT_DESCRIPTION_LENGTH, a as DEFAULT_SUMMARY_KEYWORD_LIMIT, b as DEFAULT_TITLE_LENGTH } from '../summarization-BFmhXeAu.js';
3
3
  import 'zod';
4
4
  import '@ai-sdk/anthropic';
5
5
  import '@ai-sdk/google';
6
6
  import '@ai-sdk/openai';
7
- import '../shots-BwpjZDpr.js';
7
+ import '../shots-3wmvZnUV.js';
8
8
  import '@mux/ts';
@@ -5515,21 +5515,21 @@ async function fetchShotsFromManifest(shotsManifestUrl) {
5515
5515
  async function transformShotsResponse(data) {
5516
5516
  switch (data.status) {
5517
5517
  case "pending":
5518
+ case "skipped":
5519
+ case "deleted":
5518
5520
  return {
5519
- status: "pending",
5521
+ status: data.status,
5520
5522
  createdAt: data.created_at
5521
5523
  };
5522
- case "errored": {
5523
- const details = data.errors ?? data.error;
5524
+ case "errored":
5524
5525
  return {
5525
5526
  status: "errored",
5526
5527
  createdAt: data.created_at,
5527
5528
  error: {
5528
- type: details?.type ?? "unknown",
5529
- messages: details?.messages ?? []
5529
+ type: data.errors?.type ?? "unknown",
5530
+ messages: data.errors?.messages ?? []
5530
5531
  }
5531
5532
  };
5532
- }
5533
5533
  case "completed":
5534
5534
  if (!data.shots_manifest_url) {
5535
5535
  throw new Error("Completed shots response is missing shots_manifest_url");
@@ -8195,8 +8195,63 @@ async function getSummaryAndTagsInternal(assetId, options, collectedUsage) {
8195
8195
 
8196
8196
  // src/workflows/translate-audio.ts
8197
8197
  import { sleep } from "workflow";
8198
- var STATIC_RENDITION_POLL_INTERVAL_MS = 5e3;
8199
- var STATIC_RENDITION_MAX_ATTEMPTS = 36;
8198
+
8199
+ // src/lib/mux-static-renditions.ts
8200
+ var STATIC_RENDITIONS_GUIDE_URL = "https://www.mux.com/docs/guides/enable-static-mp4-renditions";
8201
+ var LEGACY_MP4_SUPPORT_FILE_PREFERENCE = {
8202
+ "capped-1080p": ["capped-1080p.mp4", "audio.m4a"],
8203
+ "audio-only": ["audio.m4a"],
8204
+ "audio-only,capped-1080p": ["audio.m4a", "capped-1080p.mp4"],
8205
+ "standard": ["low.mp4", "audio.m4a"]
8206
+ };
8207
+ var BYTES_PER_GB = 1e9;
8208
+ function usesLegacyMp4Support(asset) {
8209
+ return asset.mp4_support !== void 0 && asset.mp4_support !== "none";
8210
+ }
8211
+ function parseFilesizeBytes(filesize) {
8212
+ const bytes = typeof filesize === "string" ? Number(filesize) : filesize;
8213
+ return typeof bytes === "number" && Number.isFinite(bytes) && bytes > 0 ? bytes : void 0;
8214
+ }
8215
+ function resolveLegacyMp4SupportRendition(asset) {
8216
+ if (!usesLegacyMp4Support(asset)) {
8217
+ return void 0;
8218
+ }
8219
+ const status = asset.static_renditions?.status;
8220
+ if (status === void 0 || status === "preparing") {
8221
+ return { kind: "preparing" };
8222
+ }
8223
+ if (status !== "ready") {
8224
+ return {
8225
+ kind: "unusable",
8226
+ reason: `This asset uses the deprecated mp4_support setting, and its static renditions are ${status}. Move the asset to the Static Renditions API (${STATIC_RENDITIONS_GUIDE_URL}) and add an audio-only static rendition, then retry.`
8227
+ };
8228
+ }
8229
+ const files = asset.static_renditions?.files ?? [];
8230
+ for (const name of LEGACY_MP4_SUPPORT_FILE_PREFERENCE[asset.mp4_support] ?? []) {
8231
+ const file = files.find((candidate) => candidate.name === name);
8232
+ if (file) {
8233
+ return { kind: "ready", name, filesizeBytes: parseFilesizeBytes(file.filesize) };
8234
+ }
8235
+ }
8236
+ return {
8237
+ kind: "unusable",
8238
+ reason: `This asset uses the deprecated mp4_support setting ("${asset.mp4_support}"), and none of its static renditions can be used by this workflow. Move the asset to the Static Renditions API (${STATIC_RENDITIONS_GUIDE_URL}) and add an audio-only static rendition, then retry.`
8239
+ };
8240
+ }
8241
+ function formatGigabytes(bytes) {
8242
+ return `${Math.round(bytes / BYTES_PER_GB * 100) / 100} GB`;
8243
+ }
8244
+ function getLegacyMp4SupportRenditionSizeError(rendition, maxBytes) {
8245
+ if (rendition.filesizeBytes === void 0 || rendition.filesizeBytes <= maxBytes) {
8246
+ return void 0;
8247
+ }
8248
+ return `This asset uses the deprecated mp4_support setting, and its ${rendition.name} static rendition (${formatGigabytes(rendition.filesizeBytes)}) is larger than the ${formatGigabytes(maxBytes)} this workflow can process. Move the asset to the Static Renditions API (${STATIC_RENDITIONS_GUIDE_URL}) and add an audio-only static rendition, then retry.`;
8249
+ }
8250
+
8251
+ // src/workflows/translate-audio.ts
8252
+ var STATIC_RENDITION_POLL_INTERVAL_MS = 1e4;
8253
+ var STATIC_RENDITION_MAX_ATTEMPTS = 180;
8254
+ var MAX_DUBBING_SOURCE_BYTES = 1e9;
8200
8255
  var DUBBING_POLL_INTERVAL_MS = 1e4;
8201
8256
  var DEFAULT_DUBBING_POLL_TIMEOUT_SECONDS = 7200;
8202
8257
  function getReadyAudioStaticRendition(asset) {
@@ -8297,6 +8352,40 @@ async function waitForAudioStaticRendition({
8297
8352
  { type: "timeout_error", retryable: true }
8298
8353
  );
8299
8354
  }
8355
+ async function waitForLegacyMp4SupportRendition({
8356
+ assetId,
8357
+ initialAsset,
8358
+ credentials
8359
+ }) {
8360
+ let rendition = resolveLegacyMp4SupportRendition(initialAsset);
8361
+ for (let attempt = 1; rendition?.kind === "preparing" && attempt <= STATIC_RENDITION_MAX_ATTEMPTS; attempt++) {
8362
+ console.warn(
8363
+ `\u231B Waiting for mp4_support static renditions (attempt ${attempt}/${STATIC_RENDITION_MAX_ATTEMPTS})`
8364
+ );
8365
+ await sleep(STATIC_RENDITION_POLL_INTERVAL_MS);
8366
+ rendition = resolveLegacyMp4SupportRendition(await retrieveAsset(assetId, credentials));
8367
+ }
8368
+ if (!rendition) {
8369
+ throw new MuxAiError(
8370
+ "The asset's static rendition settings changed while waiting for them. Please try again.",
8371
+ { type: "processing_error", retryable: true }
8372
+ );
8373
+ }
8374
+ if (rendition.kind === "preparing") {
8375
+ throw new MuxAiError(
8376
+ "Timed out waiting for the static rendition to become ready. Please try again in a moment.",
8377
+ { type: "timeout_error", retryable: true }
8378
+ );
8379
+ }
8380
+ if (rendition.kind === "unusable") {
8381
+ throw new MuxAiError(rendition.reason, { type: "validation_error" });
8382
+ }
8383
+ const sizeError = getLegacyMp4SupportRenditionSizeError(rendition, MAX_DUBBING_SOURCE_BYTES);
8384
+ if (sizeError) {
8385
+ throw new MuxAiError(sizeError, { type: "validation_error" });
8386
+ }
8387
+ return rendition.name;
8388
+ }
8300
8389
  async function createElevenLabsDubbingJob({
8301
8390
  sourceUrl,
8302
8391
  assetId,
@@ -8505,7 +8594,8 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
8505
8594
  }
8506
8595
  let currentAsset = initialAsset;
8507
8596
  let createdStaticRenditionId;
8508
- if (!hasReadyAudioStaticRendition(currentAsset)) {
8597
+ const isLegacyMp4SupportAsset = usesLegacyMp4Support(initialAsset);
8598
+ if (!isLegacyMp4SupportAsset && !hasReadyAudioStaticRendition(currentAsset)) {
8509
8599
  console.warn("\u274C No ready audio static rendition found. Requesting one now...");
8510
8600
  const renditionStatus = currentAsset.static_renditions?.status ?? "not_requested";
8511
8601
  if (renditionStatus === "not_requested" || renditionStatus === "errored") {
@@ -8522,21 +8612,30 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
8522
8612
  let captionsPresignedUrl;
8523
8613
  let captionsTrackId;
8524
8614
  try {
8525
- if (!hasReadyAudioStaticRendition(currentAsset)) {
8526
- currentAsset = await waitForAudioStaticRendition({
8615
+ let sourceRenditionName = "audio.m4a";
8616
+ if (isLegacyMp4SupportAsset) {
8617
+ sourceRenditionName = await waitForLegacyMp4SupportRendition({
8527
8618
  assetId,
8528
8619
  initialAsset: currentAsset,
8529
8620
  credentials
8530
8621
  });
8622
+ } else {
8623
+ if (!hasReadyAudioStaticRendition(currentAsset)) {
8624
+ currentAsset = await waitForAudioStaticRendition({
8625
+ assetId,
8626
+ initialAsset: currentAsset,
8627
+ credentials
8628
+ });
8629
+ }
8630
+ const audioRendition = getReadyAudioStaticRendition(currentAsset);
8631
+ if (!audioRendition) {
8632
+ throw new MuxAiError(
8633
+ "Unable to obtain an audio-only static rendition for this asset. Please verify static renditions are enabled in Mux.",
8634
+ { type: "validation_error" }
8635
+ );
8636
+ }
8531
8637
  }
8532
- const audioRendition = getReadyAudioStaticRendition(currentAsset);
8533
- if (!audioRendition) {
8534
- throw new MuxAiError(
8535
- "Unable to obtain an audio-only static rendition for this asset. Please verify static renditions are enabled in Mux.",
8536
- { type: "validation_error" }
8537
- );
8538
- }
8539
- let audioUrl = `${await getMuxStreamOrigin(credentials)}/${playbackId}/audio.m4a`;
8638
+ let audioUrl = `${await getMuxStreamOrigin(credentials)}/${playbackId}/${sourceRenditionName}`;
8540
8639
  if (policy === "signed") {
8541
8640
  audioUrl = await signUrl(audioUrl, playbackId, "video", void 0, credentials);
8542
8641
  }