n8n-nodes-lumalabs
Version:
n8n node for LumaLabs video generation API
270 lines • 11.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LumaLabs = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class LumaLabs {
constructor() {
this.description = {
displayName: 'LumaLabs',
name: 'lumaLabs',
icon: 'file:lumalabs.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Generate videos using LumaLabs AI',
defaults: {
name: 'LumaLabs',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'lumaLabsApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Generate Video',
value: 'generateVideo',
description: 'Generate a new video',
action: 'Generate a new video',
},
{
name: 'Get Video Status',
value: 'getVideoStatus',
description: 'Check the status of a video generation',
action: 'Get the status of a video generation',
},
],
default: 'generateVideo',
},
{
displayName: 'Prompt',
name: 'prompt',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['generateVideo'],
},
},
default: '',
description: 'The prompt to generate the video from',
},
{
displayName: 'Wait For Video',
name: 'waitForVideo',
type: 'boolean',
displayOptions: {
show: {
operation: ['generateVideo'],
},
},
default: true,
description: 'Whether to wait for the video generation to complete',
},
{
displayName: 'Maximum Wait Time',
name: 'maxWaitTime',
type: 'number',
displayOptions: {
show: {
operation: ['generateVideo'],
waitForVideo: [true],
},
},
default: 300,
description: 'Maximum time to wait for video generation in seconds',
},
{
displayName: 'Video ID',
name: 'videoId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['getVideoStatus'],
},
},
default: '',
description: 'The ID of the video to check status for',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['generateVideo'],
},
},
options: [
{
displayName: 'Negative Prompt',
name: 'negativePrompt',
type: 'string',
default: '',
description: 'Things to avoid in the generated video',
},
{
displayName: 'Aspect Ratio',
name: 'aspectRatio',
type: 'options',
options: [
{
name: '16:9',
value: '16:9',
},
{
name: '9:16',
value: '9:16',
},
{
name: '1:1',
value: '1:1',
},
],
default: '16:9',
description: 'The aspect ratio of the generated video',
},
{
displayName: 'Loop',
name: 'loop',
type: 'boolean',
default: false,
description: 'Whether to loop the video',
},
{
displayName: 'Callback URL',
name: 'callbackUrl',
type: 'string',
default: '',
description: 'URL to receive generation status updates',
},
{
displayName: 'Seed',
name: 'seed',
type: 'number',
default: 0,
description: 'Random seed for generation',
},
],
},
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
const operation = this.getNodeParameter('operation', 0);
const credentials = await this.getCredentials('lumaLabsApi');
for (let i = 0; i < items.length; i++) {
try {
if (operation === 'generateVideo') {
const prompt = this.getNodeParameter('prompt', i);
const waitForVideo = this.getNodeParameter('waitForVideo', i);
const maxWaitTime = this.getNodeParameter('maxWaitTime', i);
const additionalFields = this.getNodeParameter('additionalFields', i);
const body = {
prompt,
};
if (additionalFields.negativePrompt) {
body.negative_prompt = additionalFields.negativePrompt;
}
if (additionalFields.aspectRatio) {
body.aspect_ratio = additionalFields.aspectRatio;
}
if (additionalFields.loop !== undefined) {
body.loop = additionalFields.loop;
}
if (additionalFields.callbackUrl) {
body.callback_url = additionalFields.callbackUrl;
}
if (additionalFields.seed !== undefined) {
body.seed = additionalFields.seed;
}
const response = await this.helpers.request({
method: 'POST',
url: 'https://api.lumalabs.ai/dream-machine/v1/generations',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${credentials.apiKey}`,
},
body,
json: true,
});
if (waitForVideo) {
const startTime = Date.now();
const maxWaitTimeMs = maxWaitTime * 1000;
let videoData = response;
while (videoData.state === 'queued' || videoData.state === 'processing') {
if (Date.now() - startTime > maxWaitTimeMs) {
throw new Error(`Video generation timed out after ${maxWaitTime} seconds`);
}
await new Promise(resolve => setTimeout(resolve, 5000));
videoData = await this.helpers.request({
method: 'GET',
url: `https://api.lumalabs.ai/dream-machine/v1/generations/${videoData.id}`,
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${credentials.apiKey}`,
},
json: true,
});
if (videoData.state === 'failed') {
throw new Error(`Video generation failed: ${videoData.failure_reason || 'Unknown error'}`);
}
}
returnData.push({
json: videoData,
});
}
else {
returnData.push({
json: response,
});
}
}
else if (operation === 'getVideoStatus') {
const videoId = this.getNodeParameter('videoId', i);
const response = await this.helpers.request({
method: 'GET',
url: `https://api.lumalabs.ai/dream-machine/v1/generations/${videoId}`,
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${credentials.apiKey}`,
},
json: true,
});
returnData.push({
json: response,
});
}
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: {
error: error.message || 'An error occurred while executing the node',
},
});
continue;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error);
}
}
return [returnData];
}
}
exports.LumaLabs = LumaLabs;
//# sourceMappingURL=LumaLabs.node.js.map