n8n-nodes-gemini-search
Version:
n8n nodes to interact with Google Gemini API for search and content generation
266 lines • 12.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GeminiSearchTool = void 0;
const GenericFunctions_1 = require("./GenericFunctions");
const axios_1 = __importDefault(require("axios"));
const instructionBuilder_1 = require("./instructionBuilder");
class GeminiSearchTool {
constructor() {
this.description = {
displayName: 'Gemini Search Tool',
name: 'geminiSearchTool',
icon: 'file:gemini.svg',
group: ['transform'],
version: 1,
description: 'Use Google Gemini as a search tool',
defaults: {
name: 'Gemini Search Tool',
},
inputs: [{ type: 'main', required: true }],
outputs: [{ type: 'main', required: true }],
usableAsTool: true,
credentials: [
{
name: 'geminiSearchApi',
required: true,
},
],
properties: [
{
displayName: 'Query',
name: 'query',
type: 'string',
default: '',
required: true,
description: 'The search query to execute with Gemini',
},
{
displayName: 'Model',
name: 'model',
type: 'options',
options: [
{
name: 'Gemini 1.0 Pro',
value: 'gemini-1.0-pro',
},
{
name: 'Gemini 1.5 Pro',
value: 'gemini-1.5-pro',
},
{
name: 'Gemini 2.0 Flash',
value: 'gemini-2.0-flash',
},
{
name: 'Gemini 2.0 Pro',
value: 'gemini-2.0-pro',
},
{
name: 'Gemini 2.5 Pro',
value: 'gemini-2.5-pro',
},
],
default: 'gemini-2.0-flash',
description: 'The Gemini model to use',
},
{
displayName: 'Organization Context',
name: 'organization',
type: 'string',
default: '',
description: 'Optional organization name to use as context for search',
},
{
displayName: 'Restrict Search to URLs',
name: 'restrictUrls',
type: 'string',
default: '',
placeholder: 'example.com,docs.example.com',
description: 'Optional comma-separated list of URLs to restrict search to',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Temperature',
name: 'temperature',
type: 'number',
typeOptions: {
minValue: 0,
maxValue: 1,
numberPrecision: 1,
},
default: 0.6,
description: 'Controls randomness in the response (0-1)',
},
{
displayName: 'Max Output Tokens',
name: 'maxOutputTokens',
type: 'number',
default: 2048,
description: 'Maximum number of tokens to generate',
},
{
displayName: 'Custom System Instruction',
name: 'systemInstruction',
type: 'string',
typeOptions: {
rows: 4,
},
default: '',
description: 'Override the default system instruction',
},
{
displayName: 'Return Full Response',
name: 'returnFullResponse',
type: 'boolean',
default: false,
description: 'Whether to return the full API response',
},
{
displayName: 'Extract Source URL',
name: 'extractSourceUrl',
type: 'boolean',
default: false,
description: 'Whether to extract the source URL from the response',
},
],
},
],
};
}
async execute() {
var _a, _b, _c, _d, _e;
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const query = this.getNodeParameter('query', i);
const model = this.getNodeParameter('model', i);
const organization = this.getNodeParameter('organization', i, '');
const restrictUrls = this.getNodeParameter('restrictUrls', i, '');
const options = this.getNodeParameter('options', i, {});
const finalSystemInstruction = (0, instructionBuilder_1.buildSystemInstruction)({
systemInstruction: options.systemInstruction,
organization,
restrictUrls,
});
const requestBody = {
contents: [
{
role: 'user',
parts: [
{
text: query,
},
],
},
],
generationConfig: {
temperature: options.temperature || 0.6,
topP: 1,
topK: 1,
maxOutputTokens: options.maxOutputTokens || 2048,
responseMimeType: 'text/plain',
},
tools: [
{
googleSearch: {},
},
],
};
if (finalSystemInstruction) {
requestBody.systemInstruction = {
parts: [
{
text: finalSystemInstruction,
},
],
};
}
const response = await GenericFunctions_1.geminiRequest.call(this, model, requestBody);
const extractSourceUrl = (responseObj) => {
var _a, _b, _c, _d, _e, _f;
const possiblePaths = [
(_f = (_e = (_d = (_c = (_b = (_a = responseObj === null || responseObj === void 0 ? void 0 : responseObj.candidates) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.groundingMetadata) === null || _c === void 0 ? void 0 : _c.groundingChunks) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.web) === null || _f === void 0 ? void 0 : _f.uri,
];
return (possiblePaths.find((url) => typeof url === 'string' &&
(url.startsWith('http://') || url.startsWith('https://'))) || '');
};
const getRedirectedUrl = async (url) => {
var _a, _b, _c, _d;
if (!url)
return '';
try {
const response = await axios_1.default.head(url, {
maxRedirects: 10,
timeout: 5000,
validateStatus: null,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
},
});
const finalUrl = ((_b = (_a = response.request) === null || _a === void 0 ? void 0 : _a.res) === null || _b === void 0 ? void 0 : _b.responseUrl) ||
((_c = response.request) === null || _c === void 0 ? void 0 : _c.responseURL) ||
(typeof response.request === 'object' && 'res' in response.request
? (_d = response.request.res.headers) === null || _d === void 0 ? void 0 : _d.location
: null) ||
url;
return finalUrl;
}
catch (error) {
console.error(`Error fetching redirected URL: ${error.message}`);
return url;
}
};
const outputData = {
result: ((_e = (_d = (_c = (_b = (_a = response.candidates) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.parts) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.text) || '',
query,
organization,
restrictedUrls: restrictUrls || undefined,
};
if (options.extractSourceUrl) {
const sourceUrl = extractSourceUrl(response);
outputData.sourceUrl = sourceUrl;
if (sourceUrl) {
try {
outputData.redirectedSourceUrl = await getRedirectedUrl(sourceUrl);
}
catch (error) {
outputData.redirectedSourceUrl = sourceUrl;
}
}
}
if (options.returnFullResponse) {
outputData.fullResponse = response;
}
returnData.push({
json: outputData,
pairedItem: { item: i },
});
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: {
error: error.message,
},
pairedItem: { item: i },
});
continue;
}
throw error;
}
}
return [returnData];
}
}
exports.GeminiSearchTool = GeminiSearchTool;
//# sourceMappingURL=GeminiSearchTool.node.js.map