@n8n/n8n-nodes-langchain
Version:

183 lines • 6.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.description = void 0;
exports.execute = execute;
const n8n_workflow_1 = require("n8n-workflow");
const utils_1 = require("../../helpers/utils");
const transport_1 = require("../../transport");
const descriptions_1 = require("../descriptions");
function isImagesParameter(param) {
if (typeof param !== 'object' || param === null) {
return false;
}
const paramObj = param;
if (!('values' in paramObj)) {
return true;
}
if (!Array.isArray(paramObj.values)) {
return false;
}
return paramObj.values.every((item) => {
if (typeof item !== 'object' || item === null) {
return false;
}
const itemObj = item;
if (!('binaryPropertyName' in itemObj)) {
return true;
}
return (typeof itemObj.binaryPropertyName === 'string' || itemObj.binaryPropertyName === undefined);
});
}
function isGenerateContentResponse(response) {
if (typeof response !== 'object' || response === null) {
return false;
}
const responseObj = response;
if (!('candidates' in responseObj) || !Array.isArray(responseObj.candidates)) {
return false;
}
return responseObj.candidates.every((candidate) => {
if (typeof candidate !== 'object' || candidate === null) {
return false;
}
const candidateObj = candidate;
if (!('content' in candidateObj) ||
typeof candidateObj.content !== 'object' ||
candidateObj.content === null) {
return false;
}
const contentObj = candidateObj.content;
return 'parts' in contentObj && Array.isArray(contentObj.parts);
});
}
const properties = [
(0, descriptions_1.modelRLC)('imageEditModelSearch'),
{
displayName: 'Prompt',
name: 'prompt',
type: 'string',
placeholder: 'e.g. combine the first image with the second image',
description: 'Instruction describing how to edit the image',
default: '',
typeOptions: {
rows: 2,
},
},
{
displayName: 'Images',
name: 'images',
type: 'fixedCollection',
placeholder: 'Add Image',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Image',
},
default: { values: [{ binaryPropertyName: 'data' }] },
description: 'Add one or more binary fields to include images with your prompt',
options: [
{
displayName: 'Image',
name: 'values',
values: [
{
displayName: 'Binary Field Name',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
placeholder: 'e.g. data',
description: 'The name of the binary field containing the image data',
},
],
},
],
},
{
displayName: 'Options',
name: 'options',
placeholder: 'Add Option',
type: 'collection',
default: {},
options: [
{
displayName: 'Put Output in Field',
name: 'binaryPropertyOutput',
type: 'string',
default: 'edited',
hint: 'The name of the output field to put the binary file data in',
},
],
},
];
const displayOptions = {
show: {
operation: ['edit'],
resource: ['image'],
},
};
exports.description = (0, n8n_workflow_1.updateDisplayOptions)(displayOptions, properties);
async function execute(i) {
const prompt = this.getNodeParameter('prompt', i, '');
let model = this.getNodeParameter('modelId', i, '', { extractValue: true });
if (!model) {
model = 'models/gemini-2.5-flash-image-preview';
}
const binaryPropertyOutput = this.getNodeParameter('options.binaryPropertyOutput', i, 'edited');
const outputKey = typeof binaryPropertyOutput === 'string' ? binaryPropertyOutput : 'data';
const imagesParam = this.getNodeParameter('images', i, {
values: [{ binaryPropertyName: 'data' }],
});
if (!isImagesParameter(imagesParam)) {
throw new Error('Invalid images parameter format');
}
const imagesUi = imagesParam.values ?? [];
const imageFieldNames = imagesUi
.map((v) => v.binaryPropertyName)
.filter((n) => Boolean(n));
const fileParts = [];
for (const fieldName of imageFieldNames) {
const bin = this.helpers.assertBinaryData(i, fieldName);
const buf = await this.helpers.getBinaryDataBuffer(i, fieldName);
const uploaded = await utils_1.uploadFile.call(this, buf, bin.mimeType);
fileParts.push({ fileData: { fileUri: uploaded.fileUri, mimeType: uploaded.mimeType } });
}
const generationConfig = {
responseModalities: ['IMAGE'],
};
const body = {
contents: [
{
role: 'user',
parts: [...fileParts, { text: prompt }],
},
],
generationConfig,
};
const response = await transport_1.apiRequest.call(this, 'POST', `/v1beta/${model}:generateContent`, {
body,
});
if (!isGenerateContentResponse(response)) {
throw new Error('Invalid response format from Gemini API');
}
const promises = response.candidates.map(async (candidate) => {
const imagePart = candidate.content.parts.find((part) => 'inlineData' in part);
if (!imagePart?.inlineData?.data) {
throw new Error('No image data returned from Gemini API');
}
const mimeType = imagePart.inlineData.mimeType;
const fileName = (0, utils_1.getFilenameFromMimeType)(mimeType, 'image', 'png');
const bufferOut = Buffer.from(imagePart.inlineData.data, 'base64');
const binaryOut = await this.helpers.prepareBinaryData(bufferOut, fileName, mimeType);
return {
binary: {
[outputKey]: binaryOut,
},
json: {
...binaryOut,
data: undefined,
},
pairedItem: { item: i },
};
});
return await Promise.all(promises);
}
//# sourceMappingURL=edit.operation.js.map