UNPKG

n8n-nodes-gemini-search

Version:

n8n nodes to interact with Google Gemini API for search and content generation

324 lines 14.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GeminiSearch = void 0; const GenericFunctions_1 = require("./GenericFunctions"); const axios_1 = __importDefault(require("axios")); const instructionBuilder_1 = require("./instructionBuilder"); class GeminiSearch { constructor() { this.description = { displayName: 'Gemini Search', name: 'geminiSearch', icon: 'file:gemini.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"]}}', description: 'Perform searches and generate content using Google Gemini API', defaults: { name: 'Gemini Search', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'geminiSearchApi', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Web Search', value: 'webSearch', description: 'Perform a web search using Gemini', action: 'Perform a web search using Gemini', }, { name: 'Generate Content', value: 'generateContent', description: 'Generate content using Gemini', action: 'Generate content using Gemini', }, ], default: 'webSearch', }, { 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: 'Prompt', name: 'prompt', type: 'string', default: '', required: true, displayOptions: { show: { operation: ['webSearch', 'generateContent'], }, }, description: 'The prompt to send to Gemini', }, { displayName: 'Organization Context', name: 'organization', type: 'string', default: '', displayOptions: { show: { operation: ['webSearch'], }, }, 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', displayOptions: { show: { operation: ['webSearch'], }, }, description: 'Optional comma-separated list of URLs to restrict search to', }, { displayName: 'System Instruction', name: 'systemInstruction', type: 'string', typeOptions: { rows: 4, }, default: '', displayOptions: { show: { operation: ['webSearch', 'generateContent'], }, }, description: 'Optional system instruction to guide the model behavior', }, { 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: 'Top P', name: 'topP', type: 'number', default: 1, description: 'Nucleus sampling parameter', }, { displayName: 'Top K', name: 'topK', type: 'number', default: 1, description: 'Top K sampling parameter', }, { 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 operation = this.getNodeParameter('operation', i); const model = this.getNodeParameter('model', i); const prompt = this.getNodeParameter('prompt', i); const options = this.getNodeParameter('options', i, {}); const systemInstruction = this.getNodeParameter('systemInstruction', i, ''); const organization = operation === 'webSearch' ? this.getNodeParameter('organization', i, '') : ''; const restrictUrls = operation === 'webSearch' ? this.getNodeParameter('restrictUrls', i, '') : ''; const finalSystemInstruction = (0, instructionBuilder_1.buildSystemInstruction)({ systemInstruction, organization, restrictUrls, }); const requestBody = { contents: [ { role: 'user', parts: [ { text: prompt, }, ], }, ], generationConfig: { temperature: options.temperature || 0.6, topP: options.topP || 1, topK: options.topK || 1, maxOutputTokens: options.maxOutputTokens || 2048, responseMimeType: 'text/plain', }, }; if (operation === 'webSearch') { requestBody.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 outputJson = { response: ((_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) || '', fullResponse: response, }; if (operation === 'webSearch') { const restrictUrls = this.getNodeParameter('restrictUrls', i, ''); if (restrictUrls) { outputJson.restrictedUrls = restrictUrls; } } if (options.extractSourceUrl) { const sourceUrl = extractSourceUrl(response); outputJson.sourceUrl = sourceUrl; if (sourceUrl) { try { outputJson.redirectedSourceUrl = await getRedirectedUrl(sourceUrl); } catch (error) { outputJson.redirectedSourceUrl = sourceUrl; outputJson.redirectError = error.message; } } } returnData.push({ json: outputJson, pairedItem: { item: i }, }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message, }, pairedItem: { item: i }, }); continue; } throw error; } } return [returnData]; } } exports.GeminiSearch = GeminiSearch; //# sourceMappingURL=GeminiSearch.node.js.map