@mux/ai 0.1.2 → 0.1.4

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/image-download.ts","../src/moderation.ts","../src/summarization.ts","../src/utils/vtt-parser.ts","../src/translation.ts","../src/audio-translation.ts","../src/chapters.ts","../src/utils/storyboard-processor.ts","../src/burned-in-captions.ts","../src/index.ts"],"names":["processor","Mux","OpenAI","Anthropic","audioUrl","S3Client","Upload","GetObjectCommand","getSignedUrl","z","ANTHROPIC_JSON_PROMPT","zodTextFormat","downloadImageAsBase64"],"mappings":"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","file":"index.js","sourcesContent":["import pRetry, { AbortError } from 'p-retry';\n\nexport interface ImageDownloadOptions {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Maximum number of retry attempts (default: 3) */\n retries?: number;\n /** Base delay between retries in milliseconds (default: 1000) */\n retryDelay?: number;\n /** Maximum delay between retries in milliseconds (default: 10000) */\n maxRetryDelay?: number;\n /** Whether to use exponential backoff (default: true) */\n exponentialBackoff?: boolean;\n}\n\nexport interface ImageDownloadResult {\n /** Base64 encoded image data with data URI prefix (e.g., \"data:image/png;base64,iVBORw0K...\") */\n base64Data: string;\n /** Raw image buffer for multipart/form-data uploads */\n buffer: Buffer;\n /** Original image URL */\n url: string;\n /** Content type of the downloaded image */\n contentType: string;\n /** Size of the downloaded image in bytes */\n sizeBytes: number;\n /** Number of retry attempts made (0 if successful on first try) */\n attempts: number;\n}\n\nexport interface AnthropicFileUploadResult {\n /** Anthropic Files API file ID */\n fileId: string;\n /** Original image URL */\n url: string;\n /** Content type of the uploaded image */\n contentType: string;\n /** Size of the uploaded image in bytes */\n sizeBytes: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ImageDownloadOptions> = {\n timeout: 10000,\n retries: 3,\n retryDelay: 1000,\n maxRetryDelay: 10000,\n exponentialBackoff: true,\n};\n\n/**\n * Downloads an image from a URL and converts it to base64 with robust retry logic\n * \n * @param url - The image URL to download\n * @param options - Download configuration options\n * @returns Promise resolving to ImageDownloadResult with base64 data and metadata\n * @throws Error if download fails after all retries\n */\nexport async function downloadImageAsBase64(\n url: string,\n options: ImageDownloadOptions = {}\n): Promise<ImageDownloadResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n let attemptCount = 0;\n\n return pRetry(\n async () => {\n attemptCount++;\n \n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), opts.timeout);\n\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers: {\n 'User-Agent': '@mux/ai image downloader',\n },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n // Don't retry 4xx errors (except 429 rate limiting)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n throw new AbortError(`HTTP ${response.status}: ${response.statusText}`);\n }\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get('content-type');\n if (!contentType?.startsWith('image/')) {\n throw new AbortError(`Invalid content type: ${contentType}. Expected image/*`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n \n if (buffer.length === 0) {\n throw new AbortError('Downloaded image is empty');\n }\n\n // Convert to base64 with data URI prefix\n const base64Data = `data:${contentType};base64,${buffer.toString('base64')}`;\n\n return {\n base64Data,\n buffer,\n url,\n contentType,\n sizeBytes: buffer.length,\n attempts: attemptCount,\n };\n\n } catch (error) {\n clearTimeout(timeoutId);\n \n // If it's an AbortError (non-retryable), re-throw it\n if (error instanceof AbortError) {\n throw error;\n }\n\n // For network errors, timeout errors, etc., wrap in retryable error\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new Error(`Request timeout after ${opts.timeout}ms`);\n }\n throw new Error(`Download failed: ${error.message}`);\n }\n \n throw new Error('Unknown download error');\n }\n },\n {\n retries: opts.retries,\n minTimeout: opts.retryDelay,\n maxTimeout: opts.maxRetryDelay,\n factor: opts.exponentialBackoff ? 2 : 1,\n randomize: true, // Add jitter to prevent thundering herd\n onFailedAttempt: (error) => {\n console.warn(`Image download attempt ${error.attemptNumber} failed for ${url}`);\n if (error.retriesLeft > 0) {\n console.warn(`Retrying... (${error.retriesLeft} attempts left)`);\n }\n },\n }\n );\n}\n\n/**\n * Downloads multiple images concurrently with controlled concurrency\n * \n * @param urls - Array of image URLs to download\n * @param options - Download configuration options \n * @param maxConcurrent - Maximum concurrent downloads (default: 5)\n * @returns Promise resolving to array of ImageDownloadResult (in same order as input URLs)\n */\nexport async function downloadImagesAsBase64(\n urls: string[],\n options: ImageDownloadOptions = {},\n maxConcurrent: number = 5\n): Promise<ImageDownloadResult[]> {\n const results: ImageDownloadResult[] = [];\n \n for (let i = 0; i < urls.length; i += maxConcurrent) {\n const batch = urls.slice(i, i + maxConcurrent);\n const batchPromises = batch.map(url => downloadImageAsBase64(url, options));\n const batchResults = await Promise.all(batchPromises);\n results.push(...batchResults);\n }\n \n return results;\n}\n\n/**\n * Uploads an image to Anthropic Files API for use in messages\n * \n * @param url - The image URL to download and upload\n * @param anthropicApiKey - Anthropic API key\n * @param options - Download configuration options\n * @returns Promise resolving to AnthropicFileUploadResult with file ID and metadata\n * @throws Error if download or upload fails\n */\nexport async function uploadImageToAnthropicFiles(\n url: string,\n anthropicApiKey: string,\n options: ImageDownloadOptions = {}\n): Promise<AnthropicFileUploadResult> {\n // First download the image\n const downloadResult = await downloadImageAsBase64(url, options);\n \n // Create form data for Files API upload\n const formData = new FormData();\n \n // Create a Blob from the buffer for form data\n const imageBlob = new Blob([downloadResult.buffer], { \n type: downloadResult.contentType \n });\n \n // Get file extension from content type\n const extension = downloadResult.contentType.split('/')[1] || 'png';\n formData.append('file', imageBlob, `image.${extension}`);\n\n // Upload to Anthropic Files API\n const response = await fetch('https://api.anthropic.com/v1/files', {\n method: 'POST',\n headers: {\n 'x-api-key': anthropicApiKey,\n 'anthropic-version': '2023-06-01',\n 'anthropic-beta': 'files-api-2025-04-14',\n // Don't set Content-Type header - let fetch set it with boundary for multipart\n },\n body: formData\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Anthropic Files API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const fileResult = await response.json() as { id: string };\n \n return {\n fileId: fileResult.id,\n url: downloadResult.url,\n contentType: downloadResult.contentType,\n sizeBytes: downloadResult.sizeBytes,\n };\n}","import Mux from '@mux/mux-node';\nimport OpenAI from 'openai';\nimport { MuxAIOptions } from './types';\nimport { ImageDownloadOptions, downloadImagesAsBase64 } from './utils/image-download';\n\nexport interface ThumbnailModerationScore {\n url: string;\n sexual: number;\n violence: number;\n error: boolean;\n}\n\nexport interface ModerationResult {\n assetId: string;\n thumbnailScores: ThumbnailModerationScore[];\n maxScores: {\n sexual: number;\n violence: number;\n };\n exceedsThreshold: boolean;\n thresholds: {\n sexual: number;\n violence: number;\n };\n}\n\nexport interface ModerationOptions extends MuxAIOptions {\n provider?: 'openai' | 'hive';\n model?: string;\n thresholds?: {\n sexual?: number;\n violence?: number;\n };\n thumbnailInterval?: number;\n thumbnailWidth?: number;\n maxConcurrent?: number;\n /** Method for submitting images to AI providers (default: 'url') */\n imageSubmissionMode?: 'url' | 'base64';\n /** Options for image download when using base64 submission mode */\n imageDownloadOptions?: ImageDownloadOptions;\n hiveApiKey?: string;\n}\n\nconst DEFAULT_THRESHOLDS = {\n sexual: 0.7,\n violence: 0.8\n};\n\n// Process promises in batches with maximum concurrency limit\nasync function processConcurrently<T>(\n items: any[],\n processor: (item: any) => Promise<T>,\n maxConcurrent: number = 5\n): Promise<T[]> {\n const results: T[] = [];\n \n for (let i = 0; i < items.length; i += maxConcurrent) {\n const batch = items.slice(i, i + maxConcurrent);\n const batchPromises = batch.map(processor);\n const batchResults = await Promise.all(batchPromises);\n results.push(...batchResults);\n }\n \n return results;\n}\n\n// Mapping Hive categories to OpenAI-compatible scores\nconst HIVE_SEXUAL_CATEGORIES = [\n 'general_nsfw',\n 'general_suggestive', \n 'yes_sexual_activity',\n 'female_underwear',\n 'male_underwear',\n 'bra',\n 'panties',\n 'sex_toys',\n 'nudity_female',\n 'nudity_male',\n 'cleavage',\n 'swimwear'\n];\n\nconst HIVE_VIOLENCE_CATEGORIES = [\n 'gun_in_hand',\n 'gun_not_in_hand',\n 'animated_gun',\n 'knife_in_hand',\n 'knife_not_in_hand',\n 'culinary_knife_not_in_hand',\n 'culinary_knife_in_hand',\n 'very_bloody',\n 'a_little_bloody',\n 'other_blood',\n 'hanging',\n 'noose',\n 'human_corpse',\n 'animated_corpse',\n 'emaciated_body',\n 'self_harm',\n 'animal_abuse',\n 'fights',\n 'garm_death_injury_or_military_conflict'\n];\n\n// Generates thumbnail URLs at regular intervals based on video duration\nfunction getThumbnailUrls(playbackId: string, duration: number, options: { interval?: number; width?: number } = {}): string[] {\n const { interval = 10, width = 640 } = options;\n const timestamps: number[] = [];\n\n if (duration <= 50) {\n // Short videos: 5 evenly spaced thumbnails\n const spacing = duration / 6;\n for (let i = 1; i <= 5; i++) {\n timestamps.push(Math.round(i * spacing));\n }\n } else {\n // Longer videos: one thumbnail every interval seconds\n for (let time = 0; time < duration; time += interval) {\n timestamps.push(time);\n }\n }\n\n return timestamps.map(\n (time) => `https://image.mux.com/${playbackId}/thumbnail.png?time=${time}&width=${width}`\n );\n}\n\n// Sends thumbnail URLs to OpenAI moderation API with concurrency limiting\nasync function requestOpenAIModeration(\n imageUrls: string[], \n openaiClient: OpenAI, \n model: string, \n maxConcurrent: number = 5,\n submissionMode: 'url' | 'base64' = 'url',\n downloadOptions?: ImageDownloadOptions\n): Promise<ThumbnailModerationScore[]> {\n \n // If using base64 mode, download all images first\n if (submissionMode === 'base64') {\n \n try {\n const downloadResults = await downloadImagesAsBase64(imageUrls, downloadOptions, maxConcurrent);\n \n // Process each downloaded image through OpenAI moderation\n const processor = async (downloadResult: typeof downloadResults[0]): Promise<ThumbnailModerationScore> => {\n try {\n const moderation = await openaiClient.moderations.create({\n model,\n input: [\n {\n type: \"image_url\",\n image_url: {\n url: downloadResult.base64Data, // Use base64 data URI\n },\n },\n ],\n });\n\n const categoryScores = moderation.results[0].category_scores;\n\n return {\n url: downloadResult.url, // Return original URL for tracking\n sexual: categoryScores.sexual || 0,\n violence: categoryScores.violence || 0,\n error: false\n };\n\n } catch (error) {\n console.error(`Failed to moderate downloaded image ${downloadResult.url}:`, error);\n return {\n url: downloadResult.url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(downloadResults, processor, maxConcurrent);\n \n } catch (error) {\n console.error('Failed to download images for base64 submission:', error);\n // Return error results for all URLs\n return imageUrls.map(url => ({\n url,\n sexual: 0,\n violence: 0,\n error: true,\n }));\n }\n }\n \n // Original URL-based submission mode\n const processor = async (url: string): Promise<ThumbnailModerationScore> => {\n try {\n const moderation = await openaiClient.moderations.create({\n model,\n input: [\n {\n type: \"image_url\",\n image_url: {\n url: url,\n },\n },\n ],\n });\n\n const categoryScores = moderation.results[0].category_scores;\n\n return {\n url,\n sexual: categoryScores.sexual || 0,\n violence: categoryScores.violence || 0,\n error: false\n };\n\n } catch (error) {\n console.error(\"Failed to moderate image:\", error);\n return {\n url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(imageUrls, processor, maxConcurrent);\n}\n\n// Sends thumbnail URLs to Hive moderation API with concurrency limiting\nasync function requestHiveModeration(\n imageUrls: string[], \n hiveApiKey: string, \n maxConcurrent: number = 5,\n submissionMode: 'url' | 'base64' = 'url',\n downloadOptions?: ImageDownloadOptions\n): Promise<ThumbnailModerationScore[]> {\n \n // If using base64 mode, download all images first and upload via multipart/form-data\n if (submissionMode === 'base64') {\n \n try {\n const downloadResults = await downloadImagesAsBase64(imageUrls, downloadOptions, maxConcurrent);\n \n // Process each downloaded image through Hive moderation via file upload\n const processor = async (downloadResult: typeof downloadResults[0]): Promise<ThumbnailModerationScore> => {\n try {\n // Create form data with image buffer\n const formData = new FormData();\n \n // Create a Blob from the buffer for form data\n const imageBlob = new Blob([downloadResult.buffer], { \n type: downloadResult.contentType \n });\n \n // Get file extension from content type\n const extension = downloadResult.contentType.split('/')[1] || 'png';\n formData.append('media', imageBlob, `image.${extension}`);\n\n const response = await fetch('https://api.thehive.ai/api/v2/task/sync', {\n method: 'POST',\n headers: {\n 'Authorization': `Token ${hiveApiKey}`,\n // Don't set Content-Type header - let fetch set it with boundary for multipart\n },\n body: formData\n });\n\n if (!response.ok) {\n throw new Error(`Hive API error: ${response.statusText}`);\n }\n\n const hiveResult = await response.json() as any;\n \n // Extract scores from Hive response and map to OpenAI format\n const classes = hiveResult.status?.[0]?.response?.output?.[0]?.classes || [];\n const scoreMap = Object.fromEntries(classes.map((c: any) => [c.class, c.score]));\n \n const sexualScores = HIVE_SEXUAL_CATEGORIES.map(category => \n scoreMap[category] || 0\n );\n const violenceScores = HIVE_VIOLENCE_CATEGORIES.map(category => \n scoreMap[category] || 0\n );\n\n return {\n url: downloadResult.url, // Return original URL for tracking\n sexual: Math.max(...sexualScores, 0),\n violence: Math.max(...violenceScores, 0),\n error: false\n };\n\n } catch (error) {\n console.error(`Failed to moderate uploaded image ${downloadResult.url}:`, error);\n return {\n url: downloadResult.url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(downloadResults, processor, maxConcurrent);\n \n } catch (error) {\n console.error('Failed to download images for Hive multipart upload:', error);\n // Return error results for all URLs\n return imageUrls.map(url => ({\n url,\n sexual: 0,\n violence: 0,\n error: true,\n }));\n }\n }\n \n // Original URL-based submission mode\n const processor = async (url: string): Promise<ThumbnailModerationScore> => {\n try {\n const response = await fetch('https://api.thehive.ai/api/v2/task/sync', {\n method: 'POST',\n headers: {\n 'Authorization': `Token ${hiveApiKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ url })\n });\n\n if (!response.ok) {\n throw new Error(`Hive API error: ${response.statusText}`);\n }\n\n const hiveResult = await response.json() as any;\n \n // Extract scores from Hive response and map to OpenAI format\n // Hive returns scores in status[0].response.output[0].classes as array of {class, score}\n const classes = hiveResult.status?.[0]?.response?.output?.[0]?.classes || [];\n const scoreMap = Object.fromEntries(classes.map((c: any) => [c.class, c.score]));\n \n const sexualScores = HIVE_SEXUAL_CATEGORIES.map(category => \n scoreMap[category] || 0\n );\n const violenceScores = HIVE_VIOLENCE_CATEGORIES.map(category => \n scoreMap[category] || 0\n );\n\n return {\n url,\n sexual: Math.max(...sexualScores, 0),\n violence: Math.max(...violenceScores, 0),\n error: false\n };\n\n } catch (error) {\n console.error(\"Failed to moderate image with Hive:\", error);\n return {\n url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(imageUrls, processor, maxConcurrent);\n}\n\nexport async function getModerationScores(\n assetId: string,\n options: ModerationOptions = {}\n): Promise<ModerationResult> {\n const {\n provider = 'openai',\n model = 'omni-moderation-latest',\n thresholds = DEFAULT_THRESHOLDS,\n thumbnailInterval = 10,\n thumbnailWidth = 640,\n maxConcurrent = 5,\n imageSubmissionMode = 'url',\n imageDownloadOptions,\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n ...config\n } = options;\n\n if (provider !== 'openai' && provider !== 'hive') {\n throw new Error('Only OpenAI and Hive providers are currently supported');\n }\n\n // Validate required credentials\n const muxId = muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n const openaiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n const hiveKey = options.hiveApiKey || process.env.HIVE_API_KEY;\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n if (provider === 'openai' && !openaiKey) {\n throw new Error('OpenAI API key is required for OpenAI provider. Provide openaiApiKey in options or set OPENAI_API_KEY environment variable.');\n }\n\n if (provider === 'hive' && !hiveKey) {\n throw new Error('Hive API key is required for Hive provider. Provide hiveApiKey in options or set HIVE_API_KEY environment variable.');\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n let openaiClient: OpenAI | undefined;\n if (provider === 'openai') {\n openaiClient = new OpenAI({\n apiKey: openaiKey!,\n });\n }\n\n // Fetch asset data from Mux\n let assetData;\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n assetData = asset;\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Get playback ID - prefer public playback IDs\n const publicPlaybackIds = assetData.playback_ids?.filter(pid => pid.policy === 'public') || [];\n \n if (publicPlaybackIds.length === 0) {\n throw new Error('No public playback IDs found for this asset. Moderation requires public playback access.');\n }\n\n const playbackId = publicPlaybackIds[0].id;\n const duration = assetData.duration || 0;\n\n // Generate thumbnail URLs\n const thumbnailUrls = getThumbnailUrls(playbackId, duration, {\n interval: thumbnailInterval,\n width: thumbnailWidth\n });\n\n // Request moderation for all thumbnails\n let thumbnailScores: ThumbnailModerationScore[];\n \n if (provider === 'openai') {\n thumbnailScores = await requestOpenAIModeration(\n thumbnailUrls, \n openaiClient!, \n model, \n maxConcurrent, \n imageSubmissionMode, \n imageDownloadOptions\n );\n } else if (provider === 'hive') {\n thumbnailScores = await requestHiveModeration(\n thumbnailUrls, \n hiveKey!, \n maxConcurrent, \n imageSubmissionMode, \n imageDownloadOptions\n );\n } else {\n throw new Error('Unsupported provider');\n }\n \n // Find highest scores across all thumbnails\n const maxSexual = Math.max(...thumbnailScores.map(s => s.sexual));\n const maxViolence = Math.max(...thumbnailScores.map(s => s.violence));\n \n const finalThresholds = { ...DEFAULT_THRESHOLDS, ...thresholds };\n \n return {\n assetId,\n thumbnailScores,\n maxScores: {\n sexual: maxSexual,\n violence: maxViolence\n },\n exceedsThreshold: maxSexual > finalThresholds.sexual || maxViolence > finalThresholds.violence,\n thresholds: finalThresholds\n };\n}","import Mux from '@mux/mux-node';\nimport OpenAI from 'openai';\nimport Anthropic from '@anthropic-ai/sdk';\nimport { z } from 'zod';\nimport { zodTextFormat } from 'openai/helpers/zod';\nimport { MuxAIOptions, ToneType } from './types';\nimport { ImageDownloadOptions, downloadImageAsBase64, uploadImageToAnthropicFiles } from './utils/image-download';\nimport { extractTextFromVTT } from './utils/vtt-parser';\n\nexport interface SummaryAndTagsResult {\n assetId: string;\n title: string;\n description: string;\n tags: string[];\n storyboardUrl?: string;\n}\n\nexport interface SummarizationOptions extends MuxAIOptions {\n provider?: 'openai' | 'anthropic';\n model?: string;\n maxSummaryLength?: number;\n maxTags?: number;\n customPrompt?: string;\n tone?: ToneType;\n includeTranscript?: boolean;\n /** Whether to clean VTT timestamps and formatting from transcript (default: true) */\n cleanTranscript?: boolean;\n /** Method for submitting storyboard to AI providers (default: 'url') */\n imageSubmissionMode?: 'url' | 'base64';\n /** Options for image download when using base64 submission mode */\n imageDownloadOptions?: ImageDownloadOptions;\n}\n\nconst summarySchema = z.object({\n keywords: z.array(z.string()).max(10),\n title: z.string().max(100),\n description: z.string().max(1000)\n});\n\nconst DEFAULT_PROMPT = \"Generate a short title (max 100 characters) and description (max 500 characters) for what happens. Start immediately with the action or subject - never reference that this is a video, content, or storyboard. Example: Title: 'Cooking Pasta Tutorial' Description: 'Someone cooks pasta by boiling water and adding noodles.'\";\n\nconst ANTHROPIC_JSON_PROMPT = `You must respond with valid JSON in exactly this format:\n{\n \"title\": \"Your title here (max 100 characters)\",\n \"description\": \"Your description here (max 500 characters)\",\n \"keywords\": [\"keyword1\", \"keyword2\", \"keyword3\"]\n}\n\nDo not include any text before or after the JSON. The JSON must be valid and parseable.`;\n\nexport async function getSummaryAndTags(\n assetId: string,\n promptOrOptions?: string | SummarizationOptions,\n options?: SummarizationOptions\n): Promise<SummaryAndTagsResult> {\n // Handle overloaded parameters\n let prompt: string;\n let actualOptions: SummarizationOptions;\n \n if (typeof promptOrOptions === 'string') {\n prompt = promptOrOptions;\n actualOptions = options || {};\n } else {\n prompt = DEFAULT_PROMPT;\n actualOptions = promptOrOptions || {};\n }\n const {\n provider = 'openai',\n model,\n tone = 'normal',\n includeTranscript = true,\n cleanTranscript = true,\n imageSubmissionMode = 'url',\n imageDownloadOptions,\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n anthropicApiKey,\n ...config\n } = actualOptions;\n\n // Set default models based on provider\n const defaultModel = provider === 'anthropic' ? 'claude-3-5-haiku-20241022' : 'gpt-4o-mini';\n const finalModel = model || defaultModel;\n\n // Validate required credentials\n const muxId = muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n const openaiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n if (provider === 'openai' && !openaiKey) {\n throw new Error('OpenAI API key is required. Provide openaiApiKey in options or set OPENAI_API_KEY environment variable.');\n }\n\n if (provider === 'anthropic' && !anthropicKey) {\n throw new Error('Anthropic API key is required. Provide anthropicApiKey in options or set ANTHROPIC_API_KEY environment variable.');\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n let openaiClient: OpenAI | undefined;\n let anthropicClient: Anthropic | undefined;\n\n if (provider === 'openai') {\n openaiClient = new OpenAI({\n apiKey: openaiKey!,\n });\n } else if (provider === 'anthropic') {\n anthropicClient = new Anthropic({\n apiKey: anthropicKey!,\n });\n }\n\n // Fetch asset data from Mux\n let assetData;\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n assetData = asset;\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Get playback ID for storyboard URL\n const playbackId = assetData.playback_ids?.[0]?.id;\n if (!playbackId) {\n throw new Error('No playback ID found for this asset');\n }\n\n // Check for text tracks and fetch transcript if available\n let transcriptText = '';\n if (includeTranscript && assetData.tracks) {\n const textTrack = assetData.tracks.find((track) => \n track.type === 'text' && track.status === 'ready'\n );\n \n if (textTrack) {\n const transcriptUrl = `https://stream.mux.com/${playbackId}/text/${textTrack.id}.vtt`;\n \n try {\n const transcriptResponse = await fetch(transcriptUrl);\n if (transcriptResponse.ok) {\n const rawVttContent = await transcriptResponse.text();\n // Use clean text or raw VTT based on user preference\n transcriptText = cleanTranscript \n ? extractTextFromVTT(rawVttContent)\n : rawVttContent;\n }\n } catch (error) {\n console.warn('Failed to fetch transcript:', error);\n }\n }\n }\n\n // Create tone-informed prompt\n let toneInstruction = '';\n switch (tone) {\n case 'sassy':\n toneInstruction = ' Answer with a sassy, playful attitude and personality.';\n break;\n case 'professional':\n toneInstruction = ' Provide a professional, executive-level analysis suitable for business reporting.';\n break;\n default: // normal\n toneInstruction = ' Provide a clear, straightforward analysis.';\n }\n\n // Add transcript context to prompt if available\n let contextualPrompt = prompt + toneInstruction;\n if (transcriptText) {\n const transcriptType = cleanTranscript ? 'transcript' : 'WebVTT transcript';\n contextualPrompt += ` Use the following ${transcriptType} for additional context: \"${transcriptText}\"`;\n }\n\n // Analyze storyboard with AI provider\n const imageUrl = `https://image.mux.com/${playbackId}/storyboard.png?width=640`;\n \n let aiAnalysis: { title?: string; description?: string; keywords?: string[] } | null = null;\n let retryAttempt = 0;\n const maxRetries = 3;\n \n if (provider === 'openai') {\n // Handle base64 vs URL submission modes\n if (imageSubmissionMode === 'base64') {\n \n try {\n const downloadResult = await downloadImageAsBase64(imageUrl, imageDownloadOptions);\n \n const response = await openaiClient!.responses.parse({\n model: finalModel,\n input: [\n {\n role: \"system\",\n content: \"You are an image analysis tool. You will be given a storyboard image from a video showing multiple frames/scenes, and be expected to return structured data about the contents across all the frames.\",\n },\n {\n role: \"user\",\n content: [\n {\n type: \"input_text\",\n text: contextualPrompt,\n },\n {\n type: \"input_image\",\n image_url: downloadResult.base64Data, // Use base64 data URI\n detail: \"high\",\n },\n ],\n },\n ],\n text: {\n format: zodTextFormat(summarySchema, \"analysis\"),\n },\n });\n\n aiAnalysis = response.output_parsed;\n \n } catch (error: unknown) {\n throw new Error(`Failed to analyze video content with OpenAI in base64 mode: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n // Original URL-based submission with retry logic\n while (retryAttempt <= maxRetries) {\n try {\n const response = await openaiClient!.responses.parse({\n model: finalModel,\n input: [\n {\n role: \"system\",\n content: \"You are an image analysis tool. You will be given a storyboard image from a video showing multiple frames/scenes, and be expected to return structured data about the contents across all the frames.\",\n },\n {\n role: \"user\",\n content: [\n {\n type: \"input_text\",\n text: contextualPrompt,\n },\n {\n type: \"input_image\",\n image_url: imageUrl,\n detail: \"high\",\n },\n ],\n },\n ],\n text: {\n format: zodTextFormat(summarySchema, \"analysis\"),\n },\n });\n\n aiAnalysis = response.output_parsed;\n break; // Success, exit retry loop\n \n } catch (error: unknown) {\n const isTimeoutError = error instanceof Error && error.message && error.message.includes('Timeout while downloading');\n \n if (isTimeoutError && retryAttempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, 5000));\n retryAttempt++;\n continue;\n }\n \n throw new Error(`Failed to analyze video content with OpenAI: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n }\n } else if (provider === 'anthropic') {\n // Anthropic doesn't have structured outputs, so we use prompt engineering\n const anthropicPrompt = `${contextualPrompt}\n\n${ANTHROPIC_JSON_PROMPT}`;\n \n // Handle base64 vs URL submission modes\n if (imageSubmissionMode === 'base64') {\n \n try {\n // Upload to Files API instead of using base64 inline (no 5MB limit)\n const fileUploadResult = await uploadImageToAnthropicFiles(imageUrl, anthropicKey!, imageDownloadOptions);\n \n \n const response = await anthropicClient!.messages.create({\n model: finalModel,\n max_tokens: 1000,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"file\",\n file_id: fileUploadResult.fileId,\n } as any, // Type assertion for Files API support\n },\n {\n type: \"text\",\n text: anthropicPrompt,\n },\n ],\n },\n ],\n }, {\n headers: {\n 'anthropic-beta': 'files-api-2025-04-14'\n }\n });\n\n const content = response.content[0];\n if (content.type === 'text') {\n const jsonText = content.text.trim();\n try {\n aiAnalysis = JSON.parse(jsonText);\n } catch (parseError) {\n throw new Error(`Failed to parse JSON response from Anthropic: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`);\n }\n } else {\n throw new Error('Unexpected response type from Anthropic');\n }\n \n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`Failed to analyze video content with Anthropic Files API: ${errorMessage}`);\n }\n } else {\n // URL-based submission with retry logic\n while (retryAttempt <= maxRetries) {\n try {\n const response = await anthropicClient!.messages.create({\n model: finalModel,\n max_tokens: 1000,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"url\",\n url: imageUrl,\n } as any, // Type assertion to work around SDK type definitions\n },\n {\n type: \"text\",\n text: anthropicPrompt,\n },\n ],\n },\n ],\n });\n\n const content = response.content[0];\n if (content.type === 'text') {\n // Parse JSON from Anthropic response\n const jsonText = content.text.trim();\n try {\n aiAnalysis = JSON.parse(jsonText);\n break; // Success, exit retry loop\n } catch (parseError) {\n if (retryAttempt < maxRetries) {\n console.warn(`Failed to parse JSON from Anthropic (attempt ${retryAttempt + 1}):`, jsonText);\n retryAttempt++;\n await new Promise(resolve => setTimeout(resolve, 2000));\n continue;\n }\n throw new Error(`Failed to parse JSON response from Anthropic: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`);\n }\n } else {\n throw new Error('Unexpected response type from Anthropic');\n }\n \n } catch (error: unknown) {\n if (retryAttempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, 5000));\n retryAttempt++;\n continue;\n }\n \n throw new Error(`Failed to analyze video content with Anthropic: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n }\n } else {\n throw new Error(`Unsupported provider: ${provider}`);\n }\n\n if (!aiAnalysis) {\n throw new Error('No analysis result received from AI provider');\n }\n\n return {\n assetId,\n title: aiAnalysis.title || 'No title available',\n description: aiAnalysis.description || 'No description available',\n tags: aiAnalysis.keywords || [],\n storyboardUrl: imageUrl,\n };\n}","/**\n * Parses WebVTT content and extracts clean text for AI processing\n * \n * @param vttContent - Raw WebVTT content\n * @returns Clean transcript text without timestamps and markers\n */\nexport function extractTextFromVTT(vttContent: string): string {\n if (!vttContent.trim()) {\n return '';\n }\n\n const lines = vttContent.split('\\n');\n const textLines: string[] = [];\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n \n // Skip empty lines\n if (!line) continue;\n \n // Skip WEBVTT header\n if (line === 'WEBVTT') continue;\n \n // Skip NOTE lines\n if (line.startsWith('NOTE ')) continue;\n \n // Skip timestamp lines (contain -->)\n if (line.includes('-->')) continue;\n \n // Skip cue identifiers (numeric or UUID-like patterns)\n if (/^[\\d\\w-]+$/.test(line) && !line.includes(' ')) continue;\n \n // Skip style/formatting tags\n if (line.startsWith('STYLE') || line.startsWith('REGION')) continue;\n \n // This should be subtitle text\n // Remove any inline formatting tags like <c.color> or <b>\n const cleanLine = line.replace(/<[^>]*>/g, '').trim();\n \n if (cleanLine) {\n textLines.push(cleanLine);\n }\n }\n \n // Join all text lines with spaces and clean up multiple spaces\n return textLines.join(' ').replace(/\\s+/g, ' ').trim();\n}","import Mux from '@mux/mux-node';\nimport Anthropic from '@anthropic-ai/sdk';\nimport { S3Client } from '@aws-sdk/client-s3';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { GetObjectCommand } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { MuxAIOptions } from './types';\n\nexport interface TranslationResult {\n assetId: string;\n sourceLanguageCode: string;\n targetLanguageCode: string;\n originalVtt: string;\n translatedVtt: string;\n uploadedTrackId?: string;\n presignedUrl?: string;\n}\n\nexport interface TranslationOptions extends MuxAIOptions {\n provider?: 'anthropic';\n model?: string;\n s3Endpoint?: string;\n s3Region?: string;\n s3Bucket?: string;\n s3AccessKeyId?: string;\n s3SecretAccessKey?: string;\n uploadToMux?: boolean;\n}\n\nexport async function translateCaptions(\n assetId: string,\n fromLanguageCode: string,\n toLanguageCode: string,\n options: TranslationOptions = {}\n): Promise<TranslationResult> {\n const {\n provider = 'anthropic',\n model = 'claude-sonnet-4-20250514',\n muxTokenId,\n muxTokenSecret,\n anthropicApiKey,\n ...config\n } = options;\n\n if (provider !== 'anthropic') {\n throw new Error('Only Anthropic provider is currently supported for translation');\n }\n\n // Validate required credentials\n const muxId = muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n \n // S3 configuration\n const s3Endpoint = options.s3Endpoint || process.env.S3_ENDPOINT;\n const s3Region = options.s3Region || process.env.S3_REGION || 'auto';\n const s3Bucket = options.s3Bucket || process.env.S3_BUCKET;\n const s3AccessKeyId = options.s3AccessKeyId || process.env.S3_ACCESS_KEY_ID;\n const s3SecretAccessKey = options.s3SecretAccessKey || process.env.S3_SECRET_ACCESS_KEY;\n const uploadToMux = options.uploadToMux !== false; // Default to true\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n if (!anthropicKey) {\n throw new Error('Anthropic API key is required. Provide anthropicApiKey in options or set ANTHROPIC_API_KEY environment variable.');\n }\n \n if (uploadToMux && (!s3Endpoint || !s3Bucket || !s3AccessKeyId || !s3SecretAccessKey)) {\n throw new Error('S3 configuration is required for uploading to Mux. Provide s3Endpoint, s3Bucket, s3AccessKeyId, and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.');\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n const anthropicClient = new Anthropic({\n apiKey: anthropicKey,\n });\n\n // Fetch asset data from Mux\n let assetData;\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n assetData = asset;\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Get playback ID for caption URL\n const playbackId = assetData.playback_ids?.[0]?.id;\n if (!playbackId) {\n throw new Error('No playback ID found for this asset');\n }\n\n // Find text track with the source language\n if (!assetData.tracks) {\n throw new Error('No tracks found for this asset');\n }\n\n const sourceTextTrack = assetData.tracks.find((track) => \n track.type === 'text' && \n track.status === 'ready' && \n track.language_code === fromLanguageCode\n );\n\n if (!sourceTextTrack) {\n throw new Error(`No ready text track found with language code '${fromLanguageCode}' for this asset`);\n }\n\n // Fetch the VTT file content\n const vttUrl = `https://stream.mux.com/${playbackId}/text/${sourceTextTrack.id}.vtt`;\n let vttContent: string;\n \n try {\n const vttResponse = await fetch(vttUrl);\n if (!vttResponse.ok) {\n throw new Error(`Failed to fetch VTT file: ${vttResponse.statusText}`);\n }\n vttContent = await vttResponse.text();\n } catch (error) {\n throw new Error(`Failed to fetch VTT content: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n console.log(`✅ Found VTT content for language '${fromLanguageCode}'`);\n\n // Translate VTT content using Anthropic\n let translatedVtt: string;\n \n try {\n const response = await anthropicClient.messages.create({\n model,\n max_tokens: 4000,\n messages: [\n {\n role: 'user',\n content: `Translate the following VTT subtitle file from ${fromLanguageCode} to ${toLanguageCode}. Return the translated VTT in JSON format with the key 'translation'. Preserve all timestamps and VTT formatting exactly as they appear.\\n\\n${vttContent}`\n }\n ]\n });\n\n const content = response.content[0];\n if (content.type === 'text') {\n // Parse JSON from Anthropic response\n const responseText = content.text.trim();\n try {\n // Remove code block markers if present\n const cleanedResponse = responseText.replace(/```json/g, '').replace(/```/g, '').trim();\n const parsed = JSON.parse(cleanedResponse);\n translatedVtt = parsed.translation;\n } catch (parseError) {\n throw new Error(`Failed to parse JSON response from Anthropic: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`);\n }\n } else {\n throw new Error('Unexpected response type from Anthropic');\n }\n } catch (error) {\n throw new Error(`Failed to translate VTT with Anthropic: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n console.log(`\\n✅ Translation completed successfully!`);\n \n // If uploadToMux is false, just return the translation\n if (!uploadToMux) {\n console.log(`✅ VTT translated to ${toLanguageCode} successfully!`);\n \n return {\n assetId,\n sourceLanguageCode: fromLanguageCode,\n targetLanguageCode: toLanguageCode,\n originalVtt: vttContent,\n translatedVtt: translatedVtt\n };\n }\n \n // Upload translated VTT to S3-compatible storage\n console.log('📤 Uploading translated VTT to S3-compatible storage...');\n \n const s3Client = new S3Client({\n region: s3Region,\n endpoint: s3Endpoint,\n credentials: {\n accessKeyId: s3AccessKeyId!,\n secretAccessKey: s3SecretAccessKey!\n },\n forcePathStyle: true // Often needed for non-AWS S3 services\n });\n \n // Create unique key for the VTT file\n const vttKey = `translations/${assetId}/${fromLanguageCode}-to-${toLanguageCode}-${Date.now()}.vtt`;\n \n let presignedUrl: string;\n \n try {\n // Upload VTT to S3\n const upload = new Upload({\n client: s3Client,\n params: {\n Bucket: s3Bucket!,\n Key: vttKey,\n Body: translatedVtt,\n ContentType: 'text/vtt'\n }\n });\n \n await upload.done();\n console.log(`✅ VTT uploaded successfully to: ${vttKey}`);\n \n // Generate presigned URL (valid for 1 hour)\n const getObjectCommand = new GetObjectCommand({\n Bucket: s3Bucket!,\n Key: vttKey\n });\n \n presignedUrl = await getSignedUrl(s3Client, getObjectCommand, { \n expiresIn: 3600 // 1 hour\n });\n \n console.log(`🔗 Generated presigned URL (expires in 1 hour)`);\n \n } catch (error) {\n throw new Error(`Failed to upload VTT to S3: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n \n // Add translated track to Mux asset\n console.log('📹 Adding translated track to Mux asset...');\n \n let uploadedTrackId: string | undefined;\n \n try {\n const languageName = new Intl.DisplayNames(['en'], { type: 'language' }).of(toLanguageCode) || toLanguageCode.toUpperCase();\n const trackName = `${languageName} (auto-translated)`;\n \n const trackResponse = await mux.video.assets.createTrack(assetId, {\n type: 'text',\n text_type: 'subtitles',\n language_code: toLanguageCode,\n name: trackName,\n url: presignedUrl\n });\n \n uploadedTrackId = trackResponse.id;\n console.log(`✅ Track added to Mux asset with ID: ${uploadedTrackId}`);\n console.log(`📋 Track name: \"${trackName}\"`);\n \n } catch (error) {\n console.warn(`⚠️ Failed to add track to Mux asset: ${error instanceof Error ? error.message : 'Unknown error'}`);\n console.log('🔗 You can manually add the track using this presigned URL:');\n console.log(presignedUrl);\n }\n \n return {\n assetId,\n sourceLanguageCode: fromLanguageCode,\n targetLanguageCode: toLanguageCode,\n originalVtt: vttContent,\n translatedVtt: translatedVtt,\n uploadedTrackId,\n presignedUrl\n };\n}","import Mux from '@mux/mux-node';\n// Using direct HTTP requests instead of SDK for better compatibility\nimport { S3Client } from '@aws-sdk/client-s3';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { GetObjectCommand } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { MuxAIOptions } from './types';\n\nexport interface AudioTranslationResult {\n assetId: string;\n targetLanguageCode: string;\n dubbingId: string;\n uploadedTrackId?: string;\n presignedUrl?: string;\n}\n\nexport interface AudioTranslationOptions extends MuxAIOptions {\n provider?: 'elevenlabs';\n numSpeakers?: number;\n s3Endpoint?: string;\n s3Region?: string;\n s3Bucket?: string;\n s3AccessKeyId?: string;\n s3SecretAccessKey?: string;\n uploadToMux?: boolean;\n elevenLabsApiKey?: string;\n}\n\nexport async function translateAudio(\n assetId: string,\n toLanguageCode: string,\n options: AudioTranslationOptions = {}\n): Promise<AudioTranslationResult> {\n // Uses the default audio track on your asset, language is auto-detected by ElevenLabs\n const {\n provider = 'elevenlabs',\n numSpeakers = 0, // 0 = auto-detect\n muxTokenId,\n muxTokenSecret,\n elevenLabsApiKey,\n uploadToMux = true,\n ...config\n } = options;\n\n if (provider !== 'elevenlabs') {\n throw new Error('Only ElevenLabs provider is currently supported for audio translation');\n }\n\n // Validate required credentials\n const muxId = muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n const elevenLabsKey = elevenLabsApiKey || process.env.ELEVENLABS_API_KEY;\n \n // S3 configuration\n const s3Endpoint = options.s3Endpoint || process.env.S3_ENDPOINT;\n const s3Region = options.s3Region || process.env.S3_REGION || 'auto';\n const s3Bucket = options.s3Bucket || process.env.S3_BUCKET;\n const s3AccessKeyId = options.s3AccessKeyId || process.env.S3_ACCESS_KEY_ID;\n const s3SecretAccessKey = options.s3SecretAccessKey || process.env.S3_SECRET_ACCESS_KEY;\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n if (!elevenLabsKey) {\n throw new Error('ElevenLabs API key is required. Provide elevenLabsApiKey in options or set ELEVENLABS_API_KEY environment variable.');\n }\n \n if (uploadToMux && (!s3Endpoint || !s3Bucket || !s3AccessKeyId || !s3SecretAccessKey)) {\n throw new Error('S3 configuration is required for uploading to Mux. Provide s3Endpoint, s3Bucket, s3AccessKeyId, and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.');\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n // Fetch asset data from Mux\n console.log(`🎬 Fetching Mux asset: ${assetId}`);\n let assetData;\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n assetData = asset;\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Check for audio-only static rendition\n console.log('🔍 Checking for audio-only static rendition...');\n \n if (!assetData.static_renditions || !assetData.static_renditions.files) {\n throw new Error('No static renditions found for this asset');\n }\n\n const staticRenditionFiles = assetData.static_renditions.files as any[];\n\n if (staticRenditionFiles.length === 0) {\n throw new Error('No static rendition files found for this asset');\n }\n\n const audioRendition = staticRenditionFiles.find((rendition: any) => \n rendition.name === 'audio.m4a' && rendition.status === 'ready'\n );\n\n if (!audioRendition) {\n throw new Error('No ready audio-only static rendition found for this asset. Please ensure the asset has an audio.m4a static rendition.');\n }\n\n const audioUrl = `https://stream.mux.com/${assetData.playback_ids?.[0]?.id}/audio.m4a`;\n console.log(`✅ Found audio rendition: ${audioUrl}`);\n\n // Create dubbing job in ElevenLabs\n console.log(`🎙️ Creating ElevenLabs dubbing job (auto-detect → ${toLanguageCode})`);\n \n let dubbingId: string;\n \n try {\n // Fetch audio file and create dubbing job\n const audioResponse = await fetch(audioUrl);\n if (!audioResponse.ok) {\n throw new Error(`Failed to fetch audio file: ${audioResponse.statusText}`);\n }\n \n const audioBuffer = await audioResponse.arrayBuffer();\n const audioBlob = new Blob([audioBuffer], { type: 'audio/mp4' });\n const audioFile = audioBlob as any; // ElevenLabs accepts Blob\n \n // Create dubbing job using direct HTTP request\n const formData = new FormData();\n formData.append('file', audioFile);\n formData.append('target_lang', toLanguageCode);\n // Note: source_lang is omitted to enable automatic language detection\n formData.append('num_speakers', numSpeakers.toString());\n formData.append('name', `Mux Asset ${assetId} - auto to ${toLanguageCode}`);\n \n const dubbingResponse = await fetch('https://api.elevenlabs.io/v1/dubbing', {\n method: 'POST',\n headers: {\n 'xi-api-key': elevenLabsKey!\n },\n body: formData\n });\n \n if (!dubbingResponse.ok) {\n throw new Error(`ElevenLabs API error: ${dubbingResponse.statusText}`);\n }\n \n const dubbingData = await dubbingResponse.json() as any;\n \n dubbingId = dubbingData.dubbing_id;\n console.log(`✅ Dubbing job created: ${dubbingId}`);\n console.log(`⏱️ Expected duration: ${dubbingData.expected_duration_sec}s`);\n \n } catch (error) {\n throw new Error(`Failed to create ElevenLabs dubbing job: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Poll for completion\n console.log('⏳ Waiting for dubbing to complete...');\n \n let dubbingStatus: string = 'dubbing';\n let pollAttempts = 0;\n const maxPollAttempts = 180; // 30 minutes at 10s intervals\n \n while (dubbingStatus === 'dubbing' && pollAttempts < maxPollAttempts) {\n await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds\n pollAttempts++;\n \n try {\n const statusResponse = await fetch(`https://api.elevenlabs.io/v1/dubbing/${dubbingId}`, {\n headers: {\n 'xi-api-key': elevenLabsKey!\n }\n });\n \n if (!statusResponse.ok) {\n throw new Error(`Status check failed: ${statusResponse.statusText}`);\n }\n \n const statusData = await statusResponse.json() as any;\n dubbingStatus = statusData.status;\n \n console.log(`📊 Status check ${pollAttempts}: ${dubbingStatus}`);\n \n if (dubbingStatus === 'failed') {\n throw new Error('ElevenLabs dubbing job failed');\n }\n \n } catch (error) {\n throw new Error(`Failed to check dubbing status: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n \n if (dubbingStatus !== 'dubbed') {\n throw new Error(`Dubbing job timed out or failed. Final status: ${dubbingStatus}`);\n }\n \n console.log('✅ Dubbing completed successfully!');\n\n // If uploadToMux is false, just return the dubbing info\n if (!uploadToMux) {\n return {\n assetId,\n targetLanguageCode: toLanguageCode,\n dubbingId\n };\n }\n\n // Download dubbed audio from ElevenLabs\n console.log('📥 Downloading dubbed audio from ElevenLabs...');\n \n let dubbedAudioBuffer: ArrayBuffer;\n \n try {\n // Get dubbed audio using fetch (since the SDK method might not be available)\n const audioUrl = `https://api.elevenlabs.io/v1/dubbing/${dubbingId}/audio/${toLanguageCode}`;\n const audioResponse = await fetch(audioUrl, {\n headers: {\n 'xi-api-key': elevenLabsKey!\n }\n });\n \n if (!audioResponse.ok) {\n throw new Error(`Failed to fetch dubbed audio: ${audioResponse.statusText}`);\n }\n \n dubbedAudioBuffer = await audioResponse.arrayBuffer();\n console.log(`✅ Downloaded dubbed audio (${dubbedAudioBuffer.byteLength} bytes)`);\n \n } catch (error) {\n throw new Error(`Failed to download dubbed audio: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Upload to S3-compatible storage\n console.log('📤 Uploading dubbed audio to S3-compatible storage...');\n \n const s3Client = new S3Client({\n region: s3Region,\n endpoint: s3Endpoint,\n credentials: {\n accessKeyId: s3AccessKeyId!,\n secretAccessKey: s3SecretAccessKey!\n },\n forcePathStyle: true\n });\n \n // Create unique key for the audio file\n const audioKey = `audio-translations/${assetId}/auto-to-${toLanguageCode}-${Date.now()}.m4a`;\n \n let presignedUrl: string;\n \n try {\n // Upload audio to S3\n const upload = new Upload({\n client: s3Client,\n params: {\n Bucket: s3Bucket!,\n Key: audioKey,\n Body: new Uint8Array(dubbedAudioBuffer),\n ContentType: 'audio/mp4'\n }\n });\n \n await upload.done();\n console.log(`✅ Audio uploaded successfully to: ${audioKey}`);\n \n // Generate presigned URL (valid for 1 hour)\n const getObjectCommand = new GetObjectCommand({\n Bucket: s3Bucket!,\n Key: audioKey\n });\n \n presignedUrl = await getSignedUrl(s3Client, getObjectCommand, { \n expiresIn: 3600 // 1 hour\n });\n \n console.log(`🔗 Generated presigned URL (expires in 1 hour)`);\n \n } catch (error) {\n throw new Error(`Failed to upload audio to S3: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Add translated audio track to Mux asset\n console.log('🎬 Adding translated audio track to Mux asset...');\n \n let uploadedTrackId: string | undefined;\n \n try {\n const languageName = new Intl.DisplayNames(['en'], { type: 'language' }).of(toLanguageCode) || toLanguageCode.toUpperCase();\n const trackName = `${languageName} (auto-dubbed)`;\n \n const trackResponse = await mux.video.assets.createTrack(assetId, {\n type: 'audio',\n language_code: toLanguageCode,\n name: trackName,\n url: presignedUrl\n });\n \n uploadedTrackId = trackResponse.id;\n console.log(`✅ Audio track added to Mux asset with ID: ${uploadedTrackId}`);\n console.log(`🎵 Track name: \"${trackName}\"`);\n \n } catch (error) {\n console.warn(`⚠️ Failed to add audio track to Mux asset: ${error instanceof Error ? error.message : 'Unknown error'}`);\n console.log('🔗 You can manually add the track using this presigned URL:');\n console.log(presignedUrl);\n }\n\n return {\n assetId,\n targetLanguageCode: toLanguageCode,\n dubbingId,\n uploadedTrackId,\n presignedUrl\n };\n}","import Mux from '@mux/mux-node';\nimport OpenAI from 'openai';\nimport Anthropic from '@anthropic-ai/sdk';\nimport { z } from 'zod';\nimport { zodTextFormat } from 'openai/helpers/zod';\nimport { MuxAIOptions } from './types';\n\nexport interface Chapter {\n /** Start time in seconds */\n startTime: number;\n /** Chapter title */\n title: string;\n}\n\nexport interface ChaptersResult {\n assetId: string;\n languageCode: string;\n chapters: Chapter[];\n}\n\nexport interface ChaptersOptions extends MuxAIOptions {\n provider?: 'openai' | 'anthropic';\n model?: string;\n}\n\nconst chaptersSchema = z.object({\n chapters: z.array(z.object({\n startTime: z.number(),\n title: z.string()\n }))\n});\n\nconst DEFAULT_SYSTEM_PROMPT = `Your role is to segment the following captions into chunked chapters, summarising each chapter with a title. \n\nAnalyze the transcript and create logical chapter breaks based on topic changes, major transitions, or distinct sections of content. Each chapter should represent a meaningful segment of the video.\n\nYou must respond with valid JSON in exactly this format:\n{\n \"chapters\": [\n {\"startTime\": 0, \"title\": \"Introduction\"},\n {\"startTime\": 45.5, \"title\": \"Main Topic Discussion\"},\n {\"startTime\": 120.0, \"title\": \"Conclusion\"}\n ]\n}\n\nImportant rules:\n- startTime must be in seconds (not HH:MM:SS format)\n- Always start with startTime: 0 for the first chapter\n- Create 3-8 chapters depending on content length and natural breaks\n- Chapter titles should be concise and descriptive\n- Do not include any text before or after the JSON\n- The JSON must be valid and parseable`;\n\nconst ANTHROPIC_JSON_PROMPT = `You must respond with valid JSON in exactly this format:\n{\n \"chapters\": [\n {\"startTime\": 0, \"title\": \"Chapter title here\"},\n {\"startTime\": 45.5, \"title\": \"Another chapter title\"}\n ]\n}\n\nDo not include any text before or after the JSON. The JSON must be valid and parseable.`;\n\n/**\n * Converts VTT timestamp (HH:MM:SS.mmm) to seconds\n */\nfunction vttTimestampToSeconds(timestamp: string): number {\n const parts = timestamp.split(':');\n if (parts.length !== 3) return 0;\n \n const hours = parseInt(parts[0], 10) || 0;\n const minutes = parseInt(parts[1], 10) || 0;\n const seconds = parseFloat(parts[2]) || 0;\n \n return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Extracts timestamps and text from VTT content for chapter generation\n */\nfunction extractTimestampsFromVTT(vttContent: string): string {\n if (!vttContent.trim()) {\n return '';\n }\n\n const lines = vttContent.split('\\n');\n const segments: Array<{time: number, text: string}> = [];\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n \n // Find timestamp lines (contain -->)\n if (line.includes('-->')) {\n const startTime = line.split(' --> ')[0].trim();\n const timeInSeconds = vttTimestampToSeconds(startTime);\n \n // Get the subtitle text (next non-empty line)\n let j = i + 1;\n while (j < lines.length && !lines[j].trim()) {\n j++;\n }\n \n if (j < lines.length) {\n const text = lines[j].trim().replace(/<[^>]*>/g, ''); // Remove formatting tags\n if (text) {\n segments.push({ time: timeInSeconds, text });\n }\n }\n }\n }\n \n // Create a readable transcript with timestamps for the AI\n return segments\n .map(segment => `[${Math.floor(segment.time)}s] ${segment.text}`)\n .join('\\n');\n}\n\nexport async function generateChapters(\n assetId: string,\n languageCode: string,\n options: ChaptersOptions = {}\n): Promise<ChaptersResult> {\n const {\n provider = 'openai',\n model,\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n anthropicApiKey,\n ...config\n } = options;\n\n // Set default models based on provider\n const defaultModel = provider === 'anthropic' ? 'claude-3-5-haiku-20241022' : 'gpt-4o-mini';\n const finalModel = model || defaultModel;\n\n // Validate required credentials\n const muxId = muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n const openaiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n if (provider === 'openai' && !openaiKey) {\n throw new Error('OpenAI API key is required for OpenAI provider. Provide openaiApiKey in options or set OPENAI_API_KEY environment variable.');\n }\n\n if (provider === 'anthropic' && !anthropicKey) {\n throw new Error('Anthropic API key is required for Anthropic provider. Provide anthropicApiKey in options or set ANTHROPIC_API_KEY environment variable.');\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n let openaiClient: OpenAI | undefined;\n let anthropicClient: Anthropic | undefined;\n\n if (provider === 'openai') {\n openaiClient = new OpenAI({\n apiKey: openaiKey!,\n });\n } else if (provider === 'anthropic') {\n anthropicClient = new Anthropic({\n apiKey: anthropicKey!,\n });\n }\n\n // Fetch asset data from Mux\n let assetData;\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n assetData = asset;\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Get playback ID\n const playbackId = assetData.playback_ids?.[0]?.id;\n if (!playbackId) {\n throw new Error('No playback ID found for this asset');\n }\n\n // Find caption track in the specified language\n if (!assetData.tracks) {\n throw new Error('No tracks found for this asset');\n }\n\n const captionTrack = assetData.tracks.find((track) => \n track.type === 'text' && \n track.status === 'ready' &&\n track.text_type === 'subtitles' &&\n track.language_code === languageCode\n );\n\n if (!captionTrack) {\n throw new Error(`No caption track found for language '${languageCode}'. Available languages: ${assetData.tracks.filter(t => t.type === 'text').map(t => t.language_code).join(', ')}`);\n }\n\n // Fetch the VTT content\n const transcriptUrl = `https://stream.mux.com/${playbackId}/text/${captionTrack.id}.vtt`;\n \n let vttContent: string;\n try {\n const transcriptResponse = await fetch(transcriptUrl);\n if (!transcriptResponse.ok) {\n throw new Error(`Failed to fetch VTT: ${transcriptResponse.statusText}`);\n }\n vttContent = await transcriptResponse.text();\n } catch (error) {\n throw new Error(`Failed to fetch caption track: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n // Extract timestamped transcript for AI processing\n const timestampedTranscript = extractTimestampsFromVTT(vttContent);\n \n if (!timestampedTranscript) {\n throw new Error('No usable content found in caption track');\n }\n\n // Generate chapters using AI\n let chaptersData: { chapters: Chapter[] } | null = null;\n\n if (provider === 'openai') {\n try {\n const response = await openaiClient!.responses.parse({\n model: finalModel,\n input: [\n {\n role: \"system\",\n content: DEFAULT_SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: [\n {\n type: \"input_text\",\n text: timestampedTranscript,\n },\n ],\n },\n ],\n text: {\n format: zodTextFormat(chaptersSchema, \"chapters\"),\n },\n });\n\n chaptersData = response.output_parsed;\n } catch (error) {\n throw new Error(`Failed to generate chapters with OpenAI: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else if (provider === 'anthropic') {\n const anthropicPrompt = `${DEFAULT_SYSTEM_PROMPT}\n\n${ANTHROPIC_JSON_PROMPT}\n\nTranscript:\n${timestampedTranscript}`;\n\n try {\n const response = await anthropicClient!.messages.create({\n model: finalModel,\n max_tokens: 2000,\n messages: [\n {\n role: \"user\",\n content: anthropicPrompt,\n },\n ],\n });\n\n const content = response.content[0];\n if (content.type === 'text') {\n const jsonText = content.text.trim();\n try {\n chaptersData = JSON.parse(jsonText);\n } catch (parseError) {\n throw new Error(`Failed to parse JSON response from Anthropic: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`);\n }\n } else {\n throw new Error('Unexpected response type from Anthropic');\n }\n } catch (error) {\n throw new Error(`Failed to generate chapters with Anthropic: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n throw new Error(`Unsupported provider: ${provider}`);\n }\n\n if (!chaptersData || !chaptersData.chapters) {\n throw new Error('No chapters generated from AI response');\n }\n\n // Validate and sort chapters\n const validChapters = chaptersData.chapters\n .filter(chapter => typeof chapter.startTime === 'number' && typeof chapter.title === 'string')\n .sort((a, b) => a.startTime - b.startTime);\n\n if (validChapters.length === 0) {\n throw new Error('No valid chapters found in AI response');\n }\n\n // Ensure first chapter starts at 0\n if (validChapters[0].startTime !== 0) {\n validChapters[0].startTime = 0;\n }\n\n return {\n assetId,\n languageCode,\n chapters: validChapters,\n };\n}","import Mux from '@mux/mux-node';\nimport OpenAI from 'openai';\nimport Anthropic from '@anthropic-ai/sdk';\nimport { ImageDownloadOptions, downloadImageAsBase64, uploadImageToAnthropicFiles } from './image-download';\n\nexport interface StoryboardProcessorOptions {\n muxTokenId?: string;\n muxTokenSecret?: string;\n openaiApiKey?: string;\n anthropicApiKey?: string;\n imageSubmissionMode?: 'url' | 'base64';\n imageDownloadOptions?: ImageDownloadOptions;\n}\n\nexport interface AssetInfo {\n playbackId: string;\n duration?: number;\n}\n\n/**\n * Retrieves asset information from Mux including playback ID and duration\n */\nexport async function getAssetInfo(assetId: string, options: StoryboardProcessorOptions): Promise<AssetInfo> {\n const muxId = options.muxTokenId || process.env.MUX_TOKEN_ID;\n const muxSecret = options.muxTokenSecret || process.env.MUX_TOKEN_SECRET;\n\n if (!muxId || !muxSecret) {\n throw new Error('Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.');\n }\n\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n try {\n const asset = await mux.video.assets.retrieve(assetId);\n \n const playbackId = asset.playback_ids?.[0]?.id;\n if (!playbackId) {\n throw new Error('No playback ID found for this asset');\n }\n\n return {\n playbackId,\n duration: asset.duration || undefined\n };\n } catch (error) {\n throw new Error(`Failed to fetch asset from Mux: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n}\n\n/**\n * Processes a storyboard image with OpenAI\n */\nexport async function processStoryboardWithOpenAI<T>(\n imageUrl: string,\n prompt: string,\n systemPrompt: string,\n options: {\n apiKey: string;\n model: string;\n responseParser: (response: any) => T;\n imageSubmissionMode?: 'url' | 'base64';\n imageDownloadOptions?: ImageDownloadOptions;\n maxRetries?: number;\n }\n): Promise<T> {\n const { apiKey, model, responseParser, imageSubmissionMode = 'url', imageDownloadOptions, maxRetries = 3 } = options;\n \n const openaiClient = new OpenAI({ apiKey });\n let retryAttempt = 0;\n\n if (imageSubmissionMode === 'base64') {\n try {\n const downloadResult = await downloadImageAsBase64(imageUrl, imageDownloadOptions);\n \n const response = await openaiClient.chat.completions.create({\n model,\n messages: [\n {\n role: \"system\",\n content: systemPrompt,\n },\n {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: prompt,\n },\n {\n type: \"image_url\",\n image_url: {\n url: downloadResult.base64Data,\n detail: \"high\",\n },\n },\n ],\n },\n ],\n });\n\n return responseParser(response);\n \n } catch (error: unknown) {\n throw new Error(`Failed to process storyboard with OpenAI in base64 mode: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n // URL-based submission with retry logic\n while (retryAttempt <= maxRetries) {\n try {\n const response = await openaiClient.chat.completions.create({\n model,\n messages: [\n {\n role: \"system\",\n content: systemPrompt,\n },\n {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: prompt,\n },\n {\n type: \"image_url\",\n image_url: {\n url: imageUrl,\n detail: \"high\",\n },\n },\n ],\n },\n ],\n });\n\n return responseParser(response);\n \n } catch (error: unknown) {\n const isTimeoutError = error instanceof Error && error.message && error.message.includes('Timeout while downloading');\n \n if (isTimeoutError && retryAttempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, 5000));\n retryAttempt++;\n continue;\n }\n \n throw new Error(`Failed to process storyboard with OpenAI: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n }\n\n throw new Error('All retry attempts failed');\n}\n\n/**\n * Processes a storyboard image with Anthropic\n */\nexport async function processStoryboardWithAnthropic<T>(\n imageUrl: string,\n prompt: string,\n options: {\n apiKey: string;\n model: string;\n responseParser: (response: any) => T;\n imageSubmissionMode?: 'url' | 'base64';\n imageDownloadOptions?: ImageDownloadOptions;\n maxRetries?: number;\n }\n): Promise<T> {\n const { apiKey, model, responseParser, imageSubmissionMode = 'url', imageDownloadOptions, maxRetries = 3 } = options;\n \n const anthropicClient = new Anthropic({ apiKey });\n let retryAttempt = 0;\n\n if (imageSubmissionMode === 'base64') {\n try {\n // Upload to Files API instead of using base64 inline (no 5MB limit)\n const fileUploadResult = await uploadImageToAnthropicFiles(imageUrl, apiKey, imageDownloadOptions);\n \n const response = await anthropicClient.messages.create({\n model,\n max_tokens: 1000,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"file\",\n file_id: fileUploadResult.fileId,\n } as any, // Type assertion for Files API support\n },\n {\n type: \"text\",\n text: prompt,\n },\n ],\n },\n ],\n }, {\n headers: {\n 'anthropic-beta': 'files-api-2025-04-14'\n }\n });\n\n return responseParser(response);\n \n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`Failed to process storyboard with Anthropic Files API: ${errorMessage}`);\n }\n } else {\n // URL-based submission with retry logic\n while (retryAttempt <= maxRetries) {\n try {\n const response = await anthropicClient.messages.create({\n model,\n max_tokens: 1000,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"url\",\n url: imageUrl,\n } as any, // Type assertion to work around SDK type definitions\n },\n {\n type: \"text\",\n text: prompt,\n },\n ],\n },\n ],\n });\n\n return responseParser(response);\n \n } catch (error: unknown) {\n if (retryAttempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, 5000));\n retryAttempt++;\n continue;\n }\n \n throw new Error(`Failed to process storyboard with Anthropic: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n }\n\n throw new Error('All retry attempts failed');\n}","import { z } from 'zod';\nimport { zodTextFormat } from 'openai/helpers/zod';\nimport { MuxAIOptions } from './types';\nimport { ImageDownloadOptions } from './utils/image-download';\nimport { \n getAssetInfo, \n processStoryboardWithOpenAI, \n processStoryboardWithAnthropic,\n StoryboardProcessorOptions \n} from './utils/storyboard-processor';\n\nexport interface BurnedInCaptionsResult {\n assetId: string;\n hasBurnedInCaptions: boolean;\n confidence: number;\n detectedLanguage: string | null;\n storyboardUrl?: string;\n}\n\nexport interface BurnedInCaptionsOptions extends MuxAIOptions {\n provider?: 'openai' | 'anthropic';\n model?: string;\n /** Method for submitting storyboard to AI providers (default: 'url') */\n imageSubmissionMode?: 'url' | 'base64';\n /** Options for image download when using base64 submission mode */\n imageDownloadOptions?: ImageDownloadOptions;\n}\n\nconst burnedInCaptionsSchema = z.object({\n hasBurnedInCaptions: z.boolean(),\n confidence: z.number().min(0).max(1),\n detectedLanguage: z.string().nullable()\n});\n\nconst DEFAULT_SYSTEM_PROMPT = `You are an expert at analyzing video frames to detect burned-in captions (also called open captions or hardcoded subtitles). These are text overlays that are permanently embedded in the video image, common on TikTok, Instagram Reels, and other social media platforms.\n\nCRITICAL: Burned-in captions must appear consistently across MOST frames in the storyboard. Text appearing in only 1-2 frames at the end is typically marketing copy, taglines, or end-cards - NOT burned-in captions.\n\nAnalyze the provided video storyboard by:\n1. COUNT how many frames contain text overlays vs. how many don't\n2. Check if text appears in consistent positions across multiple frames\n3. Verify text changes content between frames (indicating dialogue/narration)\n4. Ensure text has caption-style formatting (contrasting colors, readable fonts)\n\nONLY classify as burned-in captions if:\n- Text appears in multiple frames (not just 1-2 end frames)\n- Text positioning is consistent across those frames\n- Content suggests dialogue, narration, or subtitles (not marketing)\n- Formatting looks like captions (not graphics/logos)\n\nDO NOT classify as burned-in captions:\n- Marketing taglines appearing only in final 1-2 frames\n- Single words or phrases that don't change between frames\n- Graphics, logos, watermarks, or UI elements\n- Text that's part of the original scene content\n- End-cards with calls-to-action or brand messaging\n\nIf you detect burned-in captions, try to identify the language of the text.`;\n\nconst ANTHROPIC_SYSTEM_PROMPT = `You are an expert at analyzing video frames to detect burned-in captions (also called open captions or hardcoded subtitles). These are text overlays permanently embedded in video images, common on social media platforms.\n\nKey principles:\n1. Burned-in captions appear across multiple frames throughout the video timeline\n2. End-cards and marketing text appear only in final frames\n3. Captions have consistent positioning and caption-style formatting\n4. Caption text typically changes between frames (dialogue/narration)\n\nAnalysis approach:\n- Look for text overlays distributed across different parts of the timeline\n- Distinguish between dialogue captions vs. marketing end-cards\n- Consider text positioning, formatting, and content patterns`;\n\nconst DEFAULT_USER_PROMPT = `Analyze this video storyboard for burned-in captions. Follow this systematic approach:\n\nSTEP 1: Count the frames\n- How many total frames are shown in this storyboard?\n- How many frames contain any text overlays?\n- What percentage of frames contain text?\n\nSTEP 2: Analyze text consistency\n- If text is present, does it appear in the same position across multiple frames?\n- Does the text content change between frames (suggesting dialogue)?\n- Or is it the same text in just 1-2 frames (suggesting marketing/end-card)?\n\nSTEP 3: Classification\n- Are there burned-in captions (text overlaid that appears to be subtitles/captions)?\n- How confident are you (0.0 to 1.0)? Be decisive and accurate:\n * If clear dialogue/caption text across multiple frames → 0.8+ confidence, TRUE\n * If ONLY marketing text in final frames → 0.0 confidence, FALSE\n * If truly uncertain → 0.3-0.5 confidence\n- If captions are present, what language?\n\nREMEMBER: Marketing taglines in final frames = NOT captions (0.0 confidence, FALSE). Dialogue text across timeline = captions (0.8+ confidence, TRUE).\n\nRespond with your analysis.`;\n\nconst ANTHROPIC_USER_PROMPT = `Analyze this storyboard for burned-in captions:\n\n1. Examine each frame from left to right (timeline order)\n2. Note which frames have text overlays and their positions\n3. Determine the pattern:\n - Text scattered across timeline = likely captions\n - Text only in final 1-2 frames = likely end-card/marketing\n\nClassification rules:\n- If text appears in 3+ frames distributed throughout timeline → burned-in captions\n- If text appears only in final frames → NOT burned-in captions\n- Look for dialogue-style content vs. marketing taglines\n\nAnalyze and classify with confidence level.`;\n\nconst ANTHROPIC_JSON_PROMPT = `Apply the frame analysis above.\n\nKey rule: Text appearing only in final 2-3 frames = NOT captions. Text distributed throughout timeline = captions.\n\nRespond ONLY with valid JSON:\n{\n \"hasBurnedInCaptions\": true/false,\n \"confidence\": 0.85,\n \"detectedLanguage\": \"English\" (or null if no captions or language unclear)\n}\n\nDo not include any text before or after the JSON. The JSON must be valid and parseable.`;\n\nexport async function hasBurnedInCaptions(\n assetId: string,\n options: BurnedInCaptionsOptions = {}\n): Promise<BurnedInCaptionsResult> {\n const {\n provider = 'openai',\n model,\n imageSubmissionMode = 'url',\n imageDownloadOptions,\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n anthropicApiKey,\n ...config\n } = options;\n\n // Set default models based on provider\n const defaultModel = provider === 'anthropic' ? 'claude-3-5-haiku-20241022' : 'gpt-4o-mini';\n const finalModel = model || defaultModel;\n\n // Validate required credentials\n const openaiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n\n if (provider === 'openai' && !openaiKey) {\n throw new Error('OpenAI API key is required for OpenAI provider. Provide openaiApiKey in options or set OPENAI_API_KEY environment variable.');\n }\n\n if (provider === 'anthropic' && !anthropicKey) {\n throw new Error('Anthropic API key is required for Anthropic provider. Provide anthropicApiKey in options or set ANTHROPIC_API_KEY environment variable.');\n }\n\n // Get asset information\n const storyboardOptions: StoryboardProcessorOptions = {\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n anthropicApiKey,\n imageSubmissionMode,\n imageDownloadOptions\n };\n\n const assetInfo = await getAssetInfo(assetId, storyboardOptions);\n const imageUrl = `https://image.mux.com/${assetInfo.playbackId}/storyboard.png?width=640`;\n\n let analysisResult: { hasBurnedInCaptions?: boolean; confidence?: number; detectedLanguage?: string | null } | null = null;\n\n if (provider === 'openai') {\n // Handle OpenAI with structured outputs directly\n const OpenAI = require('openai').default;\n const openaiClient = new OpenAI({ apiKey: openaiKey });\n\n if (imageSubmissionMode === 'base64') {\n const { downloadImageAsBase64 } = require('./utils/image-download');\n const downloadResult = await downloadImageAsBase64(imageUrl, imageDownloadOptions);\n \n const response = await openaiClient.responses.parse({\n model: finalModel,\n input: [\n {\n role: \"system\",\n content: ANTHROPIC_SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: [\n {\n type: \"input_text\",\n text: ANTHROPIC_USER_PROMPT,\n },\n {\n type: \"input_image\",\n image_url: downloadResult.base64Data,\n detail: \"high\",\n },\n ],\n },\n ],\n text: {\n format: zodTextFormat(burnedInCaptionsSchema, \"analysis\"),\n },\n });\n\n analysisResult = response.output_parsed;\n } else {\n // URL-based submission with retry logic for structured outputs\n let retryAttempt = 0;\n const maxRetries = 3;\n\n while (retryAttempt <= maxRetries) {\n try {\n const response = await openaiClient.responses.parse({\n model: finalModel,\n input: [\n {\n role: \"system\",\n content: ANTHROPIC_SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: [\n {\n type: \"input_text\",\n text: ANTHROPIC_USER_PROMPT,\n },\n {\n type: \"input_image\",\n image_url: imageUrl,\n detail: \"high\",\n },\n ],\n },\n ],\n text: {\n format: zodTextFormat(burnedInCaptionsSchema, \"analysis\"),\n },\n });\n\n analysisResult = response.output_parsed;\n break;\n \n } catch (error: unknown) {\n const isTimeoutError = error instanceof Error && error.message && error.message.includes('Timeout while downloading');\n \n if (isTimeoutError && retryAttempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, 5000));\n retryAttempt++;\n continue;\n }\n \n throw new Error(`Failed to analyze storyboard with OpenAI: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n }\n } else if (provider === 'anthropic') {\n const anthropicPrompt = `${ANTHROPIC_USER_PROMPT}\n\n${ANTHROPIC_JSON_PROMPT}`;\n\n const responseParser = (response: any) => {\n const content = response.content[0];\n if (content.type === 'text') {\n const jsonText = content.text.trim();\n try {\n return JSON.parse(jsonText);\n } catch (parseError) {\n throw new Error(`Failed to parse JSON response from Anthropic: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`);\n }\n } else {\n throw new Error('Unexpected response type from Anthropic');\n }\n };\n\n analysisResult = await processStoryboardWithAnthropic(\n imageUrl,\n anthropicPrompt,\n {\n apiKey: anthropicKey!,\n model: finalModel,\n responseParser,\n imageSubmissionMode,\n imageDownloadOptions\n }\n );\n } else {\n throw new Error(`Unsupported provider: ${provider}`);\n }\n\n if (!analysisResult) {\n throw new Error('No analysis result received from AI provider');\n }\n\n return {\n assetId,\n hasBurnedInCaptions: analysisResult.hasBurnedInCaptions ?? false,\n confidence: analysisResult.confidence ?? 0,\n detectedLanguage: analysisResult.detectedLanguage ?? null,\n storyboardUrl: imageUrl,\n };\n}","export * from './types';\nexport * from './moderation';\nexport * from './summarization';\nexport * from './translation';\nexport * from './audio-translation';\nexport * from './chapters';\nexport * from './burned-in-captions';\n\nexport const version = '0.1.0';"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/primitives/index.ts","../src/lib/url-signing.ts","../src/env.ts","../src/primitives/storyboards.ts","../src/primitives/text-chunking.ts","../src/primitives/thumbnails.ts","../src/primitives/transcripts.ts","../src/workflows/index.ts","../src/workflows/burned-in-captions.ts","../node_modules/dedent/dist/dedent.mjs","../src/lib/client-factory.ts","../src/lib/providers.ts","../src/lib/image-download.ts","../src/lib/mux-assets.ts","../src/lib/prompt-builder.ts","../src/workflows/chapters.ts","../src/lib/retry.ts","../src/workflows/embeddings.ts","../src/workflows/moderation.ts","../src/workflows/summarization.ts","../src/workflows/translate-audio.ts","../src/workflows/translate-captions.ts"],"sourcesContent":["// Entry points are intentionally shallow; import explicitly from primitives or workflows\nexport * as primitives from \"./primitives\";\nexport * from \"./types\";\nexport * as workflows from \"./workflows\";\n\nexport const version = \"0.1.0\";\n","// primitives public surface intentionally minimal; provider plumbing lives in lib/providers\nexport * from \"./storyboards\";\nexport * from \"./text-chunking\";\nexport * from \"./thumbnails\";\nexport * from \"./transcripts\";\n","import Mux from \"@mux/mux-node\";\n\nimport env from \"../env\";\nimport type { MuxAIConfig } from \"../types\";\n\n/**\n * Context required to sign URLs for signed playback IDs.\n */\nexport interface SigningContext {\n /** The signing key ID from Mux dashboard. */\n keyId: string;\n /** The base64-encoded private key from Mux dashboard. */\n keySecret: string;\n /** Token expiration time (e.g. '1h', '1d'). Defaults to '1h'. */\n expiration?: string;\n}\n\n/**\n * Token type determines which Mux service the token is valid for.\n */\nexport type TokenType = \"video\" | \"thumbnail\" | \"storyboard\" | \"gif\";\n\n/**\n * Resolves signing context from config or environment variables.\n * Returns undefined if signing keys are not configured.\n */\nexport function resolveSigningContext(config: MuxAIConfig): SigningContext | undefined {\n const keyId = config.muxSigningKey ?? env.MUX_SIGNING_KEY;\n const keySecret = config.muxPrivateKey ?? env.MUX_PRIVATE_KEY;\n\n if (!keyId || !keySecret) {\n return undefined;\n }\n\n return { keyId, keySecret };\n}\n\n/**\n * Creates a Mux client configured for JWT signing.\n * This client is used internally for signing operations.\n */\nfunction createSigningClient(context: SigningContext): Mux {\n return new Mux({\n // These are not needed for signing, but the SDK requires them\n // Using empty strings as we only need the jwt functionality\n tokenId: env.MUX_TOKEN_ID || \"\",\n tokenSecret: env.MUX_TOKEN_SECRET || \"\",\n jwtSigningKey: context.keyId,\n jwtPrivateKey: context.keySecret,\n });\n}\n\n/**\n * Generates a signed token for a playback ID using the Mux SDK.\n *\n * @param playbackId - The Mux playback ID to sign\n * @param context - Signing context with key credentials\n * @param type - Token type (video, thumbnail, storyboard, gif)\n * @param params - Additional parameters for thumbnail/storyboard tokens (values will be stringified)\n * @returns Signed JWT token\n */\nexport async function signPlaybackId(\n playbackId: string,\n context: SigningContext,\n type: TokenType = \"video\",\n params?: Record<string, string | number>,\n): Promise<string> {\n const client = createSigningClient(context);\n\n // Convert params to Record<string, string> as required by the SDK\n const stringParams = params ?\n Object.fromEntries(\n Object.entries(params).map(([key, value]) => [key, String(value)]),\n ) :\n undefined;\n\n return client.jwt.signPlaybackId(playbackId, {\n type,\n expiration: context.expiration || \"1h\",\n params: stringParams,\n });\n}\n\n/**\n * Appends a signed token to a Mux URL.\n *\n * @param url - The base Mux URL (e.g. https://image.mux.com/{playbackId}/thumbnail.png)\n * @param playbackId - The Mux playback ID\n * @param context - Signing context with key credentials\n * @param type - Token type for the URL\n * @param params - Additional parameters for the token\n * @returns URL with token query parameter appended\n */\nexport async function signUrl(\n url: string,\n playbackId: string,\n context: SigningContext,\n type: TokenType = \"video\",\n params?: Record<string, string | number>,\n): Promise<string> {\n const token = await signPlaybackId(playbackId, context, type, params);\n const separator = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${separator}token=${token}`;\n}\n","/* eslint-disable node/no-process-env */\nimport path from \"node:path\";\n\nimport { config } from \"dotenv\";\nimport { expand } from \"dotenv-expand\";\nimport { z } from \"zod\";\n\nexpand(config({\n path: path.resolve(\n process.cwd(),\n process.env.NODE_ENV === \"test\" ? \".env.test\" : \".env\",\n ),\n}));\n\nfunction optionalString(description: string, message?: string) {\n return z.preprocess(\n value => typeof value === \"string\" && value.trim().length === 0 ? undefined : value,\n z.string().trim().min(1, message).optional(),\n ).describe(description);\n}\n\nfunction requiredString(description: string, message?: string) {\n return z.preprocess(\n value => typeof value === \"string\" ? value.trim().length > 0 ? value.trim() : undefined : value,\n z.string().trim().min(1, message),\n ).describe(description);\n}\n\nconst EnvSchema = z.object({\n NODE_ENV: z.string().default(\"development\").describe(\"Runtime environment.\"),\n\n MUX_TOKEN_ID: requiredString(\"Mux access token ID.\", \"Required to access Mux APIs\"),\n MUX_TOKEN_SECRET: requiredString(\"Mux access token secret.\", \"Required to access Mux APIs\"),\n\n MUX_SIGNING_KEY: optionalString(\"Mux signing key ID for signed playback URLs.\", \"Used to sign playback URLs\"),\n MUX_PRIVATE_KEY: optionalString(\"Mux signing private key for signed playback URLs.\", \"Used to sign playback URLs\"),\n\n OPENAI_API_KEY: optionalString(\"OpenAI API key for OpenAI-backed workflows.\", \"OpenAI API key\"),\n ANTHROPIC_API_KEY: optionalString(\"Anthropic API key for Claude-backed workflows.\", \"Anthropic API key\"),\n GOOGLE_GENERATIVE_AI_API_KEY: optionalString(\"Google Generative AI API key for Gemini-backed workflows.\", \"Google Generative AI API key\"),\n\n ELEVENLABS_API_KEY: optionalString(\"ElevenLabs API key for audio translation.\", \"ElevenLabs API key\"),\n HIVE_API_KEY: optionalString(\"Hive Visual Moderation API key.\", \"Hive API key\"),\n\n S3_ENDPOINT: optionalString(\"S3-compatible endpoint for uploads.\", \"S3 endpoint\"),\n S3_REGION: optionalString(\"S3 region (defaults to 'auto' when omitted).\"),\n S3_BUCKET: optionalString(\"Bucket used for caption and audio uploads.\", \"S3 bucket\"),\n S3_ACCESS_KEY_ID: optionalString(\"Access key ID for S3-compatible uploads.\", \"S3 access key id\"),\n S3_SECRET_ACCESS_KEY: optionalString(\"Secret access key for S3-compatible uploads.\", \"S3 secret access key\"),\n});\n\nexport type Env = z.infer<typeof EnvSchema>;\n\nfunction parseEnv(): Env {\n const parsedEnv = EnvSchema.safeParse(process.env);\n\n if (!parsedEnv.success) {\n console.error(\"❌ Invalid env:\");\n console.error(JSON.stringify(parsedEnv.error.flatten().fieldErrors, null, 2));\n process.exit(1);\n }\n\n return parsedEnv.data;\n}\n\nconst env: Env = parseEnv();\n\nexport function reloadEnv(): Env {\n const parsed = parseEnv();\n Object.assign(env, parsed);\n return env;\n}\n\nexport { env };\nexport default env;\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\n\nexport const DEFAULT_STORYBOARD_WIDTH = 640;\n\n/**\n * Generates a storyboard URL for the given playback ID.\n * If a signing context is provided, the URL will be signed with a token.\n *\n * @param playbackId - The Mux playback ID\n * @param width - Width of the storyboard in pixels (default: 640)\n * @param signingContext - Optional signing context for signed playback IDs\n * @returns Storyboard URL (signed if context provided)\n */\nexport async function getStoryboardUrl(\n playbackId: string,\n width: number = DEFAULT_STORYBOARD_WIDTH,\n signingContext?: SigningContext,\n): Promise<string> {\n const baseUrl = `https://image.mux.com/${playbackId}/storyboard.png`;\n\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"storyboard\", { width });\n }\n\n return `${baseUrl}?width=${width}`;\n}\n","import type { ChunkingStrategy, TextChunk } from \"../types\";\n\nimport type { VTTCue } from \"./transcripts\";\n\n/**\n * Simple token counter that approximates tokens by word count.\n * For production use with OpenAI, consider using a proper tokenizer like tiktoken.\n * This approximation is generally close enough for chunking purposes (1 token ≈ 0.75 words).\n */\nexport function estimateTokenCount(text: string): number {\n const words = text.trim().split(/\\s+/).length;\n return Math.ceil(words / 0.75);\n}\n\n/**\n * Chunks text into overlapping segments based on token count.\n *\n * @param text - The text to chunk\n * @param maxTokens - Maximum tokens per chunk\n * @param overlapTokens - Number of tokens to overlap between chunks\n * @returns Array of text chunks with metadata\n */\nexport function chunkByTokens(\n text: string,\n maxTokens: number,\n overlapTokens: number = 0,\n): TextChunk[] {\n if (!text.trim()) {\n return [];\n }\n\n const chunks: TextChunk[] = [];\n const words = text.trim().split(/\\s+/);\n\n // Convert tokens to approximate word count\n const wordsPerChunk = Math.floor(maxTokens * 0.75);\n const overlapWords = Math.floor(overlapTokens * 0.75);\n\n let chunkIndex = 0;\n let currentPosition = 0;\n\n while (currentPosition < words.length) {\n const chunkWords = words.slice(\n currentPosition,\n currentPosition + wordsPerChunk,\n );\n const chunkText = chunkWords.join(\" \");\n const tokenCount = estimateTokenCount(chunkText);\n\n chunks.push({\n id: `chunk-${chunkIndex}`,\n text: chunkText,\n tokenCount,\n });\n\n // Move forward by chunk size minus overlap\n currentPosition += wordsPerChunk - overlapWords;\n chunkIndex++;\n\n // Prevent infinite loop if overlap is too large\n if (currentPosition <= (chunkIndex - 1) * (wordsPerChunk - overlapWords)) {\n break;\n }\n }\n\n return chunks;\n}\n\n/**\n * Creates a TextChunk from a group of VTT cues.\n */\nfunction createChunkFromCues(cues: VTTCue[], index: number): TextChunk {\n const text = cues.map(c => c.text).join(\" \");\n return {\n id: `chunk-${index}`,\n text,\n tokenCount: estimateTokenCount(text),\n startTime: cues[0].startTime,\n endTime: cues[cues.length - 1].endTime,\n };\n}\n\n/**\n * Chunks VTT cues into groups that respect natural cue boundaries.\n * Splits at cue boundaries rather than mid-sentence, preserving accurate timestamps.\n *\n * @param cues - Array of VTT cues to chunk\n * @param maxTokens - Maximum tokens per chunk\n * @param overlapCues - Number of cues to overlap between chunks (default: 2)\n * @returns Array of text chunks with accurate start/end times\n */\nexport function chunkVTTCues(\n cues: VTTCue[],\n maxTokens: number,\n overlapCues: number = 2,\n): TextChunk[] {\n if (cues.length === 0)\n return [];\n\n const chunks: TextChunk[] = [];\n let currentCues: VTTCue[] = [];\n let currentTokens = 0;\n let chunkIndex = 0;\n\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const cueTokens = estimateTokenCount(cue.text);\n\n // If adding this cue would exceed limit, finalize current chunk\n if (currentTokens + cueTokens > maxTokens && currentCues.length > 0) {\n chunks.push(createChunkFromCues(currentCues, chunkIndex));\n chunkIndex++;\n\n // Start new chunk with overlap from end of previous\n const overlapStart = Math.max(0, currentCues.length - overlapCues);\n currentCues = currentCues.slice(overlapStart);\n currentTokens = currentCues.reduce(\n (sum, c) => sum + estimateTokenCount(c.text),\n 0,\n );\n }\n\n currentCues.push(cue);\n currentTokens += cueTokens;\n }\n\n // Don't forget the last chunk\n if (currentCues.length > 0) {\n chunks.push(createChunkFromCues(currentCues, chunkIndex));\n }\n\n return chunks;\n}\n\n/**\n * Chunks text according to the specified strategy.\n *\n * @param text - The text to chunk\n * @param strategy - The chunking strategy to use\n * @returns Array of text chunks\n */\nexport function chunkText(text: string, strategy: ChunkingStrategy): TextChunk[] {\n switch (strategy.type) {\n case \"token\": {\n return chunkByTokens(text, strategy.maxTokens, strategy.overlap ?? 0);\n }\n default: {\n const exhaustiveCheck: never = strategy as never;\n throw new Error(`Unsupported chunking strategy: ${exhaustiveCheck}`);\n }\n }\n}\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\n\nexport interface ThumbnailOptions {\n /** Interval between thumbnails in seconds (default: 10) */\n interval?: number;\n /** Width of the thumbnail in pixels (default: 640) */\n width?: number;\n /** Optional signing context for signed playback IDs */\n signingContext?: SigningContext;\n}\n\n/**\n * Generates thumbnail URLs at regular intervals based on video duration.\n * If a signing context is provided, the URLs will be signed with tokens.\n *\n * @param playbackId - The Mux playback ID\n * @param duration - Video duration in seconds\n * @param options - Thumbnail generation options\n * @returns Array of thumbnail URLs (signed if context provided)\n */\nexport async function getThumbnailUrls(\n playbackId: string,\n duration: number,\n options: ThumbnailOptions = {},\n): Promise<string[]> {\n const { interval = 10, width = 640, signingContext } = options;\n const timestamps: number[] = [];\n\n if (duration <= 50) {\n const spacing = duration / 6;\n for (let i = 1; i <= 5; i++) {\n timestamps.push(Math.round(i * spacing));\n }\n } else {\n for (let time = 0; time < duration; time += interval) {\n timestamps.push(time);\n }\n }\n\n const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;\n\n const urlPromises = timestamps.map(async (time) => {\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"thumbnail\", { time, width });\n }\n\n return `${baseUrl}?time=${time}&width=${width}`;\n });\n\n return Promise.all(urlPromises);\n}\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\nimport type { AssetTextTrack, MuxAsset } from \"../types\";\n\n/** A single cue from a VTT file with timing info. */\nexport interface VTTCue {\n startTime: number;\n endTime: number;\n text: string;\n}\n\nexport interface TranscriptFetchOptions {\n languageCode?: string;\n cleanTranscript?: boolean;\n /** Optional signing context for signed playback IDs */\n signingContext?: SigningContext;\n}\n\nexport interface TranscriptResult {\n transcriptText: string;\n transcriptUrl?: string;\n track?: AssetTextTrack;\n}\n\nexport function getReadyTextTracks(asset: MuxAsset): AssetTextTrack[] {\n return (asset.tracks || []).filter(\n track => track.type === \"text\" && track.status === \"ready\",\n );\n}\n\nexport function findCaptionTrack(asset: MuxAsset, languageCode?: string): AssetTextTrack | undefined {\n const tracks = getReadyTextTracks(asset);\n if (!tracks.length)\n return undefined;\n\n if (!languageCode) {\n return tracks[0];\n }\n\n return tracks.find(\n track =>\n track.text_type === \"subtitles\" &&\n track.language_code === languageCode,\n );\n}\n\nexport function extractTextFromVTT(vttContent: string): string {\n if (!vttContent.trim()) {\n return \"\";\n }\n\n const lines = vttContent.split(\"\\n\");\n const textLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (!line)\n continue;\n if (line === \"WEBVTT\")\n continue;\n if (line.startsWith(\"NOTE \"))\n continue;\n if (line.includes(\"-->\"))\n continue;\n if (/^[\\w-]+$/.test(line) && !line.includes(\" \"))\n continue;\n if (line.startsWith(\"STYLE\") || line.startsWith(\"REGION\"))\n continue;\n\n const cleanLine = line.replace(/<[^>]*>/g, \"\").trim();\n\n if (cleanLine) {\n textLines.push(cleanLine);\n }\n }\n\n return textLines.join(\" \").replace(/\\s+/g, \" \").trim();\n}\n\nexport function vttTimestampToSeconds(timestamp: string): number {\n const parts = timestamp.split(\":\");\n if (parts.length !== 3)\n return 0;\n\n const hours = Number.parseInt(parts[0], 10) || 0;\n const minutes = Number.parseInt(parts[1], 10) || 0;\n const seconds = Number.parseFloat(parts[2]) || 0;\n\n return hours * 3600 + minutes * 60 + seconds;\n}\n\nexport function extractTimestampedTranscript(vttContent: string): string {\n if (!vttContent.trim()) {\n return \"\";\n }\n\n const lines = vttContent.split(\"\\n\");\n const segments: Array<{ time: number; text: string }> = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (line.includes(\"-->\")) {\n const startTime = line.split(\" --> \")[0].trim();\n const timeInSeconds = vttTimestampToSeconds(startTime);\n\n let j = i + 1;\n while (j < lines.length && !lines[j].trim()) {\n j++;\n }\n\n if (j < lines.length) {\n const text = lines[j].trim().replace(/<[^>]*>/g, \"\");\n if (text) {\n segments.push({ time: timeInSeconds, text });\n }\n }\n }\n }\n\n return segments\n .map(segment => `[${Math.floor(segment.time)}s] ${segment.text}`)\n .join(\"\\n\");\n}\n\n/**\n * Parses VTT content into structured cues with timing.\n *\n * @param vttContent - Raw VTT file content\n * @returns Array of VTT cues with start/end times and text\n */\nexport function parseVTTCues(vttContent: string): VTTCue[] {\n if (!vttContent.trim())\n return [];\n\n const lines = vttContent.split(\"\\n\");\n const cues: VTTCue[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (line.includes(\"-->\")) {\n const [startStr, endStr] = line.split(\" --> \").map(s => s.trim());\n const startTime = vttTimestampToSeconds(startStr);\n const endTime = vttTimestampToSeconds(endStr.split(\" \")[0]); // Handle cue settings\n\n // Collect text lines until empty line or next timestamp\n const textLines: string[] = [];\n let j = i + 1;\n while (j < lines.length && lines[j].trim() && !lines[j].includes(\"-->\")) {\n const cleanLine = lines[j].trim().replace(/<[^>]*>/g, \"\");\n if (cleanLine)\n textLines.push(cleanLine);\n j++;\n }\n\n if (textLines.length > 0) {\n cues.push({\n startTime,\n endTime,\n text: textLines.join(\" \"),\n });\n }\n }\n }\n\n return cues;\n}\n\n/**\n * Builds a transcript URL for the given playback ID and track ID.\n * If a signing context is provided, the URL will be signed with a token.\n *\n * @param playbackId - The Mux playback ID\n * @param trackId - The text track ID\n * @param signingContext - Optional signing context for signed playback IDs\n * @returns Transcript URL (signed if context provided)\n */\nexport async function buildTranscriptUrl(\n playbackId: string,\n trackId: string,\n signingContext?: SigningContext,\n): Promise<string> {\n const baseUrl = `https://stream.mux.com/${playbackId}/text/${trackId}.vtt`;\n\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"video\");\n }\n\n return baseUrl;\n}\n\nexport async function fetchTranscriptForAsset(\n asset: MuxAsset,\n playbackId: string,\n options: TranscriptFetchOptions = {},\n): Promise<TranscriptResult> {\n const { languageCode, cleanTranscript = true, signingContext } = options;\n const track = findCaptionTrack(asset, languageCode);\n\n if (!track) {\n return { transcriptText: \"\" };\n }\n\n if (!track.id) {\n return { transcriptText: \"\", track };\n }\n\n const transcriptUrl = await buildTranscriptUrl(playbackId, track.id, signingContext);\n\n try {\n const response = await fetch(transcriptUrl);\n if (!response.ok) {\n return { transcriptText: \"\", transcriptUrl, track };\n }\n\n const rawVtt = await response.text();\n const transcriptText = cleanTranscript ? extractTextFromVTT(rawVtt) : rawVtt;\n\n return { transcriptText, transcriptUrl, track };\n } catch (error) {\n console.warn(\"Failed to fetch transcript:\", error);\n return { transcriptText: \"\", transcriptUrl, track };\n }\n}\n","export * from \"./burned-in-captions\";\nexport * from \"./chapters\";\nexport * from \"./embeddings\";\nexport * from \"./moderation\";\nexport * from \"./summarization\";\nexport * from \"./translate-audio\";\nexport * from \"./translate-captions\";\n","import { generateObject } from \"ai\";\nimport dedent from \"dedent\";\nimport { z } from \"zod\";\n\nimport { createWorkflowClients } from \"../lib/client-factory\";\nimport type { ImageDownloadOptions } from \"../lib/image-download\";\nimport { downloadImageAsBase64 } from \"../lib/image-download\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport type { PromptOverrides } from \"../lib/prompt-builder\";\nimport { createPromptBuilder } from \"../lib/prompt-builder\";\nimport type { ModelIdByProvider, SupportedProvider } from \"../lib/providers\";\nimport { resolveSigningContext } from \"../lib/url-signing\";\nimport { getStoryboardUrl } from \"../primitives/storyboards\";\nimport type { ImageSubmissionMode, MuxAIOptions, TokenUsage } from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Structured payload returned from `hasBurnedInCaptions`. */\nexport interface BurnedInCaptionsResult {\n assetId: string;\n hasBurnedInCaptions: boolean;\n confidence: number;\n detectedLanguage: string | null;\n storyboardUrl: string;\n /** Token usage from the AI provider (for efficiency/cost analysis). */\n usage?: TokenUsage;\n}\n\n/**\n * Sections of the burned-in captions user prompt that can be overridden.\n * Use these to customize the AI's behavior for your specific use case.\n */\nexport type BurnedInCaptionsPromptSections =\n \"task\" |\n \"analysisSteps\" |\n \"positiveIndicators\" |\n \"negativeIndicators\";\n\n/**\n * Override specific sections of the burned-in captions prompt.\n * Each key corresponds to a section that can be customized.\n *\n * @example\n * ```typescript\n * const result = await hasBurnedInCaptions(assetId, {\n * promptOverrides: {\n * task: 'Detect any text overlays in the video frames.',\n * positiveIndicators: 'Classify as captions if text appears consistently.',\n * },\n * });\n * ```\n */\nexport type BurnedInCaptionsPromptOverrides = PromptOverrides<BurnedInCaptionsPromptSections>;\n\n/** Configuration accepted by `hasBurnedInCaptions`. */\nexport interface BurnedInCaptionsOptions extends MuxAIOptions {\n /** AI provider used for storyboard inspection (defaults to 'openai'). */\n provider?: SupportedProvider;\n /** Provider-specific model identifier. */\n model?: ModelIdByProvider[SupportedProvider];\n /** Transport used for storyboard submission (defaults to 'url'). */\n imageSubmissionMode?: ImageSubmissionMode;\n /** Download tuning used when `imageSubmissionMode` === 'base64'. */\n imageDownloadOptions?: ImageDownloadOptions;\n /**\n * Override specific sections of the user prompt.\n * Useful for customizing the AI's detection criteria for specific use cases.\n */\n promptOverrides?: BurnedInCaptionsPromptOverrides;\n}\n\n/** Schema used to validate burned-in captions analysis responses. */\nexport const burnedInCaptionsSchema = z.object({\n hasBurnedInCaptions: z.boolean(),\n confidence: z.number().min(0).max(1),\n detectedLanguage: z.string().nullable(),\n});\n\n/** Inferred shape returned from the burned-in captions schema. */\nexport type BurnedInCaptionsAnalysis = z.infer<typeof burnedInCaptionsSchema>;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Prompts\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SYSTEM_PROMPT = dedent`\n <role>\n You are an expert at analyzing video frames to detect burned-in captions (also called open captions or hardcoded subtitles).\n These are text overlays that are permanently embedded in the video image, common on TikTok, Instagram Reels, and other social media platforms.\n </role>\n\n <critical_note>\n Burned-in captions must appear consistently across MOST frames in the storyboard.\n Text appearing in only 1-2 frames at the end is typically marketing copy, taglines, or end-cards - NOT burned-in captions.\n </critical_note>\n\n <confidence_scoring>\n Use this rubric to determine your confidence score (0.0-1.0):\n\n - Score 1.0: Definitive captions - text overlays visible in most frames, consistent positioning, content changes between frames indicating dialogue/narration, clear caption-style formatting\n - Score 0.7-0.9: Strong evidence - captions visible across multiple frames with consistent placement, but minor ambiguity (e.g., some frames unclear, atypical styling)\n - Score 0.4-0.6: Moderate evidence - text present in several frames but uncertain classification (e.g., could be captions or persistent on-screen graphics, ambiguous formatting)\n - Score 0.1-0.3: Weak evidence - minimal text detected, appears in only a few frames, likely marketing copy or end-cards rather than captions\n - Score 0.0: No captions - no text overlays detected, or text is clearly not captions (logos, watermarks, scene content, single end-card)\n </confidence_scoring>\n\n <context>\n You receive storyboard images containing multiple sequential frames extracted from a video.\n These frames are arranged in a grid and represent the visual progression of the content over time.\n Read frames left-to-right, top-to-bottom to understand the temporal sequence.\n </context>\n\n <capabilities>\n - Detect and analyze text overlays in video frames\n - Distinguish between captions and other text elements (marketing, logos, UI)\n - Identify language of detected caption text\n - Assess confidence in caption detection\n </capabilities>\n\n <constraints>\n - Only classify as burned-in captions when evidence is clear across multiple frames\n - Base decisions on observable visual evidence\n - Return structured data matching the requested schema\n </constraints>`;\n\n/**\n * Prompt builder for the burned-in captions user prompt.\n * Sections can be individually overridden via `promptOverrides` in BurnedInCaptionsOptions.\n */\nconst burnedInCaptionsPromptBuilder = createPromptBuilder<BurnedInCaptionsPromptSections>({\n template: {\n task: {\n tag: \"task\",\n content: dedent`\n Analyze the provided video storyboard to detect burned-in captions (hardcoded subtitles).\n Count frames with text vs no text, note position consistency and whether text changes across frames.\n Decide if captions exist, with confidence (0.0-1.0) and detected language if any.`,\n },\n analysisSteps: {\n tag: \"analysis_steps\",\n content: dedent`\n 1. COUNT how many frames contain text overlays vs. how many don't\n 2. Check if text appears in consistent positions across multiple frames\n 3. Verify text changes content between frames (indicating dialogue/narration)\n 4. Ensure text has caption-style formatting (contrasting colors, readable fonts)\n 5. If captions are detected, identify the language of the text`,\n },\n positiveIndicators: {\n tag: \"classify_as_captions\",\n content: dedent`\n ONLY classify as burned-in captions if:\n - Text appears in multiple frames (not just 1-2 end frames)\n - Text positioning is consistent across those frames\n - Content suggests dialogue, narration, or subtitles (not marketing)\n - Formatting looks like captions (not graphics/logos)`,\n },\n negativeIndicators: {\n tag: \"not_captions\",\n content: dedent`\n DO NOT classify as burned-in captions:\n - Marketing taglines appearing only in final 1-2 frames\n - Single words or phrases that don't change between frames\n - Graphics, logos, watermarks, or UI elements\n - Text that's part of the original scene content\n - End-cards with calls-to-action or brand messaging`,\n },\n },\n sectionOrder: [\"task\", \"analysisSteps\", \"positiveIndicators\", \"negativeIndicators\"],\n});\n\nfunction buildUserPrompt(promptOverrides?: BurnedInCaptionsPromptOverrides): string {\n return burnedInCaptionsPromptBuilder.build(promptOverrides);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PROVIDER = \"openai\";\n\nexport async function hasBurnedInCaptions(\n assetId: string,\n options: BurnedInCaptionsOptions = {},\n): Promise<BurnedInCaptionsResult> {\n const {\n provider = DEFAULT_PROVIDER,\n model,\n imageSubmissionMode = \"url\",\n imageDownloadOptions,\n promptOverrides,\n ...config\n } = options;\n\n // Build the user prompt with any overrides\n const userPrompt = buildUserPrompt(promptOverrides);\n\n const clients = createWorkflowClients(\n { ...config, model },\n provider as SupportedProvider,\n );\n const { playbackId, policy } = await getPlaybackIdForAsset(clients.mux, assetId);\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n const imageUrl = await getStoryboardUrl(playbackId, 640, policy === \"signed\" ? signingContext : undefined);\n\n interface AnalysisResponse {\n result: BurnedInCaptionsAnalysis;\n usage: TokenUsage;\n }\n\n const analyzeStoryboard = async (imageDataUrl: string): Promise<AnalysisResponse> => {\n const response = await generateObject({\n model: clients.languageModel.model,\n schema: burnedInCaptionsSchema,\n abortSignal: options.abortSignal,\n experimental_telemetry: { isEnabled: true },\n messages: [\n {\n role: \"system\",\n content: SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: [\n { type: \"text\", text: userPrompt },\n { type: \"image\", image: imageDataUrl },\n ],\n },\n ],\n });\n\n return {\n result: response.object,\n usage: {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: response.usage.totalTokens,\n reasoningTokens: response.usage.reasoningTokens,\n cachedInputTokens: response.usage.cachedInputTokens,\n },\n };\n };\n\n let analysisResponse: AnalysisResponse;\n\n if (imageSubmissionMode === \"base64\") {\n const downloadResult = await downloadImageAsBase64(imageUrl, imageDownloadOptions);\n analysisResponse = await analyzeStoryboard(downloadResult.base64Data);\n } else {\n analysisResponse = await analyzeStoryboard(imageUrl);\n }\n\n if (!analysisResponse.result) {\n throw new Error(\"No analysis result received from AI provider\");\n }\n\n return {\n assetId,\n hasBurnedInCaptions: analysisResponse.result.hasBurnedInCaptions ?? false,\n confidence: analysisResponse.result.confidence ?? 0,\n detectedLanguage: analysisResponse.result.detectedLanguage ?? null,\n storyboardUrl: imageUrl,\n usage: analysisResponse.usage,\n };\n}\n","function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\nfunction _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _toPropertyKey(arg) { var key = _toPrimitive(arg, \"string\"); return typeof key === \"symbol\" ? key : String(key); }\nfunction _toPrimitive(input, hint) { if (typeof input !== \"object\" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || \"default\"); if (typeof res !== \"object\") return res; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (hint === \"string\" ? String : Number)(input); }\nconst dedent = createDedent({});\nexport default dedent;\nfunction createDedent(options) {\n dedent.withOptions = newOptions => createDedent(_objectSpread(_objectSpread({}, options), newOptions));\n return dedent;\n function dedent(strings, ...values) {\n const raw = typeof strings === \"string\" ? [strings] : strings.raw;\n const {\n alignValues = false,\n escapeSpecialCharacters = Array.isArray(strings),\n trimWhitespace = true\n } = options;\n\n // first, perform interpolation\n let result = \"\";\n for (let i = 0; i < raw.length; i++) {\n let next = raw[i];\n if (escapeSpecialCharacters) {\n // handle escaped newlines, backticks, and interpolation characters\n next = next.replace(/\\\\\\n[ \\t]*/g, \"\").replace(/\\\\`/g, \"`\").replace(/\\\\\\$/g, \"$\").replace(/\\\\\\{/g, \"{\");\n }\n result += next;\n if (i < values.length) {\n const value = alignValues ? alignValue(values[i], result) : values[i];\n\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n result += value;\n }\n }\n\n // now strip indentation\n const lines = result.split(\"\\n\");\n let mindent = null;\n for (const l of lines) {\n const m = l.match(/^(\\s+)\\S+/);\n if (m) {\n const indent = m[1].length;\n if (!mindent) {\n // this is the first indented line\n mindent = indent;\n } else {\n mindent = Math.min(mindent, indent);\n }\n }\n }\n if (mindent !== null) {\n const m = mindent; // appease TypeScript\n result = lines\n // https://github.com/typescript-eslint/typescript-eslint/issues/7140\n // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with\n .map(l => l[0] === \" \" || l[0] === \"\\t\" ? l.slice(m) : l).join(\"\\n\");\n }\n\n // dedent eats leading and trailing whitespace too\n if (trimWhitespace) {\n result = result.trim();\n }\n\n // handle escaped newlines at the end to ensure they don't get stripped too\n if (escapeSpecialCharacters) {\n result = result.replace(/\\\\n/g, \"\\n\");\n }\n return result;\n }\n}\n\n/**\n * Adjusts the indentation of a multi-line interpolated value to match the current line.\n */\nfunction alignValue(value, precedingText) {\n if (typeof value !== \"string\" || !value.includes(\"\\n\")) {\n return value;\n }\n const currentLine = precedingText.slice(precedingText.lastIndexOf(\"\\n\") + 1);\n const indentMatch = currentLine.match(/^(\\s+)/);\n if (indentMatch) {\n const indent = indentMatch[1];\n return value.replace(/\\n/g, `\\n${indent}`);\n }\n return value;\n}\n","import Mux from \"@mux/mux-node\";\n\nimport env from \"../env\";\n\nimport type {\n ModelRequestOptions,\n ResolvedModel,\n SupportedProvider,\n} from \"./providers\";\nimport {\n resolveLanguageModel,\n} from \"./providers\";\n\nexport interface ClientCredentials {\n muxTokenId?: string;\n muxTokenSecret?: string;\n openaiApiKey?: string;\n anthropicApiKey?: string;\n googleApiKey?: string;\n}\n\nexport interface ValidatedCredentials {\n muxTokenId: string;\n muxTokenSecret: string;\n openaiApiKey?: string;\n anthropicApiKey?: string;\n googleApiKey?: string;\n}\n\n/**\n * Validates and retrieves credentials from options or environment variables\n */\nexport function validateCredentials(\n options: ClientCredentials,\n requiredProvider?: SupportedProvider,\n): ValidatedCredentials {\n const muxTokenId = options.muxTokenId ?? env.MUX_TOKEN_ID;\n const muxTokenSecret = options.muxTokenSecret ?? env.MUX_TOKEN_SECRET;\n const openaiApiKey = options.openaiApiKey ?? env.OPENAI_API_KEY;\n const anthropicApiKey = options.anthropicApiKey ?? env.ANTHROPIC_API_KEY;\n const googleApiKey =\n options.googleApiKey ?? env.GOOGLE_GENERATIVE_AI_API_KEY;\n\n if (!muxTokenId || !muxTokenSecret) {\n throw new Error(\n \"Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.\",\n );\n }\n\n if (requiredProvider === \"openai\" && !openaiApiKey) {\n throw new Error(\n \"OpenAI API key is required. Provide openaiApiKey in options or set OPENAI_API_KEY environment variable.\",\n );\n }\n\n if (requiredProvider === \"anthropic\" && !anthropicApiKey) {\n throw new Error(\n \"Anthropic API key is required. Provide anthropicApiKey in options or set ANTHROPIC_API_KEY environment variable.\",\n );\n }\n\n if (requiredProvider === \"google\" && !googleApiKey) {\n throw new Error(\n \"Google Generative AI API key is required. Provide googleApiKey in options or set GOOGLE_GENERATIVE_AI_API_KEY environment variable.\",\n );\n }\n\n return {\n muxTokenId,\n muxTokenSecret,\n openaiApiKey,\n anthropicApiKey,\n googleApiKey,\n };\n}\n\n/**\n * Creates a Mux client with validated credentials\n */\nexport function createMuxClient(credentials: ValidatedCredentials): Mux {\n if (!credentials.muxTokenId || !credentials.muxTokenSecret) {\n throw new Error(\"Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.\");\n }\n return new Mux({\n tokenId: credentials.muxTokenId,\n tokenSecret: credentials.muxTokenSecret,\n });\n}\n\n/**\n * Factory for creating all necessary clients for a workflow\n */\nexport interface WorkflowClients {\n mux: Mux;\n languageModel: ResolvedModel;\n credentials: ValidatedCredentials;\n}\n\nexport function createWorkflowClients(\n options: ModelRequestOptions,\n provider?: SupportedProvider,\n): WorkflowClients {\n const providerToUse = provider || options.provider || \"openai\";\n const credentials = validateCredentials(options, providerToUse);\n const languageModel = resolveLanguageModel({\n ...options,\n provider: providerToUse,\n });\n\n return {\n mux: createMuxClient(credentials),\n languageModel,\n credentials,\n };\n}\n","import { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\n\nimport env from \"../env\";\nimport type { MuxAIOptions } from \"../types\";\n\nimport type { EmbeddingModel, LanguageModel } from \"ai\";\n\nexport type SupportedProvider = \"openai\" | \"anthropic\" | \"google\";\nexport type SupportedEmbeddingProvider = \"openai\" | \"google\";\n\n// Model ID unions inferred from ai-sdk provider call signatures\ntype OpenAIModelId = Parameters<ReturnType<typeof createOpenAI>[\"chat\"]>[0];\ntype AnthropicModelId = Parameters<ReturnType<typeof createAnthropic>[\"chat\"]>[0];\ntype GoogleModelId = Parameters<ReturnType<typeof createGoogleGenerativeAI>[\"chat\"]>[0];\n\ntype OpenAIEmbeddingModelId = Parameters<ReturnType<typeof createOpenAI>[\"embedding\"]>[0];\ntype GoogleEmbeddingModelId = Parameters<ReturnType<typeof createGoogleGenerativeAI>[\"textEmbeddingModel\"]>[0];\n\nexport interface ModelIdByProvider {\n openai: OpenAIModelId;\n anthropic: AnthropicModelId;\n google: GoogleModelId;\n}\n\nexport interface EmbeddingModelIdByProvider {\n openai: OpenAIEmbeddingModelId;\n google: GoogleEmbeddingModelId;\n}\n\nexport interface ModelRequestOptions<P extends SupportedProvider = SupportedProvider> extends MuxAIOptions {\n provider?: P;\n model?: ModelIdByProvider[P];\n}\n\nexport interface ResolvedModel<P extends SupportedProvider = SupportedProvider> {\n provider: P;\n modelId: ModelIdByProvider[P];\n model: LanguageModel;\n}\n\nexport const DEFAULT_LANGUAGE_MODELS: { [K in SupportedProvider]: ModelIdByProvider[K] } = {\n openai: \"gpt-5-mini\",\n anthropic: \"claude-haiku-4-5\",\n google: \"gemini-2.5-flash\",\n};\n\nconst DEFAULT_EMBEDDING_MODELS: { [K in SupportedEmbeddingProvider]: EmbeddingModelIdByProvider[K] } = {\n openai: \"text-embedding-3-small\",\n google: \"gemini-embedding-001\",\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Model Pricing\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Pricing is in USD per million tokens. These values are used for cost estimation\n// in evaluations and should be periodically verified against official sources.\n//\n// Sources (as of December 2025):\n// - OpenAI: https://openai.com/api/pricing\n// - Anthropic: https://www.anthropic.com/pricing\n// - Google: https://ai.google.dev/pricing\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Pricing structure for a language model.\n * All costs are in USD per million tokens.\n */\nexport interface ModelPricing {\n /** Cost per million input tokens (USD). */\n inputPerMillion: number;\n /** Cost per million output tokens (USD). */\n outputPerMillion: number;\n /** Cost per million cached input tokens (USD), if supported. */\n cachedInputPerMillion?: number;\n /** URL to the official pricing page for verification. */\n pricingUrl: string;\n}\n\n/**\n * Pricing data for the default language models.\n * Used for cost estimation in evaluations and expense tracking.\n *\n * @remarks\n * Prices are subject to change. Verify against official sources before production use.\n */\nexport const THIRD_PARTY_MODEL_PRICING: { [K in SupportedProvider]: ModelPricing } = {\n // OpenAI GPT-5 Mini\n // Reference: https://openai.com/api/pricing\n openai: {\n inputPerMillion: 0.25,\n outputPerMillion: 2.00,\n cachedInputPerMillion: 0.025,\n pricingUrl: \"https://openai.com/api/pricing\",\n },\n\n // Anthropic Claude Haiku 4.5\n // Reference: https://www.anthropic.com/pricing\n anthropic: {\n inputPerMillion: 1.00,\n outputPerMillion: 5.00,\n cachedInputPerMillion: 0.10, // Prompt caching read cost\n pricingUrl: \"https://www.anthropic.com/pricing\",\n },\n\n // Google Gemini 2.5 Flash\n // Reference: https://ai.google.dev/pricing\n google: {\n inputPerMillion: 0.30,\n outputPerMillion: 2.50,\n cachedInputPerMillion: 0.03, // Context caching price\n pricingUrl: \"https://ai.google.dev/pricing\",\n },\n};\n\n/**\n * Calculates the estimated cost for a request based on token usage.\n *\n * @param provider - The AI provider used\n * @param inputTokens - Number of input tokens consumed\n * @param outputTokens - Number of output tokens generated\n * @param cachedInputTokens - Number of input tokens served from cache (optional)\n * @returns Estimated cost in USD\n *\n * @example\n * ```typescript\n * const cost = calculateCost('openai', 2000, 500);\n * console.log(`Estimated cost: $${cost.toFixed(6)}`);\n * ```\n */\nexport function calculateCost(\n provider: SupportedProvider,\n inputTokens: number,\n outputTokens: number,\n cachedInputTokens: number = 0,\n): number {\n const pricing = THIRD_PARTY_MODEL_PRICING[provider];\n\n // Adjust input tokens: cached tokens are charged at cached rate, rest at full rate\n const uncachedInputTokens = Math.max(0, inputTokens - cachedInputTokens);\n\n const inputCost = (uncachedInputTokens / 1_000_000) * pricing.inputPerMillion;\n const outputCost = (outputTokens / 1_000_000) * pricing.outputPerMillion;\n let cachedCost = 0;\n if (pricing.cachedInputPerMillion) {\n cachedCost = (cachedInputTokens / 1_000_000) * pricing.cachedInputPerMillion;\n }\n\n return inputCost + outputCost + cachedCost;\n}\n\nfunction requireEnv(value: string | undefined, name: string): string {\n if (!value) {\n throw new Error(`Missing ${name}. Set ${name} in your environment or pass it in options.`);\n }\n return value;\n}\n\n/**\n * Resolves a language model from a suggested provider.\n */\nexport function resolveLanguageModel<P extends SupportedProvider = SupportedProvider>(\n options: ModelRequestOptions<P> = {},\n): ResolvedModel<P> {\n const provider = options.provider || (\"openai\" as P);\n const modelId = (options.model || DEFAULT_LANGUAGE_MODELS[provider]) as ModelIdByProvider[P];\n\n switch (provider) {\n case \"openai\": {\n const apiKey = options.openaiApiKey ?? env.OPENAI_API_KEY;\n requireEnv(apiKey, \"OPENAI_API_KEY\");\n const openai = createOpenAI({\n apiKey,\n });\n\n return {\n provider,\n modelId,\n model: openai(modelId),\n };\n }\n case \"anthropic\": {\n const apiKey = options.anthropicApiKey ?? env.ANTHROPIC_API_KEY;\n requireEnv(apiKey, \"ANTHROPIC_API_KEY\");\n const anthropic = createAnthropic({\n apiKey,\n });\n\n return {\n provider,\n modelId,\n model: anthropic(modelId),\n };\n }\n case \"google\": {\n const apiKey = options.googleApiKey ?? env.GOOGLE_GENERATIVE_AI_API_KEY;\n requireEnv(apiKey, \"GOOGLE_GENERATIVE_AI_API_KEY\");\n const google = createGoogleGenerativeAI({\n apiKey,\n });\n\n return {\n provider,\n modelId,\n model: google(modelId),\n };\n }\n default: {\n const exhaustiveCheck: never = provider;\n throw new Error(`Unsupported provider: ${exhaustiveCheck}`);\n }\n }\n}\n\n/**\n * Resolves an embedding model from a suggested provider.\n */\nexport function resolveEmbeddingModel<P extends SupportedEmbeddingProvider = \"openai\">(\n options: MuxAIOptions & { provider?: P; model?: EmbeddingModelIdByProvider[P] } = {},\n): { provider: P; modelId: EmbeddingModelIdByProvider[P]; model: EmbeddingModel<string> } {\n const provider = options.provider || (\"openai\" as P);\n const modelId = (options.model || DEFAULT_EMBEDDING_MODELS[provider]) as EmbeddingModelIdByProvider[P];\n\n switch (provider) {\n case \"openai\": {\n const apiKey = options.openaiApiKey ?? env.OPENAI_API_KEY;\n requireEnv(apiKey, \"OPENAI_API_KEY\");\n const openai = createOpenAI({\n apiKey,\n });\n\n return {\n provider,\n modelId,\n model: openai.embedding(modelId),\n };\n }\n case \"google\": {\n const apiKey = options.googleApiKey ?? env.GOOGLE_GENERATIVE_AI_API_KEY;\n requireEnv(apiKey, \"GOOGLE_GENERATIVE_AI_API_KEY\");\n const google = createGoogleGenerativeAI({\n apiKey,\n });\n\n return {\n provider,\n modelId,\n model: google.textEmbeddingModel(modelId),\n };\n }\n default: {\n const exhaustiveCheck: never = provider;\n throw new Error(`Unsupported embedding provider: ${exhaustiveCheck}`);\n }\n }\n}\n","import { Buffer } from \"node:buffer\";\n\nimport pRetry, { AbortError } from \"p-retry\";\n\nexport interface ImageDownloadOptions {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Maximum number of retry attempts (default: 3) */\n retries?: number;\n /** Base delay between retries in milliseconds (default: 1000) */\n retryDelay?: number;\n /** Maximum delay between retries in milliseconds (default: 10000) */\n maxRetryDelay?: number;\n /** Whether to use exponential backoff (default: true) */\n exponentialBackoff?: boolean;\n}\n\nexport interface ImageDownloadResult {\n /** Base64 encoded image data with data URI prefix (e.g., \"data:image/png;base64,iVBORw0K...\") */\n base64Data: string;\n /** Raw image buffer for multipart/form-data uploads */\n buffer: Buffer;\n /** Original image URL */\n url: string;\n /** Content type of the downloaded image */\n contentType: string;\n /** Size of the downloaded image in bytes */\n sizeBytes: number;\n /** Number of retry attempts made (0 if successful on first try) */\n attempts: number;\n}\n\nexport interface AnthropicFileUploadResult {\n /** Anthropic Files API file ID */\n fileId: string;\n /** Original image URL */\n url: string;\n /** Content type of the uploaded image */\n contentType: string;\n /** Size of the uploaded image in bytes */\n sizeBytes: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ImageDownloadOptions> = {\n timeout: 10000,\n retries: 3,\n retryDelay: 1000,\n maxRetryDelay: 10000,\n exponentialBackoff: true,\n};\n\n/**\n * Downloads an image from a URL and converts it to base64 with robust retry logic\n *\n * @param url - The image URL to download\n * @param options - Download configuration options\n * @returns Promise resolving to ImageDownloadResult with base64 data and metadata\n * @throws Error if download fails after all retries\n */\nexport async function downloadImageAsBase64(\n url: string,\n options: ImageDownloadOptions = {},\n): Promise<ImageDownloadResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n let attemptCount = 0;\n\n return pRetry(\n async () => {\n attemptCount++;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), opts.timeout);\n\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers: {\n \"User-Agent\": \"@mux/ai image downloader\",\n },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n // Don't retry 4xx errors (except 429 rate limiting)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n throw new AbortError(`HTTP ${response.status}: ${response.statusText}`);\n }\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (!contentType?.startsWith(\"image/\")) {\n throw new AbortError(`Invalid content type: ${contentType}. Expected image/*`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n if (buffer.length === 0) {\n throw new AbortError(\"Downloaded image is empty\");\n }\n\n // Convert to base64 with data URI prefix\n const base64Data = `data:${contentType};base64,${buffer.toString(\"base64\")}`;\n\n return {\n base64Data,\n buffer,\n url,\n contentType,\n sizeBytes: buffer.length,\n attempts: attemptCount,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n\n // If it's an AbortError (non-retryable), re-throw it\n if (error instanceof AbortError) {\n throw error;\n }\n\n // For network errors, timeout errors, etc., wrap in retryable error\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new Error(`Request timeout after ${opts.timeout}ms`);\n }\n throw new Error(`Download failed: ${error.message}`);\n }\n\n throw new Error(\"Unknown download error\");\n }\n },\n {\n retries: opts.retries,\n minTimeout: opts.retryDelay,\n maxTimeout: opts.maxRetryDelay,\n factor: opts.exponentialBackoff ? 2 : 1,\n randomize: true, // Add jitter to prevent thundering herd\n onFailedAttempt: (error) => {\n console.warn(`Image download attempt ${error.attemptNumber} failed for ${url}`);\n if (error.retriesLeft > 0) {\n console.warn(`Retrying... (${error.retriesLeft} attempts left)`);\n }\n },\n },\n );\n}\n\n/**\n * Downloads multiple images concurrently with controlled concurrency\n *\n * @param urls - Array of image URLs to download\n * @param options - Download configuration options\n * @param maxConcurrent - Maximum concurrent downloads (default: 5)\n * @returns Promise resolving to array of ImageDownloadResult (in same order as input URLs)\n */\nexport async function downloadImagesAsBase64(\n urls: string[],\n options: ImageDownloadOptions = {},\n maxConcurrent: number = 5,\n): Promise<ImageDownloadResult[]> {\n const results: ImageDownloadResult[] = [];\n\n for (let i = 0; i < urls.length; i += maxConcurrent) {\n const batch = urls.slice(i, i + maxConcurrent);\n const batchPromises = batch.map(url => downloadImageAsBase64(url, options));\n const batchResults = await Promise.all(batchPromises);\n results.push(...batchResults);\n }\n\n return results;\n}\n\n/**\n * Uploads an image to Anthropic Files API for use in messages\n *\n * @param url - The image URL to download and upload\n * @param anthropicApiKey - Anthropic API key\n * @param options - Download configuration options\n * @returns Promise resolving to AnthropicFileUploadResult with file ID and metadata\n * @throws Error if download or upload fails\n */\nexport async function uploadImageToAnthropicFiles(\n url: string,\n anthropicApiKey: string,\n options: ImageDownloadOptions = {},\n): Promise<AnthropicFileUploadResult> {\n // First download the image\n const downloadResult = await downloadImageAsBase64(url, options);\n\n // Create form data for Files API upload\n const formData = new FormData();\n\n // Create a Blob from the buffer for form data\n const imageBlob = new Blob([downloadResult.buffer], {\n type: downloadResult.contentType,\n });\n\n // Get file extension from content type\n const extension = downloadResult.contentType.split(\"/\")[1] || \"png\";\n formData.append(\"file\", imageBlob, `image.${extension}`);\n\n // Upload to Anthropic Files API\n const response = await fetch(\"https://api.anthropic.com/v1/files\", {\n method: \"POST\",\n headers: {\n \"x-api-key\": anthropicApiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"files-api-2025-04-14\",\n // Don't set Content-Type header - let fetch set it with boundary for multipart\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Anthropic Files API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const fileResult = await response.json() as { id: string };\n\n return {\n fileId: fileResult.id,\n url: downloadResult.url,\n contentType: downloadResult.contentType,\n sizeBytes: downloadResult.sizeBytes,\n };\n}\n","import type { MuxAsset, PlaybackAsset, PlaybackPolicy } from \"../types\";\n\nimport type Mux from \"@mux/mux-node\";\n\n/**\n * Finds a usable playback ID for the given asset.\n * Prefers public playback IDs, falls back to signed if no public is available.\n * Throws an error if no public or signed playback ID is found.\n */\nfunction getPlaybackId(asset: MuxAsset): { id: string; policy: PlaybackPolicy } {\n const playbackIds = asset.playback_ids || [];\n\n // First, try to find a public playback ID\n const publicPlaybackId = playbackIds.find(pid => pid.policy === \"public\");\n if (publicPlaybackId?.id) {\n return { id: publicPlaybackId.id, policy: \"public\" };\n }\n\n // Fall back to signed playback ID\n const signedPlaybackId = playbackIds.find(pid => pid.policy === \"signed\");\n if (signedPlaybackId?.id) {\n return { id: signedPlaybackId.id, policy: \"signed\" };\n }\n\n throw new Error(\n \"No public or signed playback ID found for this asset. \" +\n \"A public or signed playback ID is required. DRM playback IDs are not currently supported.\",\n );\n}\n\nexport async function getPlaybackIdForAsset(\n mux: Mux,\n assetId: string,\n): Promise<PlaybackAsset> {\n const asset = await mux.video.assets.retrieve(assetId);\n const { id: playbackId, policy } = getPlaybackId(asset);\n\n return { asset, playbackId, policy };\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * A single section of a prompt, rendered as an XML-like tag.\n */\nexport interface PromptSection {\n /** The XML tag name for this section */\n tag: string;\n /** The content inside the tag */\n content: string;\n /** Optional attributes to add to the tag (e.g., { format: \"plain text\" }) */\n attributes?: Record<string, string>;\n}\n\n/**\n * Configuration for building a prompt section.\n * Can be a full PromptSection object, just a string (content only), or undefined to use default.\n */\nexport type SectionOverride = string | PromptSection | undefined;\n\n/**\n * A template defining the default sections for a prompt.\n * Keys are section identifiers, values are the default PromptSection definitions.\n */\nexport type PromptTemplate<TSections extends string> = Record<TSections, PromptSection>;\n\n/**\n * User-provided overrides for prompt sections.\n * Each key can override the corresponding section's content or full definition.\n */\nexport type PromptOverrides<TSections extends string> = Partial<Record<TSections, SectionOverride>>;\n\n/**\n * Configuration for the prompt builder.\n */\nexport interface PromptBuilderConfig<TSections extends string> {\n /** Default sections that make up the prompt template */\n template: PromptTemplate<TSections>;\n /** Order in which sections should appear in the final prompt */\n sectionOrder: TSections[];\n}\n\n/**\n * A configured prompt builder instance with methods to build prompts.\n */\nexport interface PromptBuilder<TSections extends string> {\n /** The default template sections */\n template: PromptTemplate<TSections>;\n /** Build a prompt string, optionally overriding specific sections */\n build: (overrides?: PromptOverrides<TSections>) => string;\n /** Build a prompt with additional dynamic sections appended */\n buildWithContext: (\n overrides?: PromptOverrides<TSections>,\n additionalSections?: PromptSection[],\n ) => string;\n /** Get a single section's content (useful for partial rendering) */\n getSection: (section: TSections, override?: SectionOverride) => string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Renders a PromptSection as an XML-like string.\n */\nexport function renderSection(section: PromptSection): string {\n const { tag, content, attributes } = section;\n\n const XML_NAME_PATTERN = /^[A-Z_][\\w.:-]*$/i;\n\n const assertValidXmlName = (name: string, context: \"tag\" | \"attribute\"): void => {\n if (!XML_NAME_PATTERN.test(name)) {\n throw new Error(`Invalid XML ${context} name: \"${name}\"`);\n }\n };\n\n const escapeXmlText = (value: string): string =>\n value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;/\");\n\n const escapeXmlAttribute = (value: string): string =>\n escapeXmlText(value).replace(/\"/g, \"&quot;\");\n\n if (!content.trim()) {\n return \"\";\n }\n\n assertValidXmlName(tag, \"tag\");\n\n const attrString = attributes ?\n ` ${\n Object.entries(attributes)\n .map(([key, value]) => {\n assertValidXmlName(key, \"attribute\");\n return `${key}=\"${escapeXmlAttribute(value)}\"`;\n })\n .join(\" \")}` :\n \"\";\n\n const safeContent = escapeXmlText(content.trim());\n\n return `<${tag}${attrString}>\\n${safeContent}\\n</${tag}>`;\n}\n\n/**\n * Resolves a section override to a full PromptSection.\n */\nfunction resolveSection(\n defaultSection: PromptSection,\n override?: SectionOverride,\n): PromptSection {\n if (override === undefined) {\n return defaultSection;\n }\n\n if (typeof override === \"string\") {\n return { ...defaultSection, content: override };\n }\n\n return override;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Creates a type-safe prompt builder from a template configuration.\n *\n * @example\n * ```typescript\n * const builder = createPromptBuilder({\n * template: {\n * task: { tag: 'task', content: 'Analyze the image...' },\n * tone: { tag: 'tone', content: 'Be professional.' },\n * },\n * sectionOrder: ['task', 'tone'],\n * });\n *\n * // Use defaults\n * const prompt1 = builder.build();\n *\n * // Override specific sections\n * const prompt2 = builder.build({\n * tone: 'Be casual and friendly.',\n * });\n * ```\n */\nexport function createPromptBuilder<TSections extends string>(\n config: PromptBuilderConfig<TSections>,\n): PromptBuilder<TSections> {\n const { template, sectionOrder } = config;\n\n const getSection = (section: TSections, override?: SectionOverride): string => {\n const resolved = resolveSection(template[section], override);\n return renderSection(resolved);\n };\n\n const build = (overrides?: PromptOverrides<TSections>): string => {\n const sections = sectionOrder\n .map(sectionKey => getSection(sectionKey, overrides?.[sectionKey]))\n .filter(Boolean);\n\n return sections.join(\"\\n\\n\");\n };\n\n const buildWithContext = (\n overrides?: PromptOverrides<TSections>,\n additionalSections?: PromptSection[],\n ): string => {\n const basePrompt = build(overrides);\n\n if (!additionalSections?.length) {\n return basePrompt;\n }\n\n const additional = additionalSections\n .map(renderSection)\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n return additional ? `${basePrompt}\\n\\n${additional}` : basePrompt;\n };\n\n return {\n template,\n build,\n buildWithContext,\n getSection,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Common Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Creates a transcript section for inclusion in prompts.\n */\nexport function createTranscriptSection(\n transcriptText: string,\n format: \"plain text\" | \"WebVTT\" = \"plain text\",\n): PromptSection {\n return {\n tag: \"transcript\",\n content: transcriptText,\n attributes: { format },\n };\n}\n\n/**\n * Creates a tone section for inclusion in prompts.\n */\nexport function createToneSection(instruction: string): PromptSection {\n return {\n tag: \"tone\",\n content: instruction,\n };\n}\n","import { generateObject } from \"ai\";\nimport { z } from \"zod\";\n\nimport { createWorkflowClients } from \"../lib/client-factory\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport type { ModelIdByProvider, SupportedProvider } from \"../lib/providers\";\nimport { withRetry } from \"../lib/retry\";\nimport { resolveSigningContext } from \"../lib/url-signing\";\nimport {\n extractTimestampedTranscript,\n fetchTranscriptForAsset,\n getReadyTextTracks,\n} from \"../primitives/transcripts\";\nimport type { MuxAIOptions } from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const chapterSchema = z.object({\n startTime: z.number(),\n title: z.string(),\n});\n\nexport type Chapter = z.infer<typeof chapterSchema>;\n\nexport const chaptersSchema = z.object({\n chapters: z.array(chapterSchema),\n});\n\nexport type ChaptersType = z.infer<typeof chaptersSchema>;\n\n/** Structured return payload from `generateChapters`. */\nexport interface ChaptersResult {\n assetId: string;\n languageCode: string;\n chapters: Chapter[];\n}\n\n/** Configuration accepted by `generateChapters`. */\nexport interface ChaptersOptions extends MuxAIOptions {\n /** AI provider used to interpret the transcript (defaults to 'openai'). */\n provider?: SupportedProvider;\n /** Provider-specific model identifier. */\n model?: ModelIdByProvider[SupportedProvider];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PROVIDER = \"openai\";\n\nconst SYSTEM_PROMPT = `Your role is to segment the following captions into chunked chapters, summarising each chapter with a title.\n\nAnalyze the transcript and create logical chapter breaks based on topic changes, major transitions, or distinct sections of content. Each chapter should represent a meaningful segment of the video.\n\nYou must respond with valid JSON in exactly this format:\n{\n \"chapters\": [\n {\"startTime\": 0, \"title\": \"Introduction\"},\n {\"startTime\": 45.5, \"title\": \"Main Topic Discussion\"},\n {\"startTime\": 120.0, \"title\": \"Conclusion\"}\n ]\n}\n\nImportant rules:\n- startTime must be in seconds (not HH:MM:SS format)\n- Always start with startTime: 0 for the first chapter\n- Create 3-8 chapters depending on content length and natural breaks\n- Chapter titles should be concise and descriptive\n- Do not include any text before or after the JSON\n- The JSON must be valid and parseable`;\n\nexport async function generateChapters(\n assetId: string,\n languageCode: string,\n options: ChaptersOptions = {},\n): Promise<ChaptersResult> {\n const { provider = DEFAULT_PROVIDER, model, abortSignal } = options;\n\n // Initialize clients with validated credentials and resolved language model\n const clients = createWorkflowClients({ ...options, model }, provider as SupportedProvider);\n\n // Fetch asset and caption track/transcript\n const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(clients.mux, assetId);\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n const transcriptResult = await fetchTranscriptForAsset(assetData, playbackId, {\n languageCode,\n cleanTranscript: false, // keep timestamps for chapter segmentation\n signingContext: policy === \"signed\" ? signingContext : undefined,\n });\n\n if (!transcriptResult.track || !transcriptResult.transcriptText) {\n const availableLanguages = getReadyTextTracks(assetData)\n .map(t => t.language_code)\n .filter(Boolean)\n .join(\", \");\n throw new Error(\n `No caption track found for language '${languageCode}'. Available languages: ${availableLanguages || \"none\"}`,\n );\n }\n\n const timestampedTranscript = extractTimestampedTranscript(transcriptResult.transcriptText);\n if (!timestampedTranscript) {\n throw new Error(\"No usable content found in caption track\");\n }\n\n // Generate chapters using AI SDK\n let chaptersData: { chapters: Chapter[] } | null = null;\n\n try {\n const response = await withRetry(() =>\n generateObject({\n model: clients.languageModel.model,\n schema: chaptersSchema,\n abortSignal,\n messages: [\n {\n role: \"system\",\n content: SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: timestampedTranscript,\n },\n ],\n }),\n );\n\n chaptersData = response.object;\n } catch (error) {\n throw new Error(\n `Failed to generate chapters with ${provider}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n if (!chaptersData || !chaptersData.chapters) {\n throw new Error(\"No chapters generated from AI response\");\n }\n\n // Validate and sort chapters\n const validChapters = chaptersData.chapters\n .filter(chapter => typeof chapter.startTime === \"number\" && typeof chapter.title === \"string\")\n .sort((a, b) => a.startTime - b.startTime);\n\n if (validChapters.length === 0) {\n throw new Error(\"No valid chapters found in AI response\");\n }\n\n // Ensure first chapter starts at 0\n if (validChapters[0].startTime !== 0) {\n validChapters[0].startTime = 0;\n }\n\n return {\n assetId,\n languageCode,\n chapters: validChapters,\n };\n}\n","/**\n * Retry configuration options\n */\nexport interface RetryOptions {\n maxRetries?: number;\n baseDelay?: number;\n maxDelay?: number;\n shouldRetry?: (error: Error, attempt: number) => boolean;\n}\n\nconst DEFAULT_RETRY_OPTIONS: Required<Omit<RetryOptions, \"shouldRetry\">> = {\n maxRetries: 3,\n baseDelay: 2000,\n maxDelay: 10000,\n};\n\n/**\n * Default retry condition - retries on timeout errors\n */\nfunction defaultShouldRetry(error: Error, _attempt: number): boolean {\n return Boolean(error.message && error.message.includes(\"Timeout while downloading\"));\n}\n\n/**\n * Calculates exponential backoff delay with jitter\n */\nfunction calculateDelay(attempt: number, baseDelay: number, maxDelay: number): number {\n const exponentialDelay = baseDelay * 2 ** (attempt - 1);\n const delayWithJitter = exponentialDelay * (0.5 + Math.random() * 0.5);\n return Math.min(delayWithJitter, maxDelay);\n}\n\n/**\n * Executes an async function with retry logic\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n {\n maxRetries = DEFAULT_RETRY_OPTIONS.maxRetries,\n baseDelay = DEFAULT_RETRY_OPTIONS.baseDelay,\n maxDelay = DEFAULT_RETRY_OPTIONS.maxDelay,\n shouldRetry = defaultShouldRetry,\n }: RetryOptions = {},\n): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isLastAttempt = attempt === maxRetries;\n if (isLastAttempt || !shouldRetry(lastError, attempt + 1)) {\n throw lastError;\n }\n\n const delay = calculateDelay(attempt + 1, baseDelay, maxDelay);\n console.warn(\n `Attempt ${attempt + 1} failed: ${lastError.message}. Retrying in ${Math.round(delay)}ms...`,\n );\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n\n throw lastError || new Error(\"Retry failed with unknown error\");\n}\n","import { embed } from \"ai\";\n\nimport { createMuxClient, validateCredentials } from \"../lib/client-factory\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport type { EmbeddingModelIdByProvider, SupportedEmbeddingProvider } from \"../lib/providers\";\nimport { resolveEmbeddingModel } from \"../lib/providers\";\nimport { withRetry } from \"../lib/retry\";\nimport { resolveSigningContext } from \"../lib/url-signing\";\nimport { chunkText, chunkVTTCues } from \"../primitives/text-chunking\";\nimport { fetchTranscriptForAsset, getReadyTextTracks, parseVTTCues } from \"../primitives/transcripts\";\nimport type {\n ChunkEmbedding,\n ChunkingStrategy,\n MuxAIOptions,\n TextChunk,\n VideoEmbeddingsResult,\n} from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Configuration accepted by `generateVideoEmbeddings`. */\nexport interface EmbeddingsOptions extends MuxAIOptions {\n /** AI provider used to generate embeddings (defaults to 'openai'). */\n provider?: SupportedEmbeddingProvider;\n /** Provider-specific model identifier (defaults to text-embedding-3-small for OpenAI). */\n model?: EmbeddingModelIdByProvider[SupportedEmbeddingProvider];\n /** Language code for transcript selection (defaults to first available). */\n languageCode?: string;\n /** Chunking strategy configuration (defaults to token-based with 500 tokens, 100 overlap). */\n chunkingStrategy?: ChunkingStrategy;\n /** Maximum number of chunks to process concurrently (defaults to 5). */\n batchSize?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PROVIDER = \"openai\";\nconst DEFAULT_CHUNKING_STRATEGY: ChunkingStrategy = {\n type: \"token\",\n maxTokens: 500,\n overlap: 100,\n};\nconst DEFAULT_BATCH_SIZE = 5;\n\n/**\n * Averages multiple embedding vectors into a single vector.\n *\n * @param embeddings - Array of embedding vectors to average\n * @returns Single averaged embedding vector\n */\nfunction averageEmbeddings(embeddings: number[][]): number[] {\n if (embeddings.length === 0) {\n return [];\n }\n\n const dimensions = embeddings[0].length;\n const averaged = Array.from({ length: dimensions }, () => 0);\n\n for (const embedding of embeddings) {\n for (let i = 0; i < dimensions; i++) {\n averaged[i] += embedding[i];\n }\n }\n\n for (let i = 0; i < dimensions; i++) {\n averaged[i] /= embeddings.length;\n }\n\n return averaged;\n}\n\n/**\n * Generates embeddings for chunks of a video transcript in batches.\n *\n * @param chunks - Text chunks to embed\n * @param model - AI model to use for embedding generation\n * @param batchSize - Number of chunks to process concurrently\n * @param abortSignal - Optional abort signal\n * @returns Array of chunk embeddings\n */\nasync function generateChunkEmbeddings(\n chunks: TextChunk[],\n model: any,\n batchSize: number,\n abortSignal?: AbortSignal,\n): Promise<ChunkEmbedding[]> {\n const results: ChunkEmbedding[] = [];\n\n // Process chunks in batches\n for (let i = 0; i < chunks.length; i += batchSize) {\n const batch = chunks.slice(i, i + batchSize);\n\n const batchResults = await Promise.all(\n batch.map(async (chunk) => {\n const response = await withRetry(() =>\n embed({\n model,\n value: chunk.text,\n abortSignal,\n }),\n );\n\n return {\n chunkId: chunk.id,\n embedding: response.embedding,\n metadata: {\n startTime: chunk.startTime,\n endTime: chunk.endTime,\n tokenCount: chunk.tokenCount,\n },\n };\n }),\n );\n\n results.push(...batchResults);\n }\n\n return results;\n}\n\n/**\n * Generates vector embeddings for a video asset's transcript.\n *\n * This function:\n * 1. Fetches the video transcript from Mux\n * 2. Chunks the transcript according to the specified strategy\n * 3. Generates embeddings for each chunk using the specified AI provider\n * 4. Returns both individual chunk embeddings and an averaged embedding\n *\n * @param assetId - Mux asset ID\n * @param options - Configuration options\n * @returns Video embeddings result with chunks and averaged embedding\n *\n * @example\n * ```typescript\n * const embeddings = await generateVideoEmbeddings(\"asset-id\", {\n * provider: \"openai\",\n * chunkingStrategy: { type: \"token\", maxTokens: 500, overlap: 100 },\n * });\n *\n * // Store in vector database\n * for (const chunk of embeddings.chunks) {\n * await db.insert({\n * assetId: embeddings.assetId,\n * chunkId: chunk.chunkId,\n * embedding: chunk.embedding,\n * metadata: chunk.metadata,\n * });\n * }\n * ```\n */\nexport async function generateVideoEmbeddings(\n assetId: string,\n options: EmbeddingsOptions = {},\n): Promise<VideoEmbeddingsResult> {\n const {\n provider = DEFAULT_PROVIDER,\n model,\n languageCode,\n chunkingStrategy = DEFAULT_CHUNKING_STRATEGY,\n batchSize = DEFAULT_BATCH_SIZE,\n abortSignal,\n } = options;\n\n // Validate credentials and initialize Mux client\n const credentials = validateCredentials(options, provider === \"google\" ? \"google\" : \"openai\");\n const muxClient = createMuxClient(credentials);\n const embeddingModel = resolveEmbeddingModel({ ...options, provider, model });\n\n // Fetch asset and playback ID\n const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(\n muxClient,\n assetId,\n );\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n // Fetch transcript (raw VTT for VTT strategy, cleaned text otherwise)\n const useVttChunking = chunkingStrategy.type === \"vtt\";\n const transcriptResult = await fetchTranscriptForAsset(assetData, playbackId, {\n languageCode,\n cleanTranscript: !useVttChunking,\n signingContext: policy === \"signed\" ? signingContext : undefined,\n });\n\n if (!transcriptResult.track || !transcriptResult.transcriptText) {\n const availableLanguages = getReadyTextTracks(assetData)\n .map(t => t.language_code)\n .filter(Boolean)\n .join(\", \");\n throw new Error(\n `No caption track found${languageCode ? ` for language '${languageCode}'` : \"\"}. Available languages: ${availableLanguages || \"none\"}`,\n );\n }\n\n const transcriptText = transcriptResult.transcriptText;\n if (!transcriptText.trim()) {\n throw new Error(\"Transcript is empty\");\n }\n\n // Chunk the transcript\n const chunks = useVttChunking ?\n chunkVTTCues(\n parseVTTCues(transcriptText),\n chunkingStrategy.maxTokens,\n chunkingStrategy.overlapCues,\n ) :\n chunkText(transcriptText, chunkingStrategy);\n if (chunks.length === 0) {\n throw new Error(\"No chunks generated from transcript\");\n }\n\n // Generate embeddings for all chunks\n let chunkEmbeddings: ChunkEmbedding[];\n try {\n chunkEmbeddings = await generateChunkEmbeddings(\n chunks,\n embeddingModel.model,\n batchSize,\n abortSignal,\n );\n } catch (error) {\n throw new Error(\n `Failed to generate embeddings with ${provider}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n if (chunkEmbeddings.length === 0) {\n throw new Error(\"No embeddings generated\");\n }\n\n // Calculate averaged embedding\n const averagedEmbedding = averageEmbeddings(chunkEmbeddings.map(ce => ce.embedding));\n\n // Calculate total tokens\n const totalTokens = chunks.reduce((sum, chunk) => sum + chunk.tokenCount, 0);\n\n return {\n assetId,\n chunks: chunkEmbeddings,\n averagedEmbedding,\n provider,\n model: embeddingModel.modelId,\n metadata: {\n totalChunks: chunks.length,\n totalTokens,\n chunkingStrategy: JSON.stringify(chunkingStrategy),\n embeddingDimensions: chunkEmbeddings[0].embedding.length,\n generatedAt: new Date().toISOString(),\n },\n };\n}\n","import env from \"../env\";\nimport { createMuxClient, validateCredentials } from \"../lib/client-factory\";\nimport type { ImageDownloadOptions } from \"../lib/image-download\";\nimport { downloadImagesAsBase64 } from \"../lib/image-download\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport { resolveSigningContext } from \"../lib/url-signing\";\nimport { getThumbnailUrls } from \"../primitives/thumbnails\";\nimport type { ImageSubmissionMode, MuxAIOptions } from \"../types\";\n\nimport type { Buffer } from \"node:buffer\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Per-thumbnail moderation result returned from `getModerationScores`. */\nexport interface ThumbnailModerationScore {\n url: string;\n sexual: number;\n violence: number;\n error: boolean;\n}\n\n/** Aggregated moderation payload returned from `getModerationScores`. */\nexport interface ModerationResult {\n assetId: string;\n thumbnailScores: ThumbnailModerationScore[];\n maxScores: {\n sexual: number;\n violence: number;\n };\n exceedsThreshold: boolean;\n thresholds: {\n sexual: number;\n violence: number;\n };\n}\n\n/** Provider list accepted by `getModerationScores`. */\nexport type ModerationProvider = \"openai\" | \"hive\";\n\nexport type HiveModerationSource =\n | { kind: \"url\"; value: string } |\n { kind: \"file\"; buffer: Buffer; contentType: string };\n\nexport interface HiveModerationOutput {\n classes?: Array<{\n class: string;\n score: number;\n }>;\n}\n\n/** Configuration accepted by `getModerationScores`. */\nexport interface ModerationOptions extends MuxAIOptions {\n /** Provider used for moderation (defaults to 'openai'). */\n provider?: ModerationProvider;\n /** OpenAI moderation model identifier (defaults to 'omni-moderation-latest'). */\n model?: string;\n /** Override the default sexual/violence thresholds (0-1). */\n thresholds?: {\n sexual?: number;\n violence?: number;\n };\n /** Interval between storyboard thumbnails in seconds (defaults to 10). */\n thumbnailInterval?: number;\n /** Width of storyboard thumbnails in pixels (defaults to 640). */\n thumbnailWidth?: number;\n /** Max concurrent moderation requests (defaults to 5). */\n maxConcurrent?: number;\n /** Transport used for thumbnails (defaults to 'url'). */\n imageSubmissionMode?: ImageSubmissionMode;\n /** Download tuning used when `imageSubmissionMode` === 'base64'. */\n imageDownloadOptions?: ImageDownloadOptions;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_THRESHOLDS = {\n sexual: 0.7,\n violence: 0.8,\n};\n\nconst DEFAULT_PROVIDER = \"openai\";\n\nconst HIVE_ENDPOINT = \"https://api.thehive.ai/api/v2/task/sync\";\nconst HIVE_SEXUAL_CATEGORIES = [\n \"general_nsfw\",\n \"general_suggestive\",\n \"yes_sexual_activity\",\n \"female_underwear\",\n \"male_underwear\",\n \"bra\",\n \"panties\",\n \"sex_toys\",\n \"nudity_female\",\n \"nudity_male\",\n \"cleavage\",\n \"swimwear\",\n];\n\nconst HIVE_VIOLENCE_CATEGORIES = [\n \"gun_in_hand\",\n \"gun_not_in_hand\",\n \"animated_gun\",\n \"knife_in_hand\",\n \"knife_not_in_hand\",\n \"culinary_knife_not_in_hand\",\n \"culinary_knife_in_hand\",\n \"very_bloody\",\n \"a_little_bloody\",\n \"other_blood\",\n \"hanging\",\n \"noose\",\n \"human_corpse\",\n \"animated_corpse\",\n \"emaciated_body\",\n \"self_harm\",\n \"animal_abuse\",\n \"fights\",\n \"garm_death_injury_or_military_conflict\",\n];\n\nasync function processConcurrently<T>(\n items: any[],\n processor: (item: any) => Promise<T>,\n maxConcurrent: number = 5,\n): Promise<T[]> {\n const results: T[] = [];\n\n for (let i = 0; i < items.length; i += maxConcurrent) {\n const batch = items.slice(i, i + maxConcurrent);\n const batchPromises = batch.map(processor);\n const batchResults = await Promise.all(batchPromises);\n results.push(...batchResults);\n }\n\n return results;\n}\n\nasync function requestOpenAIModeration(\n imageUrls: string[],\n apiKey: string,\n model: string,\n maxConcurrent: number = 5,\n submissionMode: \"url\" | \"base64\" = \"url\",\n downloadOptions?: ImageDownloadOptions,\n): Promise<ThumbnailModerationScore[]> {\n const targetUrls =\n submissionMode === \"base64\" ?\n (await downloadImagesAsBase64(imageUrls, downloadOptions, maxConcurrent)).map(\n img => ({ url: img.url, image: img.base64Data }),\n ) :\n imageUrls.map(url => ({ url, image: url }));\n\n const moderate = async (entry: { url: string; image: string }): Promise<ThumbnailModerationScore> => {\n try {\n const res = await fetch(\"https://api.openai.com/v1/moderations\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n input: [\n {\n type: \"image_url\",\n image_url: {\n url: entry.image,\n },\n },\n ],\n }),\n });\n\n const json: any = await res.json();\n if (!res.ok) {\n throw new Error(\n `OpenAI moderation error: ${res.status} ${res.statusText} - ${JSON.stringify(json)}`,\n );\n }\n\n const categoryScores = json.results?.[0]?.category_scores || {};\n\n return {\n url: entry.url,\n sexual: categoryScores.sexual || 0,\n violence: categoryScores.violence || 0,\n error: false,\n };\n } catch (error) {\n console.error(\"OpenAI moderation failed:\", error);\n return {\n url: entry.url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(targetUrls, moderate, maxConcurrent);\n}\n\nfunction getHiveCategoryScores(\n classes: NonNullable<HiveModerationOutput[\"classes\"]>,\n categoryNames: string[],\n): number {\n const scoreMap = Object.fromEntries(\n classes.map(c => [c.class, c.score]),\n );\n const scores = categoryNames.map(category => scoreMap[category] || 0);\n return Math.max(...scores, 0);\n}\n\nasync function requestHiveModeration(\n imageUrls: string[],\n apiKey: string,\n maxConcurrent: number = 5,\n submissionMode: \"url\" | \"base64\" = \"url\",\n downloadOptions?: ImageDownloadOptions,\n): Promise<ThumbnailModerationScore[]> {\n const targets: Array<{ url: string; source: HiveModerationSource }> =\n submissionMode === \"base64\" ?\n (await downloadImagesAsBase64(imageUrls, downloadOptions, maxConcurrent)).map(img => ({\n url: img.url,\n source: {\n kind: \"file\",\n buffer: img.buffer,\n contentType: img.contentType,\n },\n })) :\n imageUrls.map(url => ({\n url,\n source: { kind: \"url\", value: url },\n }));\n\n const moderate = async (entry: { url: string; source: HiveModerationSource }): Promise<ThumbnailModerationScore> => {\n try {\n const formData = new FormData();\n\n if (entry.source.kind === \"url\") {\n formData.append(\"url\", entry.source.value);\n } else {\n const extension = entry.source.contentType.split(\"/\")[1] || \"jpg\";\n const blob = new Blob([entry.source.buffer], {\n type: entry.source.contentType,\n });\n formData.append(\"media\", blob, `thumbnail.${extension}`);\n }\n\n const res = await fetch(HIVE_ENDPOINT, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n Authorization: `Token ${apiKey}`,\n },\n body: formData,\n });\n\n const json: any = await res.json().catch(() => undefined);\n if (!res.ok) {\n throw new Error(\n `Hive moderation error: ${res.status} ${res.statusText} - ${JSON.stringify(json)}`,\n );\n }\n\n // Extract scores from Hive response\n // Hive returns scores in status[0].response.output[0].classes as array of {class, score}\n const classes = json?.status?.[0]?.response?.output?.[0]?.classes || [];\n\n return {\n url: entry.url,\n sexual: getHiveCategoryScores(classes, HIVE_SEXUAL_CATEGORIES),\n violence: getHiveCategoryScores(classes, HIVE_VIOLENCE_CATEGORIES),\n error: false,\n };\n } catch (error) {\n console.error(\"Hive moderation failed:\", error);\n return {\n url: entry.url,\n sexual: 0,\n violence: 0,\n error: true,\n };\n }\n };\n\n return processConcurrently(targets, moderate, maxConcurrent);\n}\n\n/**\n * Moderate a Mux asset's thumbnails.\n * - provider 'openai' uses OpenAI's hosted moderation endpoint (requires OPENAI_API_KEY)\n */\nexport async function getModerationScores(\n assetId: string,\n options: ModerationOptions = {},\n): Promise<ModerationResult> {\n const {\n provider = DEFAULT_PROVIDER,\n model = provider === \"openai\" ? \"omni-moderation-latest\" : undefined,\n thresholds = DEFAULT_THRESHOLDS,\n thumbnailInterval = 10,\n thumbnailWidth = 640,\n maxConcurrent = 5,\n imageSubmissionMode = \"url\",\n imageDownloadOptions,\n } = options;\n\n const credentials = validateCredentials(options, provider === \"openai\" ? \"openai\" : undefined);\n const muxClient = createMuxClient(credentials);\n\n // Fetch asset data and playback ID from Mux via helper\n const { asset, playbackId, policy } = await getPlaybackIdForAsset(muxClient, assetId);\n const duration = asset.duration || 0;\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n // Generate thumbnail URLs (signed if needed)\n const thumbnailUrls = await getThumbnailUrls(playbackId, duration, {\n interval: thumbnailInterval,\n width: thumbnailWidth,\n signingContext: policy === \"signed\" ? signingContext : undefined,\n });\n\n let thumbnailScores: ThumbnailModerationScore[];\n\n if (provider === \"openai\") {\n const apiKey = credentials.openaiApiKey;\n if (!apiKey) {\n throw new Error(\"OpenAI API key is required for moderation. Set OPENAI_API_KEY or pass openaiApiKey.\");\n }\n\n thumbnailScores = await requestOpenAIModeration(\n thumbnailUrls,\n apiKey,\n model || \"omni-moderation-latest\",\n maxConcurrent,\n imageSubmissionMode,\n imageDownloadOptions,\n );\n } else if (provider === \"hive\") {\n const hiveApiKey = options.hiveApiKey || env.HIVE_API_KEY;\n if (!hiveApiKey) {\n throw new Error(\"Hive API key is required for moderation. Set HIVE_API_KEY or pass hiveApiKey.\");\n }\n\n thumbnailScores = await requestHiveModeration(\n thumbnailUrls,\n hiveApiKey,\n maxConcurrent,\n imageSubmissionMode,\n imageDownloadOptions,\n );\n } else {\n throw new Error(`Unsupported moderation provider: ${provider}`);\n }\n\n // Find highest scores across all thumbnails\n const maxSexual = Math.max(...thumbnailScores.map(s => s.sexual));\n const maxViolence = Math.max(...thumbnailScores.map(s => s.violence));\n\n const finalThresholds = { ...DEFAULT_THRESHOLDS, ...thresholds };\n\n return {\n assetId,\n thumbnailScores,\n maxScores: {\n sexual: maxSexual,\n violence: maxViolence,\n },\n exceedsThreshold: maxSexual > finalThresholds.sexual || maxViolence > finalThresholds.violence,\n thresholds: finalThresholds,\n };\n}\n","import { generateObject } from \"ai\";\nimport dedent from \"dedent\";\nimport { z } from \"zod\";\n\nimport { createWorkflowClients } from \"../lib/client-factory\";\nimport type { ImageDownloadOptions } from \"../lib/image-download\";\nimport { downloadImageAsBase64 } from \"../lib/image-download\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport type {\n PromptOverrides,\n} from \"../lib/prompt-builder\";\nimport {\n createPromptBuilder,\n createToneSection,\n createTranscriptSection,\n} from \"../lib/prompt-builder\";\nimport type { ModelIdByProvider, SupportedProvider } from \"../lib/providers\";\nimport { withRetry } from \"../lib/retry\";\nimport { resolveSigningContext } from \"../lib/url-signing\";\nimport { getStoryboardUrl } from \"../primitives/storyboards\";\nimport { fetchTranscriptForAsset } from \"../primitives/transcripts\";\nimport type { ImageSubmissionMode, MuxAIOptions, ToneType } from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const SUMMARY_KEYWORD_LIMIT = 10;\n\nexport const summarySchema = z.object({\n keywords: z.array(z.string()),\n title: z.string(),\n description: z.string(),\n});\n\nexport type SummaryType = z.infer<typeof summarySchema>;\n\n/** Structured return payload for `getSummaryAndTags`. */\nexport interface SummaryAndTagsResult {\n /** Asset ID passed into the workflow. */\n assetId: string;\n /** Short headline generated from the storyboard. */\n title: string;\n /** Longer description of the detected content. */\n description: string;\n /** Up to 10 keywords extracted by the model. */\n tags: string[];\n /** Storyboard image URL that was analyzed. */\n storyboardUrl: string;\n}\n\n/**\n * Sections of the summarization user prompt that can be overridden.\n * Use these to customize the AI's behavior for your specific use case.\n */\nexport type SummarizationPromptSections =\n | \"task\" |\n \"title\" |\n \"description\" |\n \"keywords\" |\n \"qualityGuidelines\";\n\n/**\n * Override specific sections of the summarization prompt.\n * Each key corresponds to a section that can be customized.\n *\n * @example\n * ```typescript\n * const result = await getSummaryAndTags(assetId, {\n * promptOverrides: {\n * task: 'Generate SEO-optimized metadata for this product video.',\n * title: 'Create a click-worthy title under 60 characters for YouTube.',\n * },\n * });\n * ```\n */\nexport type SummarizationPromptOverrides = PromptOverrides<SummarizationPromptSections>;\n\n/** Configuration accepted by `getSummaryAndTags`. */\nexport interface SummarizationOptions extends MuxAIOptions {\n /** AI provider to run (defaults to 'openai'). */\n provider?: SupportedProvider;\n /** Provider-specific chat model identifier. */\n model?: ModelIdByProvider[SupportedProvider];\n /** Prompt tone shim applied to the system instruction (defaults to 'normal'). */\n tone?: ToneType;\n /** Fetch the transcript and send it alongside the storyboard (defaults to true). */\n includeTranscript?: boolean;\n /** Strip timestamps/markup from transcripts before including them (defaults to true). */\n cleanTranscript?: boolean;\n /** How storyboard frames should be delivered to the provider (defaults to 'url'). */\n imageSubmissionMode?: ImageSubmissionMode;\n /** Fine-tune storyboard downloads when `imageSubmissionMode` === 'base64'. */\n imageDownloadOptions?: ImageDownloadOptions;\n /**\n * Override specific sections of the user prompt.\n * Useful for customizing the AI's output for specific use cases (SEO, social media, etc.)\n */\n promptOverrides?: SummarizationPromptOverrides;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Prompts\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst TONE_INSTRUCTIONS: Record<ToneType, string> = {\n normal: \"Provide a clear, straightforward analysis.\",\n sassy: \"Answer with a sassy, playful attitude and personality.\",\n professional: \"Provide a professional, executive-level analysis suitable for business reporting.\",\n};\n\n/**\n * Prompt builder for the summarization user prompt.\n * Sections can be individually overridden via `promptOverrides` in SummarizationOptions.\n */\nconst summarizationPromptBuilder = createPromptBuilder<SummarizationPromptSections>({\n template: {\n task: {\n tag: \"task\",\n content: \"Analyze the storyboard frames and generate metadata that captures the essence of the video content.\",\n },\n title: {\n tag: \"title_requirements\",\n content: dedent`\n A short, compelling headline that immediately communicates the subject or action.\n Aim for brevity - typically under 10 words. Think of how a news headline or video card title would read.\n Start with the primary subject, action, or topic - never begin with \"A video of\" or similar phrasing.\n Use active, specific language.`,\n },\n description: {\n tag: \"description_requirements\",\n content: dedent`\n A concise summary (2-4 sentences) that describes what happens across the video.\n Cover the main subjects, actions, setting, and any notable progression visible across frames.\n Write in present tense. Be specific about observable details rather than making assumptions.\n If the transcript provides dialogue or narration, incorporate key points but prioritize visual content.`,\n },\n keywords: {\n tag: \"keywords_requirements\",\n content: dedent`\n Specific, searchable terms (up to 10) that capture:\n - Primary subjects (people, animals, objects)\n - Actions and activities being performed\n - Setting and environment\n - Notable objects or tools\n - Style or genre (if applicable)\n Prefer concrete nouns and action verbs over abstract concepts.\n Use lowercase. Avoid redundant or overly generic terms like \"video\" or \"content\".`,\n },\n qualityGuidelines: {\n tag: \"quality_guidelines\",\n content: dedent`\n - Examine all frames to understand the full context and progression\n - Be precise: \"golden retriever\" is better than \"dog\" when identifiable\n - Capture the narrative: what begins, develops, and concludes\n - Balance brevity with informativeness`,\n },\n },\n sectionOrder: [\"task\", \"title\", \"description\", \"keywords\", \"qualityGuidelines\"],\n});\n\nconst SYSTEM_PROMPT = dedent`\n <role>\n You are a video content analyst specializing in storyboard interpretation and multimodal analysis.\n </role>\n\n <context>\n You receive storyboard images containing multiple sequential frames extracted from a video.\n These frames are arranged in a grid and represent the visual progression of the content over time.\n Read frames left-to-right, top-to-bottom to understand the temporal sequence.\n </context>\n\n <transcript_guidance>\n When a transcript is provided alongside the storyboard:\n - Use it to understand spoken content, dialogue, narration, and audio context\n - Correlate transcript content with visual frames to build a complete picture\n - Extract key terminology, names, and specific language used by speakers\n - Let the transcript inform keyword selection, especially for topics not visually obvious\n - Prioritize visual content for the description, but enrich it with transcript insights\n - If transcript and visuals conflict, trust the visual evidence\n </transcript_guidance>\n\n <capabilities>\n - Extract meaning from visual sequences\n - Identify subjects, actions, settings, and narrative arcs\n - Generate accurate, searchable metadata\n - Synthesize visual and transcript information when provided\n </capabilities>\n\n <constraints>\n - Only describe what is clearly observable in the frames or explicitly stated in the transcript\n - Do not fabricate details or make unsupported assumptions\n - Return structured data matching the requested schema\n </constraints>`;\n\ninterface UserPromptContext {\n tone: ToneType;\n transcriptText?: string;\n isCleanTranscript?: boolean;\n promptOverrides?: SummarizationPromptOverrides;\n}\n\nfunction buildUserPrompt({\n tone,\n transcriptText,\n isCleanTranscript = true,\n promptOverrides,\n}: UserPromptContext): string {\n // Build dynamic context sections\n const contextSections = [createToneSection(TONE_INSTRUCTIONS[tone])];\n\n if (transcriptText) {\n const format = isCleanTranscript ? \"plain text\" : \"WebVTT\";\n contextSections.push(createTranscriptSection(transcriptText, format));\n }\n\n return summarizationPromptBuilder.buildWithContext(promptOverrides, contextSections);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PROVIDER = \"openai\";\nconst DEFAULT_TONE = \"normal\";\n\nfunction normalizeKeywords(keywords?: string[]): string[] {\n if (!Array.isArray(keywords) || keywords.length === 0) {\n return [];\n }\n\n const uniqueLowercase = new Set<string>();\n const normalized: string[] = [];\n\n for (const keyword of keywords) {\n const trimmed = keyword?.trim();\n if (!trimmed) {\n continue;\n }\n\n const lower = trimmed.toLowerCase();\n if (uniqueLowercase.has(lower)) {\n continue;\n }\n\n uniqueLowercase.add(lower);\n normalized.push(trimmed);\n\n if (normalized.length === SUMMARY_KEYWORD_LIMIT) {\n break;\n }\n }\n\n return normalized;\n}\n\nexport async function getSummaryAndTags(\n assetId: string,\n options?: SummarizationOptions,\n): Promise<SummaryAndTagsResult> {\n const {\n provider = DEFAULT_PROVIDER,\n model,\n tone = DEFAULT_TONE,\n includeTranscript = true,\n cleanTranscript = true,\n imageSubmissionMode = \"url\",\n imageDownloadOptions,\n abortSignal,\n promptOverrides,\n } = options ?? {};\n\n // Initialize clients with validated credentials and resolved language model\n const clients = createWorkflowClients(\n { ...options, model },\n provider as SupportedProvider,\n );\n\n // Fetch asset data from Mux and grab playback/transcript details\n const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(clients.mux, assetId);\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options ?? {});\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n const transcriptText =\n includeTranscript ?\n (await fetchTranscriptForAsset(assetData, playbackId, {\n cleanTranscript,\n signingContext: policy === \"signed\" ? signingContext : undefined,\n })).transcriptText :\n \"\";\n\n // Build the user prompt with all context and any overrides\n const userPrompt = buildUserPrompt({\n tone,\n transcriptText,\n isCleanTranscript: cleanTranscript,\n promptOverrides,\n });\n\n // Analyze storyboard with AI provider (signed if needed)\n const imageUrl = await getStoryboardUrl(playbackId, 640, policy === \"signed\" ? signingContext : undefined);\n\n const analyzeStoryboard = async (imageDataUrl: string) => {\n const response = await generateObject({\n model: clients.languageModel.model,\n schema: summarySchema,\n abortSignal,\n messages: [\n {\n role: \"system\",\n content: SYSTEM_PROMPT,\n },\n {\n role: \"user\",\n content: [\n { type: \"text\", text: userPrompt },\n { type: \"image\", image: imageDataUrl },\n ],\n },\n ],\n });\n\n return response.object;\n };\n\n let aiAnalysis: { title?: string; description?: string; keywords?: string[] } | null = null;\n\n try {\n if (imageSubmissionMode === \"base64\") {\n const downloadResult = await downloadImageAsBase64(imageUrl, imageDownloadOptions);\n aiAnalysis = await analyzeStoryboard(downloadResult.base64Data);\n } else {\n // URL-based submission with retry logic\n aiAnalysis = await withRetry(() => analyzeStoryboard(imageUrl));\n }\n } catch (error: unknown) {\n throw new Error(\n `Failed to analyze video content with ${provider}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n }\n\n if (!aiAnalysis) {\n throw new Error(`Failed to analyze video content for asset ${assetId}`);\n }\n\n if (!aiAnalysis.title) {\n throw new Error(`Failed to generate title for asset ${assetId}`);\n }\n\n if (!aiAnalysis.description) {\n throw new Error(`Failed to generate description for asset ${assetId}`);\n }\n\n return {\n assetId,\n title: aiAnalysis.title,\n description: aiAnalysis.description,\n tags: normalizeKeywords(aiAnalysis.keywords),\n storyboardUrl: imageUrl,\n };\n}\n","import { GetObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport Mux from \"@mux/mux-node\";\n\nimport env from \"../env\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport { resolveSigningContext, signUrl } from \"../lib/url-signing\";\nimport type { MuxAIOptions } from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Output returned from `translateAudio`. */\nexport interface AudioTranslationResult {\n assetId: string;\n targetLanguageCode: string;\n dubbingId: string;\n uploadedTrackId?: string;\n presignedUrl?: string;\n}\n\n/** Configuration accepted by `translateAudio`. */\nexport interface AudioTranslationOptions extends MuxAIOptions {\n /** Audio dubbing provider (currently ElevenLabs only). */\n provider?: \"elevenlabs\";\n /** Number of speakers supplied to ElevenLabs (0 = auto-detect, default). */\n numSpeakers?: number;\n /** Optional override for the S3-compatible endpoint used for uploads. */\n s3Endpoint?: string;\n /** S3 region (defaults to env.S3_REGION or 'auto'). */\n s3Region?: string;\n /** Bucket that will store dubbed audio files. */\n s3Bucket?: string;\n /** Access key ID used for uploads. */\n s3AccessKeyId?: string;\n /** Secret access key used for uploads. */\n s3SecretAccessKey?: string;\n /**\n * When true (default) the dubbed audio file is uploaded to the configured\n * bucket and attached to the Mux asset.\n */\n uploadToMux?: boolean;\n /** Override for env.ELEVENLABS_API_KEY. */\n elevenLabsApiKey?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst STATIC_RENDITION_POLL_INTERVAL_MS = 5000;\nconst STATIC_RENDITION_MAX_ATTEMPTS = 36; // ~3 minutes\n\nconst delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\n\nfunction getReadyAudioStaticRendition(asset: any) {\n const files = asset.static_renditions?.files as any[] | undefined;\n if (!files || files.length === 0) {\n return undefined;\n }\n\n return files.find(\n rendition => rendition.name === \"audio.m4a\" && rendition.status === \"ready\",\n );\n}\n\nconst hasReadyAudioStaticRendition = (asset: any) => Boolean(getReadyAudioStaticRendition(asset));\n\nasync function requestStaticRenditionCreation(muxClient: Mux, assetId: string) {\n console.log(\"📼 Requesting static rendition from Mux...\");\n try {\n await muxClient.video.assets.createStaticRendition(assetId, {\n resolution: \"audio-only\",\n });\n console.log(\"📼 Static rendition request accepted by Mux.\");\n } catch (error: any) {\n const statusCode = error?.status ?? error?.statusCode;\n const messages: string[] | undefined = error?.error?.messages;\n const alreadyDefined =\n messages?.some(message => message.toLowerCase().includes(\"already defined\")) ??\n error?.message?.toLowerCase().includes(\"already defined\");\n\n if (statusCode === 409 || alreadyDefined) {\n console.log(\"ℹ️ Static rendition already requested. Waiting for it to finish...\");\n return;\n }\n\n const message = error instanceof Error ? error.message : \"Unknown error\";\n throw new Error(`Failed to request static rendition from Mux: ${message}`);\n }\n}\n\nasync function waitForAudioStaticRendition({\n assetId,\n muxClient,\n initialAsset,\n}: {\n assetId: string;\n muxClient: any;\n initialAsset: any;\n}): Promise<any> {\n let currentAsset = initialAsset;\n\n if (hasReadyAudioStaticRendition(currentAsset)) {\n return currentAsset;\n }\n\n const status = currentAsset.static_renditions?.status ?? \"not_requested\";\n\n if (status === \"not_requested\" || status === undefined) {\n await requestStaticRenditionCreation(muxClient, assetId);\n } else if (status === \"errored\") {\n console.log(\"⚠️ Previous static rendition request errored. Creating a new one...\");\n await requestStaticRenditionCreation(muxClient, assetId);\n } else {\n console.log(`ℹ️ Static rendition already ${status}. Waiting for it to finish...`);\n }\n\n for (let attempt = 1; attempt <= STATIC_RENDITION_MAX_ATTEMPTS; attempt++) {\n await delay(STATIC_RENDITION_POLL_INTERVAL_MS);\n currentAsset = await muxClient.video.assets.retrieve(assetId);\n\n if (hasReadyAudioStaticRendition(currentAsset)) {\n console.log(\"✅ Audio static rendition is ready!\");\n return currentAsset;\n }\n\n const currentStatus = currentAsset.static_renditions?.status || \"unknown\";\n console.log(\n `⌛ Waiting for static rendition (attempt ${attempt}/${STATIC_RENDITION_MAX_ATTEMPTS}) → ${currentStatus}`,\n );\n\n if (currentStatus === \"errored\") {\n throw new Error(\n \"Mux failed to create the static rendition for this asset. Please check the asset in the Mux dashboard.\",\n );\n }\n }\n\n throw new Error(\n \"Timed out waiting for the static rendition to become ready. Please try again in a moment.\",\n );\n}\n\nexport async function translateAudio(\n assetId: string,\n toLanguageCode: string,\n options: AudioTranslationOptions = {},\n): Promise<AudioTranslationResult> {\n // Uses the default audio track on your asset, language is auto-detected by ElevenLabs\n const {\n provider = \"elevenlabs\",\n numSpeakers = 0, // 0 = auto-detect\n muxTokenId,\n muxTokenSecret,\n elevenLabsApiKey,\n uploadToMux = true,\n } = options;\n\n if (provider !== \"elevenlabs\") {\n throw new Error(\"Only ElevenLabs provider is currently supported for audio translation\");\n }\n\n // Validate required credentials\n const muxId = muxTokenId ?? env.MUX_TOKEN_ID;\n const muxSecret = muxTokenSecret ?? env.MUX_TOKEN_SECRET;\n const elevenLabsKey = elevenLabsApiKey ?? env.ELEVENLABS_API_KEY;\n\n // S3 configuration\n const s3Endpoint = options.s3Endpoint ?? env.S3_ENDPOINT;\n const s3Region = options.s3Region ?? env.S3_REGION ?? \"auto\";\n const s3Bucket = options.s3Bucket ?? env.S3_BUCKET;\n const s3AccessKeyId = options.s3AccessKeyId ?? env.S3_ACCESS_KEY_ID;\n const s3SecretAccessKey = options.s3SecretAccessKey ?? env.S3_SECRET_ACCESS_KEY;\n\n if (!muxId || !muxSecret) {\n throw new Error(\"Mux credentials are required. Provide muxTokenId and muxTokenSecret in options or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables.\");\n }\n\n if (!elevenLabsKey) {\n throw new Error(\"ElevenLabs API key is required. Provide elevenLabsApiKey in options or set ELEVENLABS_API_KEY environment variable.\");\n }\n\n if (uploadToMux && (!s3Endpoint || !s3Bucket || !s3AccessKeyId || !s3SecretAccessKey)) {\n throw new Error(\"S3 configuration is required for uploading to Mux. Provide s3Endpoint, s3Bucket, s3AccessKeyId, and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.\");\n }\n\n // Initialize clients\n const mux = new Mux({\n tokenId: muxId,\n tokenSecret: muxSecret,\n });\n\n // Fetch asset data and playback ID from Mux\n console.log(`🎬 Fetching Mux asset: ${assetId}`);\n const { asset: initialAsset, playbackId, policy } = await getPlaybackIdForAsset(mux, assetId);\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n // Check for audio-only static rendition\n console.log(\"🔍 Checking for audio-only static rendition...\");\n\n let currentAsset = initialAsset;\n if (!hasReadyAudioStaticRendition(currentAsset)) {\n console.log(\"❌ No ready audio static rendition found. Requesting one now...\");\n currentAsset = await waitForAudioStaticRendition({\n assetId,\n muxClient: mux,\n initialAsset: currentAsset,\n });\n }\n\n const audioRendition = getReadyAudioStaticRendition(currentAsset);\n\n if (!audioRendition) {\n throw new Error(\n \"Unable to obtain an audio-only static rendition for this asset. Please verify static renditions are enabled in Mux.\",\n );\n }\n\n // Build audio URL (signed if needed)\n let audioUrl = `https://stream.mux.com/${playbackId}/audio.m4a`;\n if (policy === \"signed\" && signingContext) {\n audioUrl = await signUrl(audioUrl, playbackId, signingContext, \"video\");\n }\n console.log(`✅ Found audio rendition: ${audioUrl}`);\n\n // Create dubbing job in ElevenLabs\n console.log(`🎙️ Creating ElevenLabs dubbing job (auto-detect → ${toLanguageCode})`);\n\n let dubbingId: string;\n\n try {\n // Fetch audio file and create dubbing job\n const audioResponse = await fetch(audioUrl);\n if (!audioResponse.ok) {\n throw new Error(`Failed to fetch audio file: ${audioResponse.statusText}`);\n }\n\n const audioBuffer = await audioResponse.arrayBuffer();\n const audioBlob = new Blob([audioBuffer], { type: \"audio/mp4\" });\n const audioFile = audioBlob as any; // ElevenLabs accepts Blob\n\n // Create dubbing job using direct HTTP request\n const formData = new FormData();\n formData.append(\"file\", audioFile);\n formData.append(\"target_lang\", toLanguageCode);\n // Note: source_lang is omitted to enable automatic language detection\n formData.append(\"num_speakers\", numSpeakers.toString());\n formData.append(\"name\", `Mux Asset ${assetId} - auto to ${toLanguageCode}`);\n\n const dubbingResponse = await fetch(\"https://api.elevenlabs.io/v1/dubbing\", {\n method: \"POST\",\n headers: {\n \"xi-api-key\": elevenLabsKey!,\n },\n body: formData,\n });\n\n if (!dubbingResponse.ok) {\n throw new Error(`ElevenLabs API error: ${dubbingResponse.statusText}`);\n }\n\n const dubbingData = await dubbingResponse.json() as any;\n\n dubbingId = dubbingData.dubbing_id;\n console.log(`✅ Dubbing job created: ${dubbingId}`);\n console.log(`⏱️ Expected duration: ${dubbingData.expected_duration_sec}s`);\n } catch (error) {\n throw new Error(`Failed to create ElevenLabs dubbing job: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n // Poll for completion\n console.log(\"⏳ Waiting for dubbing to complete...\");\n\n let dubbingStatus: string = \"dubbing\";\n let pollAttempts = 0;\n const maxPollAttempts = 180; // 30 minutes at 10s intervals\n\n while (dubbingStatus === \"dubbing\" && pollAttempts < maxPollAttempts) {\n await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds\n pollAttempts++;\n\n try {\n const statusResponse = await fetch(`https://api.elevenlabs.io/v1/dubbing/${dubbingId}`, {\n headers: {\n \"xi-api-key\": elevenLabsKey!,\n },\n });\n\n if (!statusResponse.ok) {\n throw new Error(`Status check failed: ${statusResponse.statusText}`);\n }\n\n const statusData = await statusResponse.json() as any;\n dubbingStatus = statusData.status;\n\n console.log(`📊 Status check ${pollAttempts}: ${dubbingStatus}`);\n\n if (dubbingStatus === \"failed\") {\n throw new Error(\"ElevenLabs dubbing job failed\");\n }\n } catch (error) {\n throw new Error(`Failed to check dubbing status: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n }\n\n if (dubbingStatus !== \"dubbed\") {\n throw new Error(`Dubbing job timed out or failed. Final status: ${dubbingStatus}`);\n }\n\n console.log(\"✅ Dubbing completed successfully!\");\n\n // If uploadToMux is false, just return the dubbing info\n if (!uploadToMux) {\n return {\n assetId,\n targetLanguageCode: toLanguageCode,\n dubbingId,\n };\n }\n\n // Download dubbed audio from ElevenLabs\n console.log(\"📥 Downloading dubbed audio from ElevenLabs...\");\n\n let dubbedAudioBuffer: ArrayBuffer;\n\n try {\n // Get dubbed audio using fetch (since the SDK method might not be available)\n const audioUrl = `https://api.elevenlabs.io/v1/dubbing/${dubbingId}/audio/${toLanguageCode}`;\n const audioResponse = await fetch(audioUrl, {\n headers: {\n \"xi-api-key\": elevenLabsKey!,\n },\n });\n\n if (!audioResponse.ok) {\n throw new Error(`Failed to fetch dubbed audio: ${audioResponse.statusText}`);\n }\n\n dubbedAudioBuffer = await audioResponse.arrayBuffer();\n console.log(`✅ Downloaded dubbed audio (${dubbedAudioBuffer.byteLength} bytes)`);\n } catch (error) {\n throw new Error(`Failed to download dubbed audio: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n // Upload to S3-compatible storage\n console.log(\"📤 Uploading dubbed audio to S3-compatible storage...\");\n\n const s3Client = new S3Client({\n region: s3Region,\n endpoint: s3Endpoint,\n credentials: {\n accessKeyId: s3AccessKeyId!,\n secretAccessKey: s3SecretAccessKey!,\n },\n forcePathStyle: true,\n });\n\n // Create unique key for the audio file\n const audioKey = `audio-translations/${assetId}/auto-to-${toLanguageCode}-${Date.now()}.m4a`;\n\n let presignedUrl: string;\n\n try {\n // Upload audio to S3\n const upload = new Upload({\n client: s3Client,\n params: {\n Bucket: s3Bucket!,\n Key: audioKey,\n Body: new Uint8Array(dubbedAudioBuffer),\n ContentType: \"audio/mp4\",\n },\n });\n\n await upload.done();\n console.log(`✅ Audio uploaded successfully to: ${audioKey}`);\n\n // Generate presigned URL (valid for 1 hour)\n const getObjectCommand = new GetObjectCommand({\n Bucket: s3Bucket!,\n Key: audioKey,\n });\n\n presignedUrl = await getSignedUrl(s3Client, getObjectCommand, {\n expiresIn: 3600, // 1 hour\n });\n\n console.log(`🔗 Generated presigned URL (expires in 1 hour)`);\n } catch (error) {\n throw new Error(`Failed to upload audio to S3: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n // Add translated audio track to Mux asset\n console.log(\"🎬 Adding translated audio track to Mux asset...\");\n\n let uploadedTrackId: string | undefined;\n\n try {\n const languageName = new Intl.DisplayNames([\"en\"], { type: \"language\" }).of(toLanguageCode) || toLanguageCode.toUpperCase();\n const trackName = `${languageName} (auto-dubbed)`;\n\n const trackResponse = await mux.video.assets.createTrack(assetId, {\n type: \"audio\",\n language_code: toLanguageCode,\n name: trackName,\n url: presignedUrl,\n });\n\n uploadedTrackId = trackResponse.id;\n console.log(`✅ Audio track added to Mux asset with ID: ${uploadedTrackId}`);\n console.log(`🎵 Track name: \"${trackName}\"`);\n } catch (error) {\n console.warn(`⚠️ Failed to add audio track to Mux asset: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n console.log(\"🔗 You can manually add the track using this presigned URL:\");\n console.log(presignedUrl);\n }\n\n return {\n assetId,\n targetLanguageCode: toLanguageCode,\n dubbingId,\n uploadedTrackId,\n presignedUrl,\n };\n}\n","import { GetObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport { generateObject } from \"ai\";\nimport { z } from \"zod\";\n\nimport env from \"../env\";\nimport { createWorkflowClients } from \"../lib/client-factory\";\nimport { getPlaybackIdForAsset } from \"../lib/mux-assets\";\nimport type { ModelIdByProvider, SupportedProvider } from \"../lib/providers\";\nimport { resolveSigningContext, signUrl } from \"../lib/url-signing\";\nimport type { MuxAIOptions } from \"../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Output returned from `translateCaptions`. */\nexport interface TranslationResult {\n assetId: string;\n sourceLanguageCode: string;\n targetLanguageCode: string;\n originalVtt: string;\n translatedVtt: string;\n uploadedTrackId?: string;\n presignedUrl?: string;\n}\n\n/** Configuration accepted by `translateCaptions`. */\nexport interface TranslationOptions<P extends SupportedProvider = SupportedProvider> extends MuxAIOptions {\n /** Provider responsible for the translation. */\n provider: P;\n /** Provider-specific chat model identifier. */\n model?: ModelIdByProvider[P];\n /** Optional override for the S3-compatible endpoint used for uploads. */\n s3Endpoint?: string;\n /** S3 region (defaults to env.S3_REGION or 'auto'). */\n s3Region?: string;\n /** Bucket that will store translated VTT files. */\n s3Bucket?: string;\n /** Access key ID used for uploads. */\n s3AccessKeyId?: string;\n /** Secret access key used for uploads. */\n s3SecretAccessKey?: string;\n /**\n * When true (default) the translated VTT is uploaded to the configured\n * bucket and attached to the Mux asset.\n */\n uploadToMux?: boolean;\n}\n\n/** Schema used when requesting caption translation from a language model. */\nexport const translationSchema = z.object({\n translation: z.string(),\n});\n\n/** Inferred shape returned by `translationSchema`. */\nexport type TranslationPayload = z.infer<typeof translationSchema>;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PROVIDER = \"openai\";\n\nexport async function translateCaptions<P extends SupportedProvider = SupportedProvider>(\n assetId: string,\n fromLanguageCode: string,\n toLanguageCode: string,\n options: TranslationOptions<P>,\n): Promise<TranslationResult> {\n const {\n provider = DEFAULT_PROVIDER,\n model,\n s3Endpoint: providedS3Endpoint,\n s3Region: providedS3Region,\n s3Bucket: providedS3Bucket,\n s3AccessKeyId: providedS3AccessKeyId,\n s3SecretAccessKey: providedS3SecretAccessKey,\n uploadToMux: uploadToMuxOption,\n ...clientConfig\n } = options;\n\n const resolvedProvider = provider;\n\n // S3 configuration\n const s3Endpoint = providedS3Endpoint ?? env.S3_ENDPOINT;\n const s3Region = providedS3Region ?? env.S3_REGION ?? \"auto\";\n const s3Bucket = providedS3Bucket ?? env.S3_BUCKET;\n const s3AccessKeyId = providedS3AccessKeyId ?? env.S3_ACCESS_KEY_ID;\n const s3SecretAccessKey = providedS3SecretAccessKey ?? env.S3_SECRET_ACCESS_KEY;\n const uploadToMux = uploadToMuxOption !== false; // Default to true\n\n const clients = createWorkflowClients(\n { ...clientConfig, provider: resolvedProvider, model },\n resolvedProvider,\n );\n\n if (uploadToMux && (!s3Endpoint || !s3Bucket || !s3AccessKeyId || !s3SecretAccessKey)) {\n throw new Error(\"S3 configuration is required for uploading to Mux. Provide s3Endpoint, s3Bucket, s3AccessKeyId, and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.\");\n }\n\n // Fetch asset data and playback ID from Mux\n const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(clients.mux, assetId);\n\n // Resolve signing context for signed playback IDs\n const signingContext = resolveSigningContext(options);\n if (policy === \"signed\" && !signingContext) {\n throw new Error(\n \"Signed playback ID requires signing credentials. \" +\n \"Provide muxSigningKey and muxPrivateKey in options or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables.\",\n );\n }\n\n // Find text track with the source language\n if (!assetData.tracks) {\n throw new Error(\"No tracks found for this asset\");\n }\n\n const sourceTextTrack = assetData.tracks.find(track =>\n track.type === \"text\" &&\n track.status === \"ready\" &&\n track.language_code === fromLanguageCode,\n );\n\n if (!sourceTextTrack) {\n throw new Error(`No ready text track found with language code '${fromLanguageCode}' for this asset`);\n }\n\n // Fetch the VTT file content (signed if needed)\n let vttUrl = `https://stream.mux.com/${playbackId}/text/${sourceTextTrack.id}.vtt`;\n if (policy === \"signed\" && signingContext) {\n vttUrl = await signUrl(vttUrl, playbackId, signingContext, \"video\");\n }\n let vttContent: string;\n\n try {\n const vttResponse = await fetch(vttUrl);\n if (!vttResponse.ok) {\n throw new Error(`Failed to fetch VTT file: ${vttResponse.statusText}`);\n }\n vttContent = await vttResponse.text();\n } catch (error) {\n throw new Error(`Failed to fetch VTT content: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n console.log(`✅ Found VTT content for language '${fromLanguageCode}'`);\n\n // Translate VTT content using configured provider via ai-sdk\n let translatedVtt: string;\n\n try {\n const response = await generateObject({\n model: clients.languageModel.model,\n schema: translationSchema,\n abortSignal: options.abortSignal,\n messages: [\n {\n role: \"user\",\n content: `Translate the following VTT subtitle file from ${fromLanguageCode} to ${toLanguageCode}. Preserve all timestamps and VTT formatting exactly as they appear. Return JSON with a single key \"translation\" containing the translated VTT.\\n\\n${vttContent}`,\n },\n ],\n });\n\n translatedVtt = response.object.translation;\n } catch (error) {\n throw new Error(`Failed to translate VTT with ${resolvedProvider}: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n console.log(`\\n✅ Translation completed successfully!`);\n\n // If uploadToMux is false, just return the translation\n if (!uploadToMux) {\n console.log(`✅ VTT translated to ${toLanguageCode} successfully!`);\n\n return {\n assetId,\n sourceLanguageCode: fromLanguageCode,\n targetLanguageCode: toLanguageCode,\n originalVtt: vttContent,\n translatedVtt,\n };\n }\n\n // Upload translated VTT to S3-compatible storage\n console.log(\"📤 Uploading translated VTT to S3-compatible storage...\");\n\n const s3Client = new S3Client({\n region: s3Region,\n endpoint: s3Endpoint,\n credentials: {\n accessKeyId: s3AccessKeyId!,\n secretAccessKey: s3SecretAccessKey!,\n },\n forcePathStyle: true, // Often needed for non-AWS S3 services\n });\n\n // Create unique key for the VTT file\n const vttKey = `translations/${assetId}/${fromLanguageCode}-to-${toLanguageCode}-${Date.now()}.vtt`;\n\n let presignedUrl: string;\n\n try {\n // Upload VTT to S3\n const upload = new Upload({\n client: s3Client,\n params: {\n Bucket: s3Bucket!,\n Key: vttKey,\n Body: translatedVtt,\n ContentType: \"text/vtt\",\n },\n });\n\n await upload.done();\n console.log(`✅ VTT uploaded successfully to: ${vttKey}`);\n\n // Generate presigned URL (valid for 1 hour)\n const getObjectCommand = new GetObjectCommand({\n Bucket: s3Bucket!,\n Key: vttKey,\n });\n\n presignedUrl = await getSignedUrl(s3Client, getObjectCommand, {\n expiresIn: 3600, // 1 hour\n });\n\n console.log(`🔗 Generated presigned URL (expires in 1 hour)`);\n } catch (error) {\n throw new Error(`Failed to upload VTT to S3: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n\n // Add translated track to Mux asset\n console.log(\"📹 Adding translated track to Mux asset...\");\n\n let uploadedTrackId: string | undefined;\n\n try {\n const languageName = new Intl.DisplayNames([\"en\"], { type: \"language\" }).of(toLanguageCode) || toLanguageCode.toUpperCase();\n const trackName = `${languageName} (auto-translated)`;\n\n const trackResponse = await clients.mux.video.assets.createTrack(assetId, {\n type: \"text\",\n text_type: \"subtitles\",\n language_code: toLanguageCode,\n name: trackName,\n url: presignedUrl,\n });\n\n uploadedTrackId = trackResponse.id;\n console.log(`✅ Track added to Mux asset with ID: ${uploadedTrackId}`);\n console.log(`📋 Track name: \"${trackName}\"`);\n } catch (error) {\n console.warn(`⚠️ Failed to add track to Mux asset: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n console.log(\"🔗 You can manually add the track using this presigned URL:\");\n console.log(presignedUrl);\n }\n\n return {\n assetId,\n sourceLanguageCode: fromLanguageCode,\n targetLanguageCode: toLanguageCode,\n originalVtt: vttContent,\n translatedVtt,\n uploadedTrackId,\n presignedUrl,\n };\n}\n"],"mappings":"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","names":["path","config","Mux","chunkText","dedent","import_zod","import_mux_node","Mux","pRetry","config","config","import_ai","import_zod","delay","DEFAULT_PROVIDER","SYSTEM_PROMPT","import_ai","DEFAULT_PROVIDER","DEFAULT_PROVIDER","import_ai","import_zod","SYSTEM_PROMPT","buildUserPrompt","DEFAULT_PROVIDER","import_mux_node","message","Mux","audioUrl","import_client_s3","import_lib_storage","import_s3_request_presigner","import_ai","import_zod","DEFAULT_PROVIDER"]}