n8n-nodes-vlm 3.2.1 → 3.3.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.
@@ -1,14 +1,20 @@
1
1
  import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
2
  /**
3
- * VLM Complexity Classifier Workflow Node v3
3
+ * VLM Complexity Classifier Workflow Node v3.3
4
4
  *
5
5
  * Routes documents to LOW or HIGH outputs based on VLM classification.
6
6
  * Always preserves both binary data and classification results.
7
+ *
8
+ * UI Structure:
9
+ * - Model selection
10
+ * - Input Settings (notice + fields)
11
+ * - Output Settings (notice + fields)
12
+ * - Advanced Options (collection)
7
13
  */
8
14
  export declare class VLMComplexityWorkflow implements INodeType {
9
15
  description: INodeTypeDescription;
10
16
  /**
11
- * Execute Method - v3 Dual Output
17
+ * Execute Method - v3.3 Dual Output with improved UI
12
18
  *
13
19
  * Routes items to LOW or HIGH output based on classification.
14
20
  * Always preserves binary data alongside classification results.
@@ -4,10 +4,16 @@ exports.VLMComplexityWorkflow = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const vlm_logic_1 = require("../shared/vlm-logic");
6
6
  /**
7
- * VLM Complexity Classifier Workflow Node v3
7
+ * VLM Complexity Classifier Workflow Node v3.3
8
8
  *
9
9
  * Routes documents to LOW or HIGH outputs based on VLM classification.
10
10
  * Always preserves both binary data and classification results.
11
+ *
12
+ * UI Structure:
13
+ * - Model selection
14
+ * - Input Settings (notice + fields)
15
+ * - Output Settings (notice + fields)
16
+ * - Advanced Options (collection)
11
17
  */
12
18
  class VLMComplexityWorkflow {
13
19
  constructor() {
@@ -16,7 +22,7 @@ class VLMComplexityWorkflow {
16
22
  name: 'vlmComplexityWorkflow',
17
23
  icon: 'file:vlm.svg',
18
24
  group: ['transform'],
19
- version: 2,
25
+ version: 3,
20
26
  subtitle: '={{$parameter["model"]}}',
21
27
  description: 'Classify document complexity and route to LOW/HIGH outputs',
22
28
  defaults: {
@@ -43,6 +49,9 @@ class VLMComplexityWorkflow {
43
49
  baseURL: '={{ $credentials.baseUrl.replace(new RegExp("/$"), "") }}',
44
50
  },
45
51
  properties: [
52
+ // ═══════════════════════════════════════════════════════════════
53
+ // MODEL SELECTION
54
+ // ═══════════════════════════════════════════════════════════════
46
55
  {
47
56
  displayName: 'Model',
48
57
  name: 'model',
@@ -84,75 +93,111 @@ class VLMComplexityWorkflow {
84
93
  },
85
94
  required: true,
86
95
  },
96
+ // ═══════════════════════════════════════════════════════════════
97
+ // INPUT SETTINGS
98
+ // ═══════════════════════════════════════════════════════════════
87
99
  {
88
- displayName: 'Options',
89
- name: 'options',
90
- type: 'collection',
91
- placeholder: 'Add Option',
92
- default: {},
100
+ displayName: 'Input Settings',
101
+ name: 'inputSettingsNotice',
102
+ type: 'notice',
103
+ default: '',
104
+ },
105
+ {
106
+ displayName: 'Image Source',
107
+ name: 'imageSource',
108
+ type: 'options',
93
109
  options: [
94
110
  {
95
- displayName: 'Image Source',
96
- name: 'imageSource',
97
- type: 'options',
98
- options: [
99
- {
100
- name: 'From Binary',
101
- value: 'binary',
102
- description: 'Extract image from binary field (n8n standard)',
103
- },
104
- {
105
- name: 'From Base64 Field',
106
- value: 'base64field',
107
- description: 'Use base64 string from JSON field (with or without Data URI prefix)',
108
- },
109
- ],
110
- default: 'binary',
111
- description: 'Where to get the image data from',
111
+ name: 'From Binary',
112
+ value: 'binary',
113
+ description: 'Extract image from binary field (n8n standard)',
112
114
  },
113
115
  {
114
- displayName: 'Binary Field',
115
- name: 'binaryField',
116
- type: 'string',
117
- default: '',
118
- placeholder: 'e.g. data (auto-detect if empty)',
119
- description: 'Name of the binary field to use for classification. Leave empty to auto-detect first image.',
116
+ name: 'From Base64 Field',
117
+ value: 'base64field',
118
+ description: 'Use base64 string from JSON field (with or without Data URI prefix)',
120
119
  },
121
- {
122
- displayName: 'Base64 Field',
123
- name: 'base64Field',
124
- type: 'string',
125
- default: 'data',
126
- placeholder: 'e.g. data, base64Image',
127
- description: 'JSON field containing base64 string (auto-detects Data URI prefix)',
120
+ ],
121
+ default: 'binary',
122
+ description: 'Where to get the image data from',
123
+ },
124
+ {
125
+ displayName: 'Binary Field',
126
+ name: 'binaryField',
127
+ type: 'string',
128
+ default: '',
129
+ placeholder: 'e.g. data (leave empty to auto-detect)',
130
+ description: 'Name of the binary field containing the image. Leave empty to auto-detect first image.',
131
+ displayOptions: {
132
+ show: {
133
+ imageSource: ['binary'],
134
+ },
135
+ },
136
+ },
137
+ {
138
+ displayName: 'Base64 Field',
139
+ name: 'base64Field',
140
+ type: 'string',
141
+ default: 'data',
142
+ placeholder: 'e.g. data, base64Image, imageData',
143
+ description: 'JSON field containing the base64 string. Auto-detects Data URI prefix.',
144
+ displayOptions: {
145
+ show: {
146
+ imageSource: ['base64field'],
128
147
  },
148
+ },
149
+ },
150
+ // ═══════════════════════════════════════════════════════════════
151
+ // OUTPUT SETTINGS
152
+ // ═══════════════════════════════════════════════════════════════
153
+ {
154
+ displayName: 'Output Settings',
155
+ name: 'outputSettingsNotice',
156
+ type: 'notice',
157
+ default: '',
158
+ },
159
+ {
160
+ displayName: 'Output Base64 Field',
161
+ name: 'outputBase64Field',
162
+ type: 'string',
163
+ default: '',
164
+ placeholder: 'e.g. base64Image (leave empty to skip)',
165
+ description: 'If set, the base64 image will be added to output JSON under this field name',
166
+ },
167
+ {
168
+ displayName: 'Output Base64 Format',
169
+ name: 'outputBase64Format',
170
+ type: 'options',
171
+ options: [
129
172
  {
130
- displayName: 'Output Base64 Field',
131
- name: 'outputBase64Field',
132
- type: 'string',
133
- default: '',
134
- placeholder: 'e.g. base64Image',
135
- description: 'If set, the base64 image will be added to output JSON under this field name.',
173
+ name: 'Raw Base64',
174
+ value: 'raw',
175
+ description: 'iVBORw0KGgo... (like n8n native binary.data.data)',
136
176
  },
137
177
  {
138
- displayName: 'Output Base64 Format',
139
- name: 'outputBase64Format',
140
- type: 'options',
141
- options: [
142
- {
143
- name: 'Raw Base64',
144
- value: 'raw',
145
- description: 'iVBORw0KGgo... (like n8n native)',
146
- },
147
- {
148
- name: 'Data URI',
149
- value: 'datauri',
150
- description: 'data:image/png;base64,iVBORw0KGgo...',
151
- },
152
- ],
153
- default: 'raw',
154
- description: 'Format of the base64 output (only applies if Output Base64 Field is set)',
178
+ name: 'Data URI',
179
+ value: 'datauri',
180
+ description: 'data:image/png;base64,iVBORw0KGgo...',
181
+ },
182
+ ],
183
+ default: 'raw',
184
+ description: 'Format of the base64 in the output field',
185
+ displayOptions: {
186
+ hide: {
187
+ outputBase64Field: [''],
155
188
  },
189
+ },
190
+ },
191
+ // ═══════════════════════════════════════════════════════════════
192
+ // ADVANCED OPTIONS
193
+ // ═══════════════════════════════════════════════════════════════
194
+ {
195
+ displayName: 'Advanced Options',
196
+ name: 'advancedOptions',
197
+ type: 'collection',
198
+ placeholder: 'Add Option',
199
+ default: {},
200
+ options: [
156
201
  {
157
202
  displayName: 'Request Timeout (ms)',
158
203
  name: 'timeout',
@@ -170,7 +215,7 @@ class VLMComplexityWorkflow {
170
215
  };
171
216
  }
172
217
  /**
173
- * Execute Method - v3 Dual Output
218
+ * Execute Method - v3.3 Dual Output with improved UI
174
219
  *
175
220
  * Routes items to LOW or HIGH output based on classification.
176
221
  * Always preserves binary data alongside classification results.
@@ -178,22 +223,25 @@ class VLMComplexityWorkflow {
178
223
  async execute() {
179
224
  var _a;
180
225
  const items = this.getInputData();
181
- this.logger.debug(`VLM Complexity Classifier: Processing ${items.length} input items`);
226
+ this.logger.debug(`VLM Complexity Classifier v3.3: Processing ${items.length} input items`);
182
227
  // Get credentials
183
228
  const credentials = await this.getCredentials('ollamaApi');
184
229
  const serverUrl = credentials.baseUrl.replace(/\/$/, '');
185
- // Get node parameters
230
+ // Get node parameters - now directly from properties (not nested in options)
186
231
  const model = this.getNodeParameter('model', 0);
187
- const options = this.getNodeParameter('options', 0, {});
188
- const timeout = (_a = options.timeout) !== null && _a !== void 0 ? _a : 30000;
189
- const imageSource = options.imageSource || 'binary';
190
- const binaryField = options.binaryField || '';
191
- const base64Field = options.base64Field || 'data';
192
- const outputBase64Field = options.outputBase64Field || '';
193
- const outputBase64Format = options.outputBase64Format || 'raw';
194
- // DEBUG: Log options to diagnose format bug
195
- this.logger.debug(`VLM DEBUG OPTIONS: imageSource='${imageSource}', outputBase64Format='${outputBase64Format}', outputBase64Field='${outputBase64Field}'`);
196
- this.logger.debug(`VLM DEBUG: outputBase64Format === 'raw' ? ${outputBase64Format === 'raw'}`);
232
+ const imageSource = this.getNodeParameter('imageSource', 0, 'binary');
233
+ const binaryField = this.getNodeParameter('binaryField', 0, '');
234
+ const base64Field = this.getNodeParameter('base64Field', 0, 'data');
235
+ const outputBase64Field = this.getNodeParameter('outputBase64Field', 0, '');
236
+ const outputBase64Format = this.getNodeParameter('outputBase64Format', 0, 'raw');
237
+ // Advanced options
238
+ const advancedOptions = this.getNodeParameter('advancedOptions', 0, {});
239
+ const timeout = (_a = advancedOptions.timeout) !== null && _a !== void 0 ? _a : 30000;
240
+ // DEBUG: Log all parameters
241
+ this.logger.debug(`VLM DEBUG PARAMS: model='${model}'`);
242
+ this.logger.debug(`VLM DEBUG PARAMS: imageSource='${imageSource}', binaryField='${binaryField}', base64Field='${base64Field}'`);
243
+ this.logger.debug(`VLM DEBUG PARAMS: outputBase64Field='${outputBase64Field}', outputBase64Format='${outputBase64Format}'`);
244
+ this.logger.debug(`VLM DEBUG PARAMS: outputBase64Format === 'raw' ? ${outputBase64Format === 'raw'}`);
197
245
  // Verify server has classifier capability (optional check)
198
246
  const status = await (0, vlm_logic_1.checkServerStatus)(this, serverUrl, timeout);
199
247
  if (status.status === 'error') {
@@ -215,6 +263,7 @@ class VLMComplexityWorkflow {
215
263
  if (imageSource === 'base64field') {
216
264
  // Extract from JSON field
217
265
  const fieldValue = item.json[base64Field];
266
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Reading from JSON field '${base64Field}', exists=${!!fieldValue}, length=${(fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.length) || 0}`);
218
267
  if (fieldValue) {
219
268
  // Auto-detect if it's already a Data URI
220
269
  const dataUriMatch = fieldValue.match(/^data:([^;]+);base64,(.+)$/);
@@ -222,17 +271,19 @@ class VLMComplexityWorkflow {
222
271
  mimeType = dataUriMatch[1];
223
272
  rawBase64 = dataUriMatch[2];
224
273
  base64Image = fieldValue; // Already in Data URI format
274
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Detected Data URI, mimeType='${mimeType}'`);
225
275
  }
226
276
  else {
227
277
  // Raw base64, wrap in Data URI
228
278
  rawBase64 = fieldValue;
229
279
  base64Image = `data:${mimeType};base64,${rawBase64}`;
280
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Raw base64, wrapped in Data URI`);
230
281
  }
231
- this.logger.debug(`Item ${i}: Using base64 from JSON field '${base64Field}' (${mimeType})`);
232
282
  }
233
283
  }
234
284
  else {
235
285
  // Extract from binary (default)
286
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Reading from binary, binaryField='${binaryField}', hasBinary=${!!item.binary}`);
236
287
  if (item.binary) {
237
288
  if (binaryField && item.binary[binaryField]) {
238
289
  // Use specified binary field
@@ -241,7 +292,7 @@ class VLMComplexityWorkflow {
241
292
  mimeType = data.mimeType || 'image/png';
242
293
  rawBase64 = data.data;
243
294
  base64Image = `data:${mimeType};base64,${rawBase64}`;
244
- this.logger.debug(`Item ${i}: Using specified binary field '${binaryField}' (${mimeType})`);
295
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Using specified binary field '${binaryField}' (${mimeType})`);
245
296
  }
246
297
  }
247
298
  else {
@@ -252,7 +303,7 @@ class VLMComplexityWorkflow {
252
303
  mimeType = data.mimeType;
253
304
  rawBase64 = data.data;
254
305
  base64Image = `data:${mimeType};base64,${rawBase64}`;
255
- this.logger.debug(`Item ${i}: Auto-detected image from binary '${binaryKey}' (${mimeType})`);
306
+ this.logger.debug(`VLM DEBUG INPUT [${i}]: Auto-detected image from binary '${binaryKey}' (${mimeType})`);
256
307
  break;
257
308
  }
258
309
  }
@@ -260,7 +311,7 @@ class VLMComplexityWorkflow {
260
311
  }
261
312
  }
262
313
  if (!base64Image) {
263
- this.logger.warn(`Item ${i}: No image found (source: ${imageSource})`);
314
+ this.logger.warn(`VLM WARNING [${i}]: No image found (imageSource=${imageSource})`);
264
315
  }
265
316
  // Classify the document
266
317
  const classification = await (0, vlm_logic_1.classifySingleDocument)(this, {
@@ -268,14 +319,14 @@ class VLMComplexityWorkflow {
268
319
  base64Image,
269
320
  timeout,
270
321
  });
271
- this.logger.debug(`Item ${i}: Classified as ${classification.complexity} (confidence: ${classification.confidence})`);
322
+ this.logger.debug(`VLM CLASSIFICATION [${i}]: ${classification.complexity} (confidence: ${classification.confidence}, model: ${classification.modelUsed})`);
272
323
  // Determine base64 output value based on format preference
273
- // DEBUG: Log values before output decision
274
- this.logger.debug(`VLM DEBUG OUTPUT: rawBase64 defined=${!!rawBase64}, rawBase64 prefix='${rawBase64 === null || rawBase64 === void 0 ? void 0 : rawBase64.substring(0, 25)}...'`);
275
- this.logger.debug(`VLM DEBUG OUTPUT: base64Image prefix='${base64Image === null || base64Image === void 0 ? void 0 : base64Image.substring(0, 35)}...'`);
276
- this.logger.debug(`VLM DEBUG OUTPUT: choosing ${outputBase64Format === 'raw' ? 'rawBase64' : 'base64Image'}`);
324
+ this.logger.debug(`VLM DEBUG OUTPUT [${i}]: rawBase64 defined=${!!rawBase64}, length=${(rawBase64 === null || rawBase64 === void 0 ? void 0 : rawBase64.length) || 0}`);
325
+ this.logger.debug(`VLM DEBUG OUTPUT [${i}]: rawBase64 prefix='${rawBase64 === null || rawBase64 === void 0 ? void 0 : rawBase64.substring(0, 30)}...'`);
326
+ this.logger.debug(`VLM DEBUG OUTPUT [${i}]: base64Image prefix='${base64Image === null || base64Image === void 0 ? void 0 : base64Image.substring(0, 40)}...'`);
327
+ this.logger.debug(`VLM DEBUG OUTPUT [${i}]: format='${outputBase64Format}', choosing ${outputBase64Format === 'raw' ? 'rawBase64' : 'base64Image'}`);
277
328
  const outputBase64Value = outputBase64Format === 'raw' ? rawBase64 : base64Image;
278
- this.logger.debug(`VLM DEBUG OUTPUT: outputBase64Value prefix='${outputBase64Value === null || outputBase64Value === void 0 ? void 0 : outputBase64Value.substring(0, 35)}...'`);
329
+ this.logger.debug(`VLM DEBUG OUTPUT [${i}]: outputBase64Value prefix='${outputBase64Value === null || outputBase64Value === void 0 ? void 0 : outputBase64Value.substring(0, 40)}...'`);
279
330
  // Build output item with BOTH json AND binary
280
331
  const outputItem = {
281
332
  json: {
@@ -302,7 +353,7 @@ class VLMComplexityWorkflow {
302
353
  lowItems.push(outputItem);
303
354
  }
304
355
  }
305
- this.logger.debug(`Classification complete: ${lowItems.length} LOW, ${highItems.length} HIGH`);
356
+ this.logger.debug(`VLM COMPLETE: ${lowItems.length} LOW, ${highItems.length} HIGH`);
306
357
  // Return dual outputs: [LOW, HIGH]
307
358
  return [lowItems, highItems];
308
359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-vlm",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Vision-Language Models for n8n - Lightweight specialized VLMs for document analysis and classification",
5
5
  "main": "dist/index.js",
6
6
  "author": "Nicolas Geysse",