n8n-nodes-vlm 3.2.0 → 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:
|
|
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: '
|
|
89
|
-
name: '
|
|
90
|
-
type: '
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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,19 +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
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
const
|
|
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'}`);
|
|
194
245
|
// Verify server has classifier capability (optional check)
|
|
195
246
|
const status = await (0, vlm_logic_1.checkServerStatus)(this, serverUrl, timeout);
|
|
196
247
|
if (status.status === 'error') {
|
|
@@ -212,6 +263,7 @@ class VLMComplexityWorkflow {
|
|
|
212
263
|
if (imageSource === 'base64field') {
|
|
213
264
|
// Extract from JSON field
|
|
214
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}`);
|
|
215
267
|
if (fieldValue) {
|
|
216
268
|
// Auto-detect if it's already a Data URI
|
|
217
269
|
const dataUriMatch = fieldValue.match(/^data:([^;]+);base64,(.+)$/);
|
|
@@ -219,17 +271,19 @@ class VLMComplexityWorkflow {
|
|
|
219
271
|
mimeType = dataUriMatch[1];
|
|
220
272
|
rawBase64 = dataUriMatch[2];
|
|
221
273
|
base64Image = fieldValue; // Already in Data URI format
|
|
274
|
+
this.logger.debug(`VLM DEBUG INPUT [${i}]: Detected Data URI, mimeType='${mimeType}'`);
|
|
222
275
|
}
|
|
223
276
|
else {
|
|
224
277
|
// Raw base64, wrap in Data URI
|
|
225
278
|
rawBase64 = fieldValue;
|
|
226
279
|
base64Image = `data:${mimeType};base64,${rawBase64}`;
|
|
280
|
+
this.logger.debug(`VLM DEBUG INPUT [${i}]: Raw base64, wrapped in Data URI`);
|
|
227
281
|
}
|
|
228
|
-
this.logger.debug(`Item ${i}: Using base64 from JSON field '${base64Field}' (${mimeType})`);
|
|
229
282
|
}
|
|
230
283
|
}
|
|
231
284
|
else {
|
|
232
285
|
// Extract from binary (default)
|
|
286
|
+
this.logger.debug(`VLM DEBUG INPUT [${i}]: Reading from binary, binaryField='${binaryField}', hasBinary=${!!item.binary}`);
|
|
233
287
|
if (item.binary) {
|
|
234
288
|
if (binaryField && item.binary[binaryField]) {
|
|
235
289
|
// Use specified binary field
|
|
@@ -238,7 +292,7 @@ class VLMComplexityWorkflow {
|
|
|
238
292
|
mimeType = data.mimeType || 'image/png';
|
|
239
293
|
rawBase64 = data.data;
|
|
240
294
|
base64Image = `data:${mimeType};base64,${rawBase64}`;
|
|
241
|
-
this.logger.debug(`
|
|
295
|
+
this.logger.debug(`VLM DEBUG INPUT [${i}]: Using specified binary field '${binaryField}' (${mimeType})`);
|
|
242
296
|
}
|
|
243
297
|
}
|
|
244
298
|
else {
|
|
@@ -249,7 +303,7 @@ class VLMComplexityWorkflow {
|
|
|
249
303
|
mimeType = data.mimeType;
|
|
250
304
|
rawBase64 = data.data;
|
|
251
305
|
base64Image = `data:${mimeType};base64,${rawBase64}`;
|
|
252
|
-
this.logger.debug(`
|
|
306
|
+
this.logger.debug(`VLM DEBUG INPUT [${i}]: Auto-detected image from binary '${binaryKey}' (${mimeType})`);
|
|
253
307
|
break;
|
|
254
308
|
}
|
|
255
309
|
}
|
|
@@ -257,7 +311,7 @@ class VLMComplexityWorkflow {
|
|
|
257
311
|
}
|
|
258
312
|
}
|
|
259
313
|
if (!base64Image) {
|
|
260
|
-
this.logger.warn(`
|
|
314
|
+
this.logger.warn(`VLM WARNING [${i}]: No image found (imageSource=${imageSource})`);
|
|
261
315
|
}
|
|
262
316
|
// Classify the document
|
|
263
317
|
const classification = await (0, vlm_logic_1.classifySingleDocument)(this, {
|
|
@@ -265,9 +319,14 @@ class VLMComplexityWorkflow {
|
|
|
265
319
|
base64Image,
|
|
266
320
|
timeout,
|
|
267
321
|
});
|
|
268
|
-
this.logger.debug(`
|
|
322
|
+
this.logger.debug(`VLM CLASSIFICATION [${i}]: ${classification.complexity} (confidence: ${classification.confidence}, model: ${classification.modelUsed})`);
|
|
269
323
|
// Determine base64 output value based on format preference
|
|
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'}`);
|
|
270
328
|
const outputBase64Value = outputBase64Format === 'raw' ? rawBase64 : base64Image;
|
|
329
|
+
this.logger.debug(`VLM DEBUG OUTPUT [${i}]: outputBase64Value prefix='${outputBase64Value === null || outputBase64Value === void 0 ? void 0 : outputBase64Value.substring(0, 40)}...'`);
|
|
271
330
|
// Build output item with BOTH json AND binary
|
|
272
331
|
const outputItem = {
|
|
273
332
|
json: {
|
|
@@ -294,7 +353,7 @@ class VLMComplexityWorkflow {
|
|
|
294
353
|
lowItems.push(outputItem);
|
|
295
354
|
}
|
|
296
355
|
}
|
|
297
|
-
this.logger.debug(`
|
|
356
|
+
this.logger.debug(`VLM COMPLETE: ${lowItems.length} LOW, ${highItems.length} HIGH`);
|
|
298
357
|
// Return dual outputs: [LOW, HIGH]
|
|
299
358
|
return [lowItems, highItems];
|
|
300
359
|
}
|
package/package.json
CHANGED