@mux/ai 0.11.0 → 0.12.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.
@@ -1,4 +1,4 @@
1
- export { A as AskQuestionsOptions, a as AskQuestionsResult, b as AskQuestionsType, c as AudioTranslationOptions, d as AudioTranslationResult, e as AutoCensorProfanityOptions, B as BurnedInCaptionsAnalysis, f as BurnedInCaptionsOptions, g as BurnedInCaptionsPromptOverrides, h as BurnedInCaptionsPromptSections, j as BurnedInCaptionsResult, C as CaptionReplacement, k as CensorMode, l as Chapter, m as ChapterSystemPromptSections, n as ChaptersOptions, o as ChaptersPromptOverrides, p as ChaptersPromptSections, q as ChaptersResult, r as ChaptersType, D as DEFAULT_DESCRIPTION_LENGTH, s as DEFAULT_SUMMARY_KEYWORD_LIMIT, t as DEFAULT_TITLE_LENGTH, E as EditCaptionsOptions, u as EditCaptionsResult, v as EmbeddingsOptions, w as EmbeddingsResult, H as HIVE_SEXUAL_CATEGORIES, x as HIVE_VIOLENCE_CATEGORIES, y as HiveModerationOutput, z as HiveModerationSource, M as ModerationOptions, F as ModerationProvider, G as ModerationResult, P as ProfanityDetectionPayload, Q as Question, I as QuestionAnswer, J as QuestionAnswerType, R as ReplacementRecord, S as SummarizationOptions, K as SummarizationPromptOverrides, L as SummarizationPromptSections, N as SummaryAndTagsResult, O as SummaryType, T as ThumbnailModerationScore, U as TranslationChunkingOptions, V as TranslationOptions, W as TranslationPayload, X as TranslationResult, Y as aggregateTokenUsage, Z as applyOverrideLists, _ as applyReplacements, $ as askQuestions, a0 as buildReplacementRegex, a1 as burnedInCaptionsSchema, a2 as censorVttContent, a3 as chapterSchema, a4 as chaptersSchema, a5 as createReplacer, a6 as editCaptions, a7 as generateChapters, a8 as generateEmbeddings, a9 as generateVideoEmbeddings, aa as getModerationScores, ab as getSummaryAndTags, ac as hasBurnedInCaptions, ad as profanityDetectionSchema, ae as questionAnswerSchema, af as shouldSplitChunkTranslationError, ag as summarySchema, ah as transformCueText, ai as translateAudio, aj as translateCaptions, ak as translationSchema } from '../index-BapL6paa.js';
1
+ export { A as AskQuestionsOptions, a as AskQuestionsResult, b as AskQuestionsType, c as AudioTranslationOptions, d as AudioTranslationResult, e as AutoCensorProfanityOptions, B as BurnedInCaptionsAnalysis, f as BurnedInCaptionsOptions, g as BurnedInCaptionsPromptOverrides, h as BurnedInCaptionsPromptSections, j as BurnedInCaptionsResult, C as CaptionReplacement, k as CensorMode, l as Chapter, m as ChapterSystemPromptSections, n as ChaptersOptions, o as ChaptersPromptOverrides, p as ChaptersPromptSections, q as ChaptersResult, r as ChaptersType, D as DEFAULT_DESCRIPTION_LENGTH, s as DEFAULT_SUMMARY_KEYWORD_LIMIT, t as DEFAULT_TITLE_LENGTH, E as EditCaptionsOptions, u as EditCaptionsResult, v as EmbeddingsOptions, w as EmbeddingsResult, H as HIVE_SEXUAL_CATEGORIES, x as HIVE_VIOLENCE_CATEGORIES, y as HiveModerationOutput, z as HiveModerationSource, M as ModerationOptions, F as ModerationProvider, G as ModerationResult, P as ProfanityDetectionPayload, Q as Question, I as QuestionAnswer, J as QuestionAnswerType, R as ReplacementRecord, S as SummarizationOptions, K as SummarizationPromptOverrides, L as SummarizationPromptSections, N as SummaryAndTagsResult, O as SummaryType, T as ThumbnailModerationScore, U as TranslationChunkingOptions, V as TranslationOptions, W as TranslationPayload, X as TranslationResult, Y as aggregateTokenUsage, Z as applyOverrideLists, _ as applyReplacements, $ as askQuestions, a0 as buildReplacementRegex, a1 as burnedInCaptionsSchema, a2 as censorVttContent, a3 as chapterSchema, a4 as chaptersSchema, a5 as createReplacer, a6 as editCaptions, a7 as generateChapters, a8 as generateEmbeddings, a9 as generateVideoEmbeddings, aa as getModerationScores, ab as getSummaryAndTags, ac as hasBurnedInCaptions, ad as profanityDetectionSchema, ae as questionAnswerSchema, af as shouldSplitChunkTranslationError, ag as summarySchema, ah as transformCueText, ai as translateAudio, aj as translateCaptions, ak as translationSchema } from '../index-DyzifniY.js';
2
2
  import 'zod';
3
3
  import '@ai-sdk/anthropic';
4
4
  import '@ai-sdk/google';
@@ -1304,12 +1304,14 @@ async function fetchTranscriptForAsset(asset, playbackId, options = {}) {
1304
1304
  // src/workflows/ask-questions.ts
1305
1305
  var questionAnswerSchema = z2.object({
1306
1306
  question: z2.string(),
1307
- answer: z2.string(),
1307
+ answer: z2.string().optional(),
1308
1308
  confidence: z2.number(),
1309
- reasoning: z2.string()
1309
+ reasoning: z2.string(),
1310
+ skipped: z2.boolean()
1310
1311
  });
1312
+ var SKIP_SENTINEL = "__SKIPPED__";
1311
1313
  function createAskQuestionsSchema(allowedAnswers) {
1312
- const answerSchema = z2.enum(allowedAnswers);
1314
+ const answerSchema = z2.enum([...allowedAnswers, SKIP_SENTINEL]);
1313
1315
  return z2.object({
1314
1316
  answers: z2.array(
1315
1317
  questionAnswerSchema.extend({
@@ -1365,8 +1367,32 @@ var SYSTEM_PROMPT = dedent`
1365
1367
  - Be precise: cite specific frames, objects, actions, or transcript quotes
1366
1368
  </answer_guidelines>
1367
1369
 
1370
+ <relevance_filtering>
1371
+ Before answering each question, assess whether it can be meaningfully
1372
+ answered based on the video storyboard and/or transcript. A question is
1373
+ relevant if it asks about something observable or inferable from the
1374
+ video content (visuals, audio, dialogue, setting, subjects, actions, etc.).
1375
+
1376
+ Mark a question as skipped (skipped: true) if it:
1377
+ - Is completely unrelated to video content (e.g., math, trivia, personal questions)
1378
+ - Asks about information that cannot be determined from storyboard frames or transcript
1379
+ - Is a general knowledge question with no connection to what is shown or said in the video
1380
+ - Attempts to use the system for non-video-analysis purposes
1381
+
1382
+ For skipped questions:
1383
+ - Set skipped to true
1384
+ - Set answer to "${SKIP_SENTINEL}"
1385
+ - Set confidence to 0
1386
+ - Use the reasoning field to explain why the question is not answerable
1387
+ from the video content
1388
+
1389
+ For borderline questions that are loosely related to the video content,
1390
+ still answer them but use a lower confidence score to reflect uncertainty.
1391
+ </relevance_filtering>
1392
+
1368
1393
  <constraints>
1369
- - You MUST answer every question with one of the allowed response options
1394
+ - You MUST answer every relevant question with one of the allowed response options
1395
+ - Skip irrelevant questions as described in relevance_filtering
1370
1396
  - Only describe observable evidence from frames or transcript
1371
1397
  - Do not fabricate details or make unsupported assumptions
1372
1398
  - Return structured data matching the requested schema exactly
@@ -1442,14 +1468,7 @@ async function analyzeQuestionsWithStoryboard(imageDataUrl, provider, modelId, u
1442
1468
  ]
1443
1469
  });
1444
1470
  return {
1445
- result: {
1446
- answers: response.output.answers.map((answer) => ({
1447
- ...answer,
1448
- // Strip numbering prefix (e.g., "1. " or "2. ") from questions
1449
- question: answer.question.replace(/^\d+\.\s*/, ""),
1450
- confidence: Math.min(1, Math.max(0, answer.confidence))
1451
- }))
1452
- },
1471
+ result: response.output,
1453
1472
  usage: {
1454
1473
  inputTokens: response.usage.inputTokens,
1455
1474
  outputTokens: response.usage.outputTokens,
@@ -1555,9 +1574,20 @@ async function askQuestions(assetId, questions, options) {
1555
1574
  `Expected ${questions.length} answers but received ${analysisResponse.result.answers.length}`
1556
1575
  );
1557
1576
  }
1577
+ const answers = analysisResponse.result.answers.map((raw) => {
1578
+ const isSkipped = raw.skipped || raw.answer === SKIP_SENTINEL;
1579
+ return {
1580
+ // Strip numbering prefix (e.g., "1. " or "2. ") from questions
1581
+ question: raw.question.replace(/^\d+\.\s*/, ""),
1582
+ confidence: isSkipped ? 0 : Math.min(1, Math.max(0, raw.confidence)),
1583
+ reasoning: raw.reasoning,
1584
+ skipped: isSkipped,
1585
+ ...isSkipped ? {} : { answer: raw.answer }
1586
+ };
1587
+ });
1558
1588
  return {
1559
1589
  assetId,
1560
- answers: analysisResponse.result.answers,
1590
+ answers,
1561
1591
  storyboardUrl: imageUrl,
1562
1592
  usage: {
1563
1593
  ...analysisResponse.usage,
@@ -3760,43 +3790,43 @@ var DESCRIPTION_LENGTH_THRESHOLD_LARGE = 100;
3760
3790
  function buildDescriptionGuidance(wordCount, contentType) {
3761
3791
  if (wordCount < DESCRIPTION_LENGTH_THRESHOLD_SMALL) {
3762
3792
  if (contentType === "video") {
3763
- return dedent5`A brief summary of the video in approximately ${wordCount} words.
3793
+ return dedent5`A brief summary of the video in no more than ${wordCount} words. Shorter is fine.
3764
3794
  Focus on the single most important subject or action.
3765
3795
  Write in present tense.`;
3766
3796
  }
3767
- return dedent5`A brief summary of the audio content in approximately ${wordCount} words.
3797
+ return dedent5`A brief summary of the audio content in no more than ${wordCount} words. Shorter is fine.
3768
3798
  Focus on the single most important topic or theme.
3769
3799
  Write in present tense.`;
3770
3800
  }
3771
3801
  if (wordCount > DESCRIPTION_LENGTH_THRESHOLD_LARGE) {
3772
3802
  if (contentType === "video") {
3773
3803
  return dedent5`A detailed summary that describes what happens across the video.
3774
- Aim for approximately ${wordCount} words, and you may use multiple sentences.
3804
+ Never exceed ${wordCount} words, but shorter is perfectly fine. You may use multiple sentences.
3775
3805
  Be thorough: cover subjects, actions, setting, progression, and any notable details visible across frames.
3776
3806
  Write in present tense. Be specific about observable details rather than making assumptions.
3777
3807
  If the transcript provides dialogue or narration, incorporate key points but prioritize visual content.`;
3778
3808
  }
3779
3809
  return dedent5`A detailed summary that describes the audio content.
3780
- Aim for approximately ${wordCount} words, and you may use multiple sentences.
3810
+ Never exceed ${wordCount} words, but shorter is perfectly fine. You may use multiple sentences.
3781
3811
  Be thorough: cover topics, speakers, themes, progression, and any notable insights.
3782
3812
  Write in present tense. Be specific about what is discussed or presented rather than making assumptions.
3783
3813
  Focus on the spoken content and any key insights, dialogue, or narrative elements.`;
3784
3814
  }
3785
3815
  if (contentType === "video") {
3786
3816
  return dedent5`A summary that describes what happens across the video.
3787
- Aim for approximately ${wordCount} words, and you may use multiple sentences.
3817
+ Never exceed ${wordCount} words, but shorter is perfectly fine. You may use multiple sentences.
3788
3818
  Cover the main subjects, actions, setting, and any notable progression visible across frames.
3789
3819
  Write in present tense. Be specific about observable details rather than making assumptions.
3790
3820
  If the transcript provides dialogue or narration, incorporate key points but prioritize visual content.`;
3791
3821
  }
3792
3822
  return dedent5`A summary that describes the audio content.
3793
- Aim for approximately ${wordCount} words, and you may use multiple sentences.
3823
+ Never exceed ${wordCount} words, but shorter is perfectly fine. You may use multiple sentences.
3794
3824
  Cover the main topics, speakers, themes, and any notable progression in the discussion or narration.
3795
3825
  Write in present tense. Be specific about what is discussed or presented rather than making assumptions.
3796
3826
  Focus on the spoken content and any key insights, dialogue, or narrative elements.`;
3797
3827
  }
3798
3828
  function createSummarizationBuilder({ titleLength, descriptionLength, tagCount } = {}) {
3799
- const titleBrevity = `Aim for approximately ${titleLength ?? DEFAULT_TITLE_LENGTH} words.`;
3829
+ const titleLimit = titleLength ?? DEFAULT_TITLE_LENGTH;
3800
3830
  const keywordLimit = tagCount ?? DEFAULT_SUMMARY_KEYWORD_LIMIT;
3801
3831
  return createPromptBuilder({
3802
3832
  template: {
@@ -3807,10 +3837,11 @@ function createSummarizationBuilder({ titleLength, descriptionLength, tagCount }
3807
3837
  title: {
3808
3838
  tag: "title_requirements",
3809
3839
  content: dedent5`
3810
- A short, compelling headline that immediately communicates the subject or action.
3811
- ${titleBrevity} Think of how a news headline or video card title would read.
3812
- Start with the primary subject, action, or topic - never begin with "A video of" or similar phrasing.
3813
- Use active, specific language.`
3840
+ A concise, label-style title not a sentence or description.
3841
+ Never exceed ${titleLimit} words, but shorter is better.
3842
+ Think of how a video card title, playlist entry, or file name would read e.g. "Predator: Badlands Trailer" or "Chef Prepares Holiday Feast".
3843
+ Start with the primary subject or topic. Never begin with "A video of" or similar phrasing.
3844
+ Use specific nouns over lengthy descriptions. Avoid clauses, conjunctions, or narrative structure.`
3814
3845
  },
3815
3846
  description: {
3816
3847
  tag: "description_requirements",
@@ -3841,7 +3872,7 @@ function createSummarizationBuilder({ titleLength, descriptionLength, tagCount }
3841
3872
  });
3842
3873
  }
3843
3874
  function createAudioOnlyBuilder({ titleLength, descriptionLength, tagCount } = {}) {
3844
- const titleBrevity = `Aim for approximately ${titleLength ?? DEFAULT_TITLE_LENGTH} words.`;
3875
+ const titleLimit = titleLength ?? DEFAULT_TITLE_LENGTH;
3845
3876
  const keywordLimit = tagCount ?? DEFAULT_SUMMARY_KEYWORD_LIMIT;
3846
3877
  return createPromptBuilder({
3847
3878
  template: {
@@ -3852,10 +3883,11 @@ function createAudioOnlyBuilder({ titleLength, descriptionLength, tagCount } = {
3852
3883
  title: {
3853
3884
  tag: "title_requirements",
3854
3885
  content: dedent5`
3855
- A short, compelling headline that immediately communicates the subject or topic.
3856
- ${titleBrevity} Think of how a podcast title or audio description would read.
3857
- Start with the primary subject, action, or topic - never begin with "An audio of" or similar phrasing.
3858
- Use active, specific language.`
3886
+ A concise, label-style title not a sentence or description.
3887
+ Never exceed ${titleLimit} words, but shorter is better.
3888
+ Think of how a podcast episode title or playlist entry would read e.g. "Weekly News Roundup" or "Interview with Dr. Smith".
3889
+ Start with the primary subject or topic. Never begin with "An audio of" or similar phrasing.
3890
+ Use specific nouns over lengthy descriptions. Avoid clauses, conjunctions, or narrative structure.`
3859
3891
  },
3860
3892
  description: {
3861
3893
  tag: "description_requirements",