UNPKG

n8n-nodes-video-ai

Version:

n8n node for AI-powered video Operations (analysis, Review, Summarize, etc), currently supporting Google Gemini.

199 lines 8.53 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.VideoAiAnalysis = void 0; const n8n_workflow_1 = require("n8n-workflow"); class VideoAiAnalysis { constructor() { this.description = { displayName: 'Video AI Analysis', name: 'videoAiAnalysis', group: ['transform'], version: 1, description: 'Perform AI-powered video Operations (analysis, Review, Summarize, etc). <br><em>Beta: Currently supports Google Gemini models only. More AI providers coming soon!</em>', documentationUrl: 'https://www.hadidizflow.com/blog/unlock-ai-video-analysis-n8n-video-ai-node-hadidizflow', defaults: { name: 'Video AI Analysis', }, icon: 'file:VideoAiAnalysis.svg', subtitle: '={{$parameter["customPrompt"] ? "Custom Prompt" : ""}}', inputs: ['main'], outputs: ['main'], credentials: [ { name: 'geminiApi', required: true, }, ], properties: [ { displayName: 'Video URL', name: 'videoUrl', type: 'string', default: '', required: true, description: 'URL of the video to analyze', }, { displayName: 'Custom Prompt', name: 'customPrompt', type: 'string', default: '', required: true, description: 'Custom prompt to analyze the video', typeOptions: { rows: 4, }, }, { displayName: 'Model', name: 'model', type: 'options', default: 'gemini-2.0-flash-thinking-exp-01-21', options: [ { name: 'Gemini 2.0 Flash (Experimental)', value: 'gemini-2.0-flash-exp', }, { name: 'Gemini 2.0 Flash Thinking (Experimental)', value: 'gemini-2.0-flash-thinking-exp-01-21', }, ], description: 'Which Gemini model to use for video analysis', }, { displayName: 'Options', name: 'options', type: 'collection', default: {}, placeholder: 'Add Option', options: [ { displayName: 'Temperature', name: 'temperature', type: 'number', default: 0.5, description: 'Controls the randomness of the output. Values can range from 0.0 to 1.0.', typeOptions: { minValue: 0, maxValue: 1, }, }, { displayName: 'Maximum Video Size (MB)', name: 'maxVideoSize', type: 'number', default: 25, description: 'Maximum size of video to download in megabytes (MB)', }, ], }, ], }; } async execute() { const items = this.getInputData(); const returnData = []; const credentials = await this.getCredentials('geminiApi'); const apiKey = credentials.apiKey; const generativeAI = await Promise.resolve().then(() => __importStar(require('@google/generative-ai'))); const fetch = require('node-fetch'); const genAI = new generativeAI.GoogleGenerativeAI(apiKey); for (let i = 0; i < items.length; i++) { try { const videoUrl = this.getNodeParameter('videoUrl', i); const customPrompt = this.getNodeParameter('customPrompt', i); const model = this.getNodeParameter('model', i); const options = this.getNodeParameter('options', i, {}); const temperature = options.temperature || 0.5; const maxVideoSize = options.maxVideoSize || 25; this.logger.info(`Downloading video from ${videoUrl}...`); const fetchOptions = { method: 'GET', }; const response = await fetch(videoUrl, fetchOptions); if (!response.ok) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to download video: ${response.statusText}`, { itemIndex: i }); } const contentLength = response.headers.get('content-length'); if (contentLength) { const sizeInMB = parseInt(contentLength) / (1024 * 1024); if (sizeInMB > maxVideoSize) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Video size (${sizeInMB.toFixed(2)} MB) exceeds maximum allowed size (${maxVideoSize} MB)`, { itemIndex: i }); } } const contentType = response.headers.get('content-type'); const mimeType = contentType || 'video/mp4'; this.logger.info('Processing video data...'); const videoBuffer = await response.buffer(); const videoBase64 = videoBuffer.toString('base64'); const generationModel = genAI.getGenerativeModel({ model, generationConfig: { temperature, }, }); this.logger.info(`Analyzing video with ${model}...`); const req = [ { text: customPrompt }, { inlineData: { mimeType, data: videoBase64 } } ]; const result = await generationModel.generateContent(req); const output = { text: result.response.text(), model, prompt: customPrompt, }; returnData.push({ json: output, pairedItem: i, }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message, }, pairedItem: i, }); continue; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i, }); } } return [returnData]; } } exports.VideoAiAnalysis = VideoAiAnalysis; //# sourceMappingURL=VideoAiAnalysis.node.js.map