@mux/ai 0.15.1 → 0.16.1
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-yn3fUDgv.d.ts → index-BfsJvx3r.d.ts} +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +72 -58
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/index.js.map +1 -1
- package/dist/workflows/index.d.ts +1 -1
- package/dist/workflows/index.js +71 -57
- package/dist/workflows/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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, x as EngagementInsightsOptions, y as EngagementInsightsResult, H as HIVE_SEXUAL_CATEGORIES, z as HIVE_VIOLENCE_CATEGORIES, F as HiveModerationOutput, G as HiveModerationSource, M as ModerationOptions, I as ModerationProvider, J as ModerationResult, K as MomentInsight, O as OverallInsight, P as ProfanityDetectionPayload, Q as Question, L as QuestionAnswer, N as QuestionAnswerType, R as ReplacementRecord, S as SummarizationOptions, T as SummarizationPromptOverrides, U as SummarizationPromptSections, V as SummaryAndTagsResult, W as SummaryType, X as ThumbnailModerationScore, Y as TranslationChunkingOptions, Z as TranslationOptions, _ as TranslationPayload, $ as TranslationResult, a0 as aggregateTokenUsage, a1 as applyOverrideLists, a2 as applyReplacements, a3 as askQuestions, a4 as buildReplacementRegex, a5 as burnedInCaptionsSchema, a6 as censorVttContent, a7 as chapterSchema, a8 as chaptersSchema, a9 as createReplacer, aa as editCaptions, ab as extractTranscriptSegmentsForHotspots, ac as generateChapters, ad as generateEmbeddings, ae as generateEngagementInsights, af as generateVideoEmbeddings, ag as getModerationScores, ah as getSummaryAndTags, ai as hasBurnedInCaptions, aj as mapShotsToHotspots, ak as profanityDetectionSchema, al as questionAnswerSchema, am as shouldSplitChunkTranslationError, an as summarySchema, ao as transformCueText, ap as translateAudio, aq as translateCaptions, ar as translationSchema } from '../index-
|
|
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, x as EngagementInsightsOptions, y as EngagementInsightsResult, H as HIVE_SEXUAL_CATEGORIES, z as HIVE_VIOLENCE_CATEGORIES, F as HiveModerationOutput, G as HiveModerationSource, M as ModerationOptions, I as ModerationProvider, J as ModerationResult, K as MomentInsight, O as OverallInsight, P as ProfanityDetectionPayload, Q as Question, L as QuestionAnswer, N as QuestionAnswerType, R as ReplacementRecord, S as SummarizationOptions, T as SummarizationPromptOverrides, U as SummarizationPromptSections, V as SummaryAndTagsResult, W as SummaryType, X as ThumbnailModerationScore, Y as TranslationChunkingOptions, Z as TranslationOptions, _ as TranslationPayload, $ as TranslationResult, a0 as aggregateTokenUsage, a1 as applyOverrideLists, a2 as applyReplacements, a3 as askQuestions, a4 as buildReplacementRegex, a5 as burnedInCaptionsSchema, a6 as censorVttContent, a7 as chapterSchema, a8 as chaptersSchema, a9 as createReplacer, aa as editCaptions, ab as extractTranscriptSegmentsForHotspots, ac as generateChapters, ad as generateEmbeddings, ae as generateEngagementInsights, af as generateVideoEmbeddings, ag as getModerationScores, ah as getSummaryAndTags, ai as hasBurnedInCaptions, aj as mapShotsToHotspots, ak as profanityDetectionSchema, al as questionAnswerSchema, am as shouldSplitChunkTranslationError, an as summarySchema, ao as transformCueText, ap as translateAudio, aq as translateCaptions, ar as translationSchema } from '../index-BfsJvx3r.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import '@ai-sdk/anthropic';
|
|
4
4
|
import '@ai-sdk/google';
|
package/dist/workflows/index.js
CHANGED
|
@@ -116,7 +116,7 @@ var MuxAiError = class extends Error {
|
|
|
116
116
|
super(message);
|
|
117
117
|
/** Structural brand for duck-type identification. */
|
|
118
118
|
this.__robots_error = true;
|
|
119
|
-
this.name = "
|
|
119
|
+
this.name = "FatalError";
|
|
120
120
|
this.publicType = opts?.type ?? "processing_error";
|
|
121
121
|
this.publicMessage = message;
|
|
122
122
|
this.retryable = opts?.retryable ?? false;
|
|
@@ -794,7 +794,7 @@ function renderSection(section) {
|
|
|
794
794
|
throw new Error(`Invalid XML ${context} name: "${name}"`);
|
|
795
795
|
}
|
|
796
796
|
};
|
|
797
|
-
const escapeXmlText = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">
|
|
797
|
+
const escapeXmlText = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
798
798
|
const escapeXmlAttribute = (value) => escapeXmlText(value).replace(/"/g, """);
|
|
799
799
|
if (!content.trim()) {
|
|
800
800
|
return "";
|
|
@@ -1342,7 +1342,7 @@ async function fetchTranscriptForAsset(asset, playbackId, options = {}) {
|
|
|
1342
1342
|
|
|
1343
1343
|
// src/workflows/ask-questions.ts
|
|
1344
1344
|
var questionAnswerSchema = z2.object({
|
|
1345
|
-
question: z2.string(),
|
|
1345
|
+
question: z2.string().describe("The full text of the original question"),
|
|
1346
1346
|
answer: z2.string().nullable(),
|
|
1347
1347
|
confidence: z2.number(),
|
|
1348
1348
|
reasoning: z2.string(),
|
|
@@ -1388,14 +1388,17 @@ var SYSTEM_PROMPT = dedent`
|
|
|
1388
1388
|
<task>
|
|
1389
1389
|
For each question provided, you must:
|
|
1390
1390
|
1. Analyze the storyboard frames and transcript (if provided)
|
|
1391
|
-
2. Answer with ONLY the allowed response options - no other values are acceptable
|
|
1391
|
+
2. Answer with ONLY the allowed response options listed for that question - no other values are acceptable
|
|
1392
1392
|
3. Provide a confidence score between 0 and 1 reflecting your certainty
|
|
1393
1393
|
4. Explain your reasoning based on observable evidence
|
|
1394
1394
|
</task>
|
|
1395
1395
|
|
|
1396
1396
|
<answer_guidelines>
|
|
1397
|
-
-
|
|
1398
|
-
- Choose
|
|
1397
|
+
- Each question is presented as its own <question> block with a <text> element (the question) and an <allowed_answers> element (the permitted response values)
|
|
1398
|
+
- Choose only from the values listed in that question's <allowed_answers> element
|
|
1399
|
+
- Questions may have any set of allowed answers. Always read the <allowed_answers> for each question and select the best matching option based on the evidence
|
|
1400
|
+
- Select the answer best supported by observable evidence from the content
|
|
1401
|
+
- When evidence is ambiguous but some signal exists, select the most conservative option and use a low confidence score. If the question cannot be answered at all from the content, skip it per the relevance_filtering rules
|
|
1399
1402
|
- Confidence should reflect the clarity and strength of evidence:
|
|
1400
1403
|
* 0.9-1.0: Clear, unambiguous evidence
|
|
1401
1404
|
* 0.7-0.9: Strong evidence with minor ambiguity
|
|
@@ -1441,7 +1444,7 @@ var SYSTEM_PROMPT = dedent`
|
|
|
1441
1444
|
</relevance_filtering>
|
|
1442
1445
|
|
|
1443
1446
|
<constraints>
|
|
1444
|
-
- You MUST answer every relevant question with one of
|
|
1447
|
+
- You MUST answer every relevant question with one of its own listed allowed response options
|
|
1445
1448
|
- Skip irrelevant questions as described in relevance_filtering
|
|
1446
1449
|
- Only describe observable evidence from frames or transcript
|
|
1447
1450
|
- Do not fabricate details or make unsupported assumptions
|
|
@@ -1476,14 +1479,17 @@ var AUDIO_ONLY_SYSTEM_PROMPT = dedent`
|
|
|
1476
1479
|
<task>
|
|
1477
1480
|
For each question provided, you must:
|
|
1478
1481
|
1. Analyze the transcript
|
|
1479
|
-
2. Answer with ONLY the allowed response options - no other values are acceptable
|
|
1482
|
+
2. Answer with ONLY the allowed response options listed for that question - no other values are acceptable
|
|
1480
1483
|
3. Provide a confidence score between 0 and 1 reflecting your certainty
|
|
1481
1484
|
4. Explain your reasoning based on observable evidence
|
|
1482
1485
|
</task>
|
|
1483
1486
|
|
|
1484
1487
|
<answer_guidelines>
|
|
1485
|
-
-
|
|
1486
|
-
- Choose
|
|
1488
|
+
- Each question is presented as its own <question> block with a <text> element (the question) and an <allowed_answers> element (the permitted response values)
|
|
1489
|
+
- Choose only from the values listed in that question's <allowed_answers> element
|
|
1490
|
+
- Questions may have any set of allowed answers. Always read the <allowed_answers> for each question and select the best matching option based on the evidence
|
|
1491
|
+
- Select the answer best supported by observable evidence from the content
|
|
1492
|
+
- When evidence is ambiguous but some signal exists, select the most conservative option and use a low confidence score. If the question cannot be answered at all from the content, skip it per the relevance_filtering rules
|
|
1487
1493
|
- Confidence should reflect the clarity and strength of evidence:
|
|
1488
1494
|
* 0.9-1.0: Clear, unambiguous evidence
|
|
1489
1495
|
* 0.7-0.9: Strong evidence with minor ambiguity
|
|
@@ -1529,7 +1535,7 @@ var AUDIO_ONLY_SYSTEM_PROMPT = dedent`
|
|
|
1529
1535
|
</relevance_filtering>
|
|
1530
1536
|
|
|
1531
1537
|
<constraints>
|
|
1532
|
-
- You MUST answer every relevant question with one of
|
|
1538
|
+
- You MUST answer every relevant question with one of its own listed allowed response options
|
|
1533
1539
|
- Skip irrelevant questions as described in relevance_filtering
|
|
1534
1540
|
- Only describe observable evidence from transcript content
|
|
1535
1541
|
- Do not fabricate details or make unsupported assumptions
|
|
@@ -1544,46 +1550,43 @@ var AUDIO_ONLY_SYSTEM_PROMPT = dedent`
|
|
|
1544
1550
|
- GOOD: "The speaker describes running through a park"
|
|
1545
1551
|
- Be specific and evidence-based
|
|
1546
1552
|
</language_guidelines>`;
|
|
1547
|
-
var askQuestionsPromptBuilder = createPromptBuilder({
|
|
1548
|
-
template: {
|
|
1549
|
-
questions: {
|
|
1550
|
-
tag: "questions",
|
|
1551
|
-
content: "Please answer the following questions about this content:"
|
|
1552
|
-
}
|
|
1553
|
-
},
|
|
1554
|
-
sectionOrder: ["questions"]
|
|
1555
|
-
});
|
|
1556
1553
|
function buildUserPrompt({
|
|
1557
1554
|
questions,
|
|
1558
|
-
allowedAnswers,
|
|
1559
1555
|
transcriptText,
|
|
1560
1556
|
isCleanTranscript = true,
|
|
1561
1557
|
isAudioOnly = false
|
|
1562
1558
|
}) {
|
|
1563
|
-
const
|
|
1564
|
-
const
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
const
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
${
|
|
1559
|
+
const contentDescriptor = isAudioOnly ? "audio content using transcript evidence" : "content";
|
|
1560
|
+
const taskContent = dedent`
|
|
1561
|
+
Answer each question in the <questions> block below about the ${contentDescriptor}.
|
|
1562
|
+
Use only the values listed inside each question's own <allowed_answers> element.
|
|
1563
|
+
Return one answer per question, in the order the questions appear.
|
|
1564
|
+
If a question cannot be answered from the provided content, skip it as described in the system instructions.`;
|
|
1565
|
+
const taskSection = `<task>
|
|
1566
|
+
${taskContent}
|
|
1567
|
+
</task>`;
|
|
1568
|
+
const questionBlocks = questions.map((q, idx) => {
|
|
1569
|
+
const textTag = renderSection({ tag: "text", content: q.question });
|
|
1570
|
+
const answersTag = renderSection({
|
|
1571
|
+
tag: "allowed_answers",
|
|
1572
|
+
content: q.answerOptions.map((a) => `"${a}"`).join(", ")
|
|
1573
|
+
});
|
|
1574
|
+
return `<question number="${idx + 1}">
|
|
1575
|
+
${textTag}
|
|
1576
|
+
${answersTag}
|
|
1577
|
+
</question>`;
|
|
1578
|
+
}).join("\n\n");
|
|
1579
|
+
const questionsSection = `<questions>
|
|
1580
|
+
${questionBlocks}
|
|
1581
|
+
</questions>`;
|
|
1582
|
+
const sections = [];
|
|
1583
|
+
if (transcriptText) {
|
|
1584
|
+
const format = isCleanTranscript ? "plain text" : "WebVTT";
|
|
1585
|
+
sections.push(renderSection(createTranscriptSection(transcriptText, format)));
|
|
1579
1586
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
return
|
|
1583
|
-
|
|
1584
|
-
${questionsSection}
|
|
1585
|
-
|
|
1586
|
-
${responseOptions}`;
|
|
1587
|
+
sections.push(taskSection);
|
|
1588
|
+
sections.push(questionsSection);
|
|
1589
|
+
return sections.join("\n\n");
|
|
1587
1590
|
}
|
|
1588
1591
|
async function fetchImageAsBase64(imageUrl, imageDownloadOptions) {
|
|
1589
1592
|
"use step";
|
|
@@ -1652,7 +1655,6 @@ async function askQuestions(assetId, questions, options) {
|
|
|
1652
1655
|
provider = "openai",
|
|
1653
1656
|
model,
|
|
1654
1657
|
languageCode,
|
|
1655
|
-
answerOptions,
|
|
1656
1658
|
includeTranscript = true,
|
|
1657
1659
|
cleanTranscript = true,
|
|
1658
1660
|
imageSubmissionMode = "url",
|
|
@@ -1660,15 +1662,23 @@ async function askQuestions(assetId, questions, options) {
|
|
|
1660
1662
|
storyboardWidth = 640,
|
|
1661
1663
|
credentials
|
|
1662
1664
|
} = options ?? {};
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1665
|
+
const normalizedQuestions = questions.map((q, idx) => {
|
|
1666
|
+
const options2 = Array.from(
|
|
1667
|
+
new Set(
|
|
1668
|
+
(q.answerOptions?.length ? q.answerOptions : ["yes", "no"]).map((o) => o.trim()).filter(Boolean)
|
|
1669
|
+
)
|
|
1670
|
+
);
|
|
1671
|
+
if (!options2.length) {
|
|
1672
|
+
throw new MuxAiError(
|
|
1673
|
+
`Question at index ${idx} has invalid answerOptions: must include at least one non-empty value.`,
|
|
1674
|
+
{ type: "validation_error" }
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
return { ...q, answerOptions: options2 };
|
|
1678
|
+
});
|
|
1679
|
+
const allowedAnswers = Array.from(
|
|
1680
|
+
new Set(normalizedQuestions.flatMap((q) => q.answerOptions))
|
|
1667
1681
|
);
|
|
1668
|
-
if (!normalizedAnswerOptions.length) {
|
|
1669
|
-
throw new MuxAiError("answerOptions must include at least one non-empty value.", { type: "validation_error" });
|
|
1670
|
-
}
|
|
1671
|
-
const allowedAnswers = normalizedAnswerOptions;
|
|
1672
1682
|
const modelConfig = resolveLanguageModelConfig({
|
|
1673
1683
|
...options,
|
|
1674
1684
|
model,
|
|
@@ -1699,8 +1709,7 @@ async function askQuestions(assetId, questions, options) {
|
|
|
1699
1709
|
}) : void 0;
|
|
1700
1710
|
const transcriptText = transcriptResult?.transcriptText ?? "";
|
|
1701
1711
|
const userPrompt = buildUserPrompt({
|
|
1702
|
-
questions,
|
|
1703
|
-
allowedAnswers,
|
|
1712
|
+
questions: normalizedQuestions,
|
|
1704
1713
|
transcriptText,
|
|
1705
1714
|
isCleanTranscript: cleanTranscript,
|
|
1706
1715
|
isAudioOnly
|
|
@@ -1763,10 +1772,15 @@ async function askQuestions(assetId, questions, options) {
|
|
|
1763
1772
|
`Failed to generate answers for all questions for asset ${assetId}.`
|
|
1764
1773
|
);
|
|
1765
1774
|
}
|
|
1766
|
-
const answers = analysisResponse.result.answers.map((raw) => {
|
|
1775
|
+
const answers = analysisResponse.result.answers.map((raw, idx) => {
|
|
1767
1776
|
const isSkipped = raw.skipped || raw.answer === SKIP_SENTINEL;
|
|
1777
|
+
if (!isSkipped && !normalizedQuestions[idx].answerOptions.includes(raw.answer)) {
|
|
1778
|
+
throw new MuxAiError(
|
|
1779
|
+
`Answer "${raw.answer}" for question ${idx} is not in allowed options: ${normalizedQuestions[idx].answerOptions.join(", ")}`
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1768
1782
|
return {
|
|
1769
|
-
// Strip numbering prefix (e.g
|
|
1783
|
+
// Strip numbering prefix (e.g. "1. ") if the LLM prepends one
|
|
1770
1784
|
question: raw.question.replace(/^\d+\.\s*/, ""),
|
|
1771
1785
|
confidence: isSkipped ? 0 : Math.min(1, Math.max(0, raw.confidence)),
|
|
1772
1786
|
reasoning: raw.reasoning,
|