n8n-nodes-pollinations-ai 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -74
- package/credentials/PollinationsApi.credentials.ts +11 -2
- package/dist/credentials/PollinationsApi.credentials.d.ts +2 -1
- package/dist/credentials/PollinationsApi.credentials.js +8 -2
- package/dist/nodes/Pollinations/Pollinations.node.d.ts +8 -1
- package/dist/nodes/Pollinations/Pollinations.node.js +555 -32
- package/dist/nodes/Pollinations/PollinationsChatModel.node.d.ts +10 -0
- package/dist/nodes/Pollinations/PollinationsChatModel.node.js +219 -0
- package/dist/nodes/Pollinations/pollinations.svg +1 -1
- package/nodes/Pollinations/Pollinations.node.json +2 -5
- package/nodes/Pollinations/Pollinations.node.ts +658 -32
- package/nodes/Pollinations/PollinationsChatModel.node.json +17 -0
- package/nodes/Pollinations/PollinationsChatModel.node.ts +247 -0
- package/nodes/Pollinations/pollinations.svg +1 -1
- package/package.json +12 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Pollinations = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
4
5
|
class Pollinations {
|
|
5
6
|
constructor() {
|
|
6
7
|
this.description = {
|
|
@@ -10,7 +11,7 @@ class Pollinations {
|
|
|
10
11
|
group: ['transform'],
|
|
11
12
|
version: 1,
|
|
12
13
|
subtitle: '={{$parameter["operation"]}}',
|
|
13
|
-
description: 'Generate images using Pollinations AI',
|
|
14
|
+
description: 'Generate images and text using Pollinations AI',
|
|
14
15
|
defaults: {
|
|
15
16
|
name: 'Pollinations',
|
|
16
17
|
},
|
|
@@ -36,10 +37,23 @@ class Pollinations {
|
|
|
36
37
|
description: 'Generate an image from a text prompt',
|
|
37
38
|
action: 'Generate an image from a text prompt',
|
|
38
39
|
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Generate with Reference',
|
|
42
|
+
value: 'generateImageWithReference',
|
|
43
|
+
description: 'Generate an image using a reference image',
|
|
44
|
+
action: 'Generate an image using a reference image',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Generate Text',
|
|
48
|
+
value: 'generateText',
|
|
49
|
+
description: 'Generate text from a prompt using AI',
|
|
50
|
+
action: 'Generate text from a prompt',
|
|
51
|
+
},
|
|
39
52
|
],
|
|
40
53
|
default: 'generateImage',
|
|
41
54
|
},
|
|
42
|
-
//
|
|
55
|
+
// ==================== GENERATE IMAGE ====================
|
|
56
|
+
// Prompt (Image)
|
|
43
57
|
{
|
|
44
58
|
displayName: 'Prompt',
|
|
45
59
|
name: 'prompt',
|
|
@@ -56,7 +70,7 @@ class Pollinations {
|
|
|
56
70
|
rows: 4,
|
|
57
71
|
},
|
|
58
72
|
},
|
|
59
|
-
// Model (
|
|
73
|
+
// Model (Image) - Dynamic loading
|
|
60
74
|
{
|
|
61
75
|
displayName: 'Model',
|
|
62
76
|
name: 'model',
|
|
@@ -67,55 +81,135 @@ class Pollinations {
|
|
|
67
81
|
operation: ['generateImage'],
|
|
68
82
|
},
|
|
69
83
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
typeOptions: {
|
|
85
|
+
loadOptionsMethod: 'getImageModels',
|
|
86
|
+
},
|
|
87
|
+
description: 'The model to use for image generation',
|
|
88
|
+
},
|
|
89
|
+
// Advanced Options (Image)
|
|
90
|
+
{
|
|
91
|
+
displayName: 'Options',
|
|
92
|
+
name: 'options',
|
|
93
|
+
type: 'collection',
|
|
94
|
+
placeholder: 'Add Option',
|
|
95
|
+
default: {},
|
|
96
|
+
displayOptions: {
|
|
97
|
+
show: {
|
|
98
|
+
operation: ['generateImage'],
|
|
75
99
|
},
|
|
100
|
+
},
|
|
101
|
+
options: [
|
|
76
102
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
displayName: 'Width',
|
|
104
|
+
name: 'width',
|
|
105
|
+
type: 'number',
|
|
106
|
+
default: 1024,
|
|
107
|
+
description: 'Width of the generated image in pixels',
|
|
108
|
+
typeOptions: {
|
|
109
|
+
minValue: 64,
|
|
110
|
+
maxValue: 2048,
|
|
111
|
+
},
|
|
80
112
|
},
|
|
81
113
|
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
114
|
+
displayName: 'Height',
|
|
115
|
+
name: 'height',
|
|
116
|
+
type: 'number',
|
|
117
|
+
default: 1024,
|
|
118
|
+
description: 'Height of the generated image in pixels',
|
|
119
|
+
typeOptions: {
|
|
120
|
+
minValue: 64,
|
|
121
|
+
maxValue: 2048,
|
|
122
|
+
},
|
|
85
123
|
},
|
|
86
124
|
{
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
125
|
+
displayName: 'Seed',
|
|
126
|
+
name: 'seed',
|
|
127
|
+
type: 'number',
|
|
128
|
+
default: 0,
|
|
129
|
+
description: 'Seed for reproducible generation. Use 0 for random.',
|
|
90
130
|
},
|
|
91
131
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
132
|
+
displayName: 'No Logo',
|
|
133
|
+
name: 'nologo',
|
|
134
|
+
type: 'boolean',
|
|
135
|
+
default: false,
|
|
136
|
+
description: 'Whether to remove the Pollinations watermark',
|
|
95
137
|
},
|
|
96
138
|
{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
139
|
+
displayName: 'Enhance Prompt',
|
|
140
|
+
name: 'enhance',
|
|
141
|
+
type: 'boolean',
|
|
142
|
+
default: false,
|
|
143
|
+
description: 'Whether to automatically enhance the prompt for better results',
|
|
100
144
|
},
|
|
101
145
|
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
146
|
+
displayName: 'Safe Mode',
|
|
147
|
+
name: 'safe',
|
|
148
|
+
type: 'boolean',
|
|
149
|
+
default: false,
|
|
150
|
+
description: 'Whether to enable content safety filter',
|
|
105
151
|
},
|
|
106
152
|
],
|
|
107
|
-
description: 'The model to use for image generation',
|
|
108
153
|
},
|
|
109
|
-
//
|
|
154
|
+
// ==================== GENERATE IMAGE WITH REFERENCE ====================
|
|
155
|
+
// Prompt (Reference)
|
|
156
|
+
{
|
|
157
|
+
displayName: 'Prompt',
|
|
158
|
+
name: 'referencePrompt',
|
|
159
|
+
type: 'string',
|
|
160
|
+
default: '',
|
|
161
|
+
required: true,
|
|
162
|
+
displayOptions: {
|
|
163
|
+
show: {
|
|
164
|
+
operation: ['generateImageWithReference'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
description: 'The text prompt describing how to transform or use the reference image',
|
|
168
|
+
typeOptions: {
|
|
169
|
+
rows: 4,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
// Reference Image URL (Required)
|
|
173
|
+
{
|
|
174
|
+
displayName: 'Reference Image URL',
|
|
175
|
+
name: 'referenceImage',
|
|
176
|
+
type: 'string',
|
|
177
|
+
default: '',
|
|
178
|
+
required: true,
|
|
179
|
+
displayOptions: {
|
|
180
|
+
show: {
|
|
181
|
+
operation: ['generateImageWithReference'],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
placeholder: 'https://example.com/image.jpg',
|
|
185
|
+
description: 'URL of the reference image. Must be publicly accessible.',
|
|
186
|
+
},
|
|
187
|
+
// Model (Reference) - Dynamic loading with image input support
|
|
188
|
+
{
|
|
189
|
+
displayName: 'Model',
|
|
190
|
+
name: 'referenceModel',
|
|
191
|
+
type: 'options',
|
|
192
|
+
default: 'kontext',
|
|
193
|
+
displayOptions: {
|
|
194
|
+
show: {
|
|
195
|
+
operation: ['generateImageWithReference'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
typeOptions: {
|
|
199
|
+
loadOptionsMethod: 'getImageModelsWithReferenceSupport',
|
|
200
|
+
},
|
|
201
|
+
description: 'The model to use. Only models supporting image input are shown.',
|
|
202
|
+
},
|
|
203
|
+
// Advanced Options (Reference)
|
|
110
204
|
{
|
|
111
205
|
displayName: 'Options',
|
|
112
|
-
name: '
|
|
206
|
+
name: 'referenceOptions',
|
|
113
207
|
type: 'collection',
|
|
114
208
|
placeholder: 'Add Option',
|
|
115
209
|
default: {},
|
|
116
210
|
displayOptions: {
|
|
117
211
|
show: {
|
|
118
|
-
operation: ['
|
|
212
|
+
operation: ['generateImageWithReference'],
|
|
119
213
|
},
|
|
120
214
|
},
|
|
121
215
|
options: [
|
|
@@ -171,8 +265,266 @@ class Pollinations {
|
|
|
171
265
|
},
|
|
172
266
|
],
|
|
173
267
|
},
|
|
268
|
+
// ==================== GENERATE TEXT ====================
|
|
269
|
+
// Prompt (Text)
|
|
270
|
+
{
|
|
271
|
+
displayName: 'Prompt',
|
|
272
|
+
name: 'textPrompt',
|
|
273
|
+
type: 'string',
|
|
274
|
+
default: '',
|
|
275
|
+
required: true,
|
|
276
|
+
displayOptions: {
|
|
277
|
+
show: {
|
|
278
|
+
operation: ['generateText'],
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
description: 'The text prompt or question for the AI model',
|
|
282
|
+
typeOptions: {
|
|
283
|
+
rows: 4,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
// Model (Text) - Dynamic loading
|
|
287
|
+
{
|
|
288
|
+
displayName: 'Model',
|
|
289
|
+
name: 'textModel',
|
|
290
|
+
type: 'options',
|
|
291
|
+
default: 'openai',
|
|
292
|
+
displayOptions: {
|
|
293
|
+
show: {
|
|
294
|
+
operation: ['generateText'],
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
typeOptions: {
|
|
298
|
+
loadOptionsMethod: 'getTextModels',
|
|
299
|
+
},
|
|
300
|
+
description: 'The AI model to use for text generation',
|
|
301
|
+
},
|
|
302
|
+
// System Prompt (Text)
|
|
303
|
+
{
|
|
304
|
+
displayName: 'System Prompt',
|
|
305
|
+
name: 'systemPrompt',
|
|
306
|
+
type: 'string',
|
|
307
|
+
default: '',
|
|
308
|
+
displayOptions: {
|
|
309
|
+
show: {
|
|
310
|
+
operation: ['generateText'],
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
description: 'Instructions that define the AI behavior and context',
|
|
314
|
+
placeholder: 'You are a helpful assistant that responds concisely...',
|
|
315
|
+
typeOptions: {
|
|
316
|
+
rows: 3,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
// Temperature (Text)
|
|
320
|
+
{
|
|
321
|
+
displayName: 'Temperature',
|
|
322
|
+
name: 'temperature',
|
|
323
|
+
type: 'number',
|
|
324
|
+
default: 0.7,
|
|
325
|
+
displayOptions: {
|
|
326
|
+
show: {
|
|
327
|
+
operation: ['generateText'],
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
description: 'Controls creativity: 0.0 = strict/deterministic, 2.0 = very creative',
|
|
331
|
+
typeOptions: {
|
|
332
|
+
minValue: 0,
|
|
333
|
+
maxValue: 2,
|
|
334
|
+
numberPrecision: 1,
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
// Advanced Options (Text)
|
|
338
|
+
{
|
|
339
|
+
displayName: 'Options',
|
|
340
|
+
name: 'textOptions',
|
|
341
|
+
type: 'collection',
|
|
342
|
+
placeholder: 'Add Option',
|
|
343
|
+
default: {},
|
|
344
|
+
displayOptions: {
|
|
345
|
+
show: {
|
|
346
|
+
operation: ['generateText'],
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
options: [
|
|
350
|
+
{
|
|
351
|
+
displayName: 'JSON Response',
|
|
352
|
+
name: 'jsonMode',
|
|
353
|
+
type: 'boolean',
|
|
354
|
+
default: false,
|
|
355
|
+
description: 'Whether to force the response in JSON format. Not supported by all models.',
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
displayName: 'Seed',
|
|
359
|
+
name: 'seed',
|
|
360
|
+
type: 'number',
|
|
361
|
+
default: -1,
|
|
362
|
+
description: 'Seed for reproducible results. Use -1 for random.',
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
},
|
|
174
366
|
],
|
|
175
367
|
};
|
|
368
|
+
this.methods = {
|
|
369
|
+
loadOptions: {
|
|
370
|
+
async getImageModels() {
|
|
371
|
+
try {
|
|
372
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
373
|
+
const apiKey = credentials.apiKey;
|
|
374
|
+
const response = await this.helpers.httpRequest({
|
|
375
|
+
method: 'GET',
|
|
376
|
+
url: 'https://gen.pollinations.ai/image/models',
|
|
377
|
+
headers: {
|
|
378
|
+
Authorization: `Bearer ${apiKey}`,
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
if (Array.isArray(response)) {
|
|
382
|
+
// Filter only image models (exclude video models)
|
|
383
|
+
const imageModels = response.filter((model) => model.output_modalities?.includes('image') &&
|
|
384
|
+
!model.output_modalities?.includes('video'));
|
|
385
|
+
return imageModels.map((model) => {
|
|
386
|
+
let displayName = model.description || model.name;
|
|
387
|
+
// Add pricing info if available
|
|
388
|
+
if (model.pricing?.completionImageTokens) {
|
|
389
|
+
const imagesPerPollen = Math.floor(1 / model.pricing.completionImageTokens);
|
|
390
|
+
displayName += ` (~${imagesPerPollen.toLocaleString()} img/$)`;
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
name: displayName,
|
|
394
|
+
value: model.name,
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
// Fallback if API fails
|
|
399
|
+
return [
|
|
400
|
+
{ name: 'Flux Schnell', value: 'flux' },
|
|
401
|
+
{ name: 'SDXL Turbo', value: 'turbo' },
|
|
402
|
+
{ name: 'GPT Image 1 Mini', value: 'gptimage' },
|
|
403
|
+
{ name: 'FLUX.1 Kontext', value: 'kontext' },
|
|
404
|
+
{ name: 'Seedream 4.0', value: 'seedream' },
|
|
405
|
+
{ name: 'NanoBanana', value: 'nanobanana' },
|
|
406
|
+
{ name: 'NanoBanana Pro', value: 'nanobanana-pro' },
|
|
407
|
+
];
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// Fallback if API fails
|
|
411
|
+
return [
|
|
412
|
+
{ name: 'Flux Schnell', value: 'flux' },
|
|
413
|
+
{ name: 'SDXL Turbo', value: 'turbo' },
|
|
414
|
+
{ name: 'GPT Image 1 Mini', value: 'gptimage' },
|
|
415
|
+
{ name: 'FLUX.1 Kontext', value: 'kontext' },
|
|
416
|
+
{ name: 'Seedream 4.0', value: 'seedream' },
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
async getTextModels() {
|
|
421
|
+
try {
|
|
422
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
423
|
+
const apiKey = credentials.apiKey;
|
|
424
|
+
const response = await this.helpers.httpRequest({
|
|
425
|
+
method: 'GET',
|
|
426
|
+
url: 'https://gen.pollinations.ai/text/models',
|
|
427
|
+
headers: {
|
|
428
|
+
Authorization: `Bearer ${apiKey}`,
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
if (Array.isArray(response)) {
|
|
432
|
+
// Filter only text models (exclude image/video models)
|
|
433
|
+
const textModels = response.filter((model) => model.output_modalities?.includes('text') &&
|
|
434
|
+
!model.output_modalities?.includes('image') &&
|
|
435
|
+
!model.output_modalities?.includes('video'));
|
|
436
|
+
return textModels.map((model) => {
|
|
437
|
+
let displayName = model.description || model.name;
|
|
438
|
+
// Add pricing info if available (responses per pollen)
|
|
439
|
+
if (model.pricing?.completionTextTokens) {
|
|
440
|
+
const responsesPerPollen = Math.floor(1 / model.pricing.completionTextTokens);
|
|
441
|
+
displayName += ` (~${responsesPerPollen.toLocaleString()} resp/$)`;
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
name: displayName,
|
|
445
|
+
value: model.name,
|
|
446
|
+
};
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
// Fallback if API fails
|
|
450
|
+
return [
|
|
451
|
+
{ name: 'OpenAI GPT-4o Mini', value: 'openai' },
|
|
452
|
+
{ name: 'OpenAI GPT-4o Mini (Fast)', value: 'openai-fast' },
|
|
453
|
+
{ name: 'OpenAI GPT-4o (Large)', value: 'openai-large' },
|
|
454
|
+
{ name: 'Claude Sonnet 3.5', value: 'claude' },
|
|
455
|
+
{ name: 'Claude (Fast)', value: 'claude-fast' },
|
|
456
|
+
{ name: 'Claude (Large)', value: 'claude-large' },
|
|
457
|
+
{ name: 'Gemini', value: 'gemini' },
|
|
458
|
+
{ name: 'Gemini (Fast)', value: 'gemini-fast' },
|
|
459
|
+
{ name: 'Gemini (Large)', value: 'gemini-large' },
|
|
460
|
+
{ name: 'DeepSeek V3', value: 'deepseek' },
|
|
461
|
+
{ name: 'Mistral', value: 'mistral' },
|
|
462
|
+
{ name: 'Grok', value: 'grok' },
|
|
463
|
+
];
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// Fallback if API fails
|
|
467
|
+
return [
|
|
468
|
+
{ name: 'OpenAI GPT-4o Mini', value: 'openai' },
|
|
469
|
+
{ name: 'OpenAI GPT-4o Mini (Fast)', value: 'openai-fast' },
|
|
470
|
+
{ name: 'OpenAI GPT-4o (Large)', value: 'openai-large' },
|
|
471
|
+
{ name: 'Claude Sonnet 3.5', value: 'claude' },
|
|
472
|
+
{ name: 'Mistral', value: 'mistral' },
|
|
473
|
+
{ name: 'DeepSeek V3', value: 'deepseek' },
|
|
474
|
+
];
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
async getImageModelsWithReferenceSupport() {
|
|
478
|
+
try {
|
|
479
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
480
|
+
const apiKey = credentials.apiKey;
|
|
481
|
+
const response = await this.helpers.httpRequest({
|
|
482
|
+
method: 'GET',
|
|
483
|
+
url: 'https://gen.pollinations.ai/image/models',
|
|
484
|
+
headers: {
|
|
485
|
+
Authorization: `Bearer ${apiKey}`,
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
if (Array.isArray(response)) {
|
|
489
|
+
// Filter only image models that support image input (for reference/transformation)
|
|
490
|
+
const imageModels = response.filter((model) => model.output_modalities?.includes('image') &&
|
|
491
|
+
!model.output_modalities?.includes('video') &&
|
|
492
|
+
model.input_modalities?.includes('image'));
|
|
493
|
+
return imageModels.map((model) => {
|
|
494
|
+
let displayName = model.description || model.name;
|
|
495
|
+
// Add pricing info if available
|
|
496
|
+
if (model.pricing?.completionImageTokens) {
|
|
497
|
+
const imagesPerPollen = Math.floor(1 / model.pricing.completionImageTokens);
|
|
498
|
+
displayName += ` (~${imagesPerPollen.toLocaleString()} img/$)`;
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
name: displayName,
|
|
502
|
+
value: model.name,
|
|
503
|
+
};
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
// Fallback if API fails
|
|
507
|
+
return [
|
|
508
|
+
{ name: 'FLUX.1 Kontext', value: 'kontext' },
|
|
509
|
+
{ name: 'NanoBanana', value: 'nanobanana' },
|
|
510
|
+
{ name: 'NanoBanana Pro', value: 'nanobanana-pro' },
|
|
511
|
+
{ name: 'Seedream 4.0', value: 'seedream' },
|
|
512
|
+
{ name: 'GPT Image 1 Mini', value: 'gptimage' },
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
// Fallback if API fails
|
|
517
|
+
return [
|
|
518
|
+
{ name: 'FLUX.1 Kontext', value: 'kontext' },
|
|
519
|
+
{ name: 'NanoBanana', value: 'nanobanana' },
|
|
520
|
+
{ name: 'NanoBanana Pro', value: 'nanobanana-pro' },
|
|
521
|
+
{ name: 'Seedream 4.0', value: 'seedream' },
|
|
522
|
+
{ name: 'GPT Image 1 Mini', value: 'gptimage' },
|
|
523
|
+
];
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
};
|
|
176
528
|
}
|
|
177
529
|
async execute() {
|
|
178
530
|
const items = this.getInputData();
|
|
@@ -183,9 +535,176 @@ class Pollinations {
|
|
|
183
535
|
const prompt = this.getNodeParameter('prompt', i);
|
|
184
536
|
const model = this.getNodeParameter('model', i);
|
|
185
537
|
const options = this.getNodeParameter('options', i, {});
|
|
538
|
+
// Get credentials
|
|
539
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
540
|
+
const apiKey = credentials.apiKey;
|
|
541
|
+
// Build query parameters
|
|
542
|
+
const queryParams = {
|
|
543
|
+
model,
|
|
544
|
+
};
|
|
545
|
+
if (options.width) {
|
|
546
|
+
queryParams.width = options.width.toString();
|
|
547
|
+
}
|
|
548
|
+
if (options.height) {
|
|
549
|
+
queryParams.height = options.height.toString();
|
|
550
|
+
}
|
|
551
|
+
if (options.seed) {
|
|
552
|
+
queryParams.seed = options.seed.toString();
|
|
553
|
+
}
|
|
554
|
+
if (options.nologo) {
|
|
555
|
+
queryParams.nologo = 'true';
|
|
556
|
+
}
|
|
557
|
+
if (options.enhance) {
|
|
558
|
+
queryParams.enhance = 'true';
|
|
559
|
+
}
|
|
560
|
+
if (options.safe) {
|
|
561
|
+
queryParams.safe = 'true';
|
|
562
|
+
}
|
|
563
|
+
// Build the URL
|
|
564
|
+
const baseUrl = 'https://gen.pollinations.ai/image';
|
|
565
|
+
const encodedPrompt = encodeURIComponent(prompt);
|
|
566
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
567
|
+
const fullUrl = `${baseUrl}/${encodedPrompt}?${queryString}`;
|
|
568
|
+
// Record start time
|
|
569
|
+
const startTime = Date.now();
|
|
570
|
+
// Make the request with authentication
|
|
571
|
+
const response = await this.helpers.httpRequest({
|
|
572
|
+
method: 'GET',
|
|
573
|
+
url: fullUrl,
|
|
574
|
+
headers: {
|
|
575
|
+
Authorization: `Bearer ${apiKey}`,
|
|
576
|
+
},
|
|
577
|
+
encoding: 'arraybuffer',
|
|
578
|
+
returnFullResponse: true,
|
|
579
|
+
});
|
|
580
|
+
// Calculate duration
|
|
581
|
+
const duration = Date.now() - startTime;
|
|
582
|
+
// Prepare binary data
|
|
583
|
+
const binaryData = await this.helpers.prepareBinaryData(Buffer.from(response.body), 'image.png', 'image/png');
|
|
584
|
+
// Build metadata for debugging
|
|
585
|
+
const metadata = {
|
|
586
|
+
request: {
|
|
587
|
+
url: fullUrl,
|
|
588
|
+
prompt,
|
|
589
|
+
model,
|
|
590
|
+
width: options.width || 1024,
|
|
591
|
+
height: options.height || 1024,
|
|
592
|
+
seed: options.seed || null,
|
|
593
|
+
nologo: options.nologo || false,
|
|
594
|
+
enhance: options.enhance || false,
|
|
595
|
+
safe: options.safe || false,
|
|
596
|
+
},
|
|
597
|
+
response: {
|
|
598
|
+
statusCode: response.statusCode,
|
|
599
|
+
contentType: response.headers?.['content-type'] || 'image/png',
|
|
600
|
+
contentLength: response.headers?.['content-length'] || null,
|
|
601
|
+
duration: `${duration}ms`,
|
|
602
|
+
},
|
|
603
|
+
timestamp: new Date().toISOString(),
|
|
604
|
+
};
|
|
605
|
+
returnData.push({
|
|
606
|
+
json: metadata,
|
|
607
|
+
binary: {
|
|
608
|
+
data: binaryData,
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
if (operation === 'generateText') {
|
|
613
|
+
const prompt = this.getNodeParameter('textPrompt', i);
|
|
614
|
+
const model = this.getNodeParameter('textModel', i);
|
|
615
|
+
const systemPrompt = this.getNodeParameter('systemPrompt', i, '');
|
|
616
|
+
const temperature = this.getNodeParameter('temperature', i);
|
|
617
|
+
const textOptions = this.getNodeParameter('textOptions', i, {});
|
|
618
|
+
const jsonMode = textOptions.jsonMode || false;
|
|
619
|
+
// Get credentials
|
|
620
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
621
|
+
const apiKey = credentials.apiKey;
|
|
622
|
+
// Build query parameters
|
|
623
|
+
const queryParams = {
|
|
624
|
+
model,
|
|
625
|
+
temperature: temperature.toString(),
|
|
626
|
+
};
|
|
627
|
+
if (systemPrompt) {
|
|
628
|
+
queryParams.system = systemPrompt;
|
|
629
|
+
}
|
|
630
|
+
if (textOptions.seed !== undefined && textOptions.seed !== -1) {
|
|
631
|
+
queryParams.seed = textOptions.seed.toString();
|
|
632
|
+
}
|
|
633
|
+
if (jsonMode) {
|
|
634
|
+
queryParams.json = 'true';
|
|
635
|
+
}
|
|
636
|
+
// Build the URL
|
|
637
|
+
const baseUrl = 'https://gen.pollinations.ai/text';
|
|
638
|
+
const encodedPrompt = encodeURIComponent(prompt);
|
|
639
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
640
|
+
const fullUrl = `${baseUrl}/${encodedPrompt}?${queryString}`;
|
|
641
|
+
// Record start time
|
|
642
|
+
const startTime = Date.now();
|
|
643
|
+
// Make the request with authentication
|
|
644
|
+
const response = await this.helpers.httpRequest({
|
|
645
|
+
method: 'GET',
|
|
646
|
+
url: fullUrl,
|
|
647
|
+
headers: {
|
|
648
|
+
Authorization: `Bearer ${apiKey}`,
|
|
649
|
+
},
|
|
650
|
+
returnFullResponse: true,
|
|
651
|
+
});
|
|
652
|
+
// Calculate duration
|
|
653
|
+
const duration = Date.now() - startTime;
|
|
654
|
+
// Parse response text
|
|
655
|
+
const text = response.body;
|
|
656
|
+
let parsedJson = null;
|
|
657
|
+
// If JSON mode, try to parse the response
|
|
658
|
+
if (jsonMode) {
|
|
659
|
+
try {
|
|
660
|
+
parsedJson = JSON.parse(text);
|
|
661
|
+
}
|
|
662
|
+
catch {
|
|
663
|
+
// Keep as string if parsing fails
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
// Build metadata for debugging
|
|
667
|
+
const metadata = {
|
|
668
|
+
text: parsedJson || text,
|
|
669
|
+
request: {
|
|
670
|
+
url: fullUrl,
|
|
671
|
+
prompt,
|
|
672
|
+
model,
|
|
673
|
+
system: systemPrompt || null,
|
|
674
|
+
temperature,
|
|
675
|
+
seed: textOptions.seed !== -1 ? textOptions.seed : null,
|
|
676
|
+
jsonMode: jsonMode,
|
|
677
|
+
},
|
|
678
|
+
response: {
|
|
679
|
+
statusCode: response.statusCode,
|
|
680
|
+
contentType: response.headers?.['content-type'] || 'text/plain',
|
|
681
|
+
duration: `${duration}ms`,
|
|
682
|
+
},
|
|
683
|
+
timestamp: new Date().toISOString(),
|
|
684
|
+
};
|
|
685
|
+
returnData.push({
|
|
686
|
+
json: metadata,
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
if (operation === 'generateImageWithReference') {
|
|
690
|
+
const prompt = this.getNodeParameter('referencePrompt', i);
|
|
691
|
+
const referenceImage = this.getNodeParameter('referenceImage', i);
|
|
692
|
+
const model = this.getNodeParameter('referenceModel', i);
|
|
693
|
+
const options = this.getNodeParameter('referenceOptions', i, {});
|
|
694
|
+
// Validate reference image URL
|
|
695
|
+
try {
|
|
696
|
+
new URL(referenceImage);
|
|
697
|
+
}
|
|
698
|
+
catch {
|
|
699
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid reference image URL: "${referenceImage}"`, { itemIndex: i });
|
|
700
|
+
}
|
|
701
|
+
// Get credentials
|
|
702
|
+
const credentials = await this.getCredentials('pollinationsApi');
|
|
703
|
+
const apiKey = credentials.apiKey;
|
|
186
704
|
// Build query parameters
|
|
187
705
|
const queryParams = {
|
|
188
706
|
model,
|
|
707
|
+
image: referenceImage,
|
|
189
708
|
};
|
|
190
709
|
if (options.width) {
|
|
191
710
|
queryParams.width = options.width.toString();
|
|
@@ -206,16 +725,19 @@ class Pollinations {
|
|
|
206
725
|
queryParams.safe = 'true';
|
|
207
726
|
}
|
|
208
727
|
// Build the URL
|
|
209
|
-
const baseUrl = 'https://
|
|
728
|
+
const baseUrl = 'https://gen.pollinations.ai/image';
|
|
210
729
|
const encodedPrompt = encodeURIComponent(prompt);
|
|
211
730
|
const queryString = new URLSearchParams(queryParams).toString();
|
|
212
731
|
const fullUrl = `${baseUrl}/${encodedPrompt}?${queryString}`;
|
|
213
732
|
// Record start time
|
|
214
733
|
const startTime = Date.now();
|
|
215
|
-
// Make the request
|
|
734
|
+
// Make the request with authentication
|
|
216
735
|
const response = await this.helpers.httpRequest({
|
|
217
736
|
method: 'GET',
|
|
218
737
|
url: fullUrl,
|
|
738
|
+
headers: {
|
|
739
|
+
Authorization: `Bearer ${apiKey}`,
|
|
740
|
+
},
|
|
219
741
|
encoding: 'arraybuffer',
|
|
220
742
|
returnFullResponse: true,
|
|
221
743
|
});
|
|
@@ -229,6 +751,7 @@ class Pollinations {
|
|
|
229
751
|
url: fullUrl,
|
|
230
752
|
prompt,
|
|
231
753
|
model,
|
|
754
|
+
referenceImage,
|
|
232
755
|
width: options.width || 1024,
|
|
233
756
|
height: options.height || 1024,
|
|
234
757
|
seed: options.seed || null,
|