|
@@ -2,7 +2,7 @@
|
|
|
* @node ocr-upload
|
|
* @node ocr-upload
|
|
|
* @name OCR Upload
|
|
* @name OCR Upload
|
|
|
* @category ocr
|
|
* @category ocr
|
|
|
- * @version 1.0.1
|
|
|
|
|
|
|
+ * @version 1.2.0
|
|
|
* @description Upload a file for OCR processing via pdftoimageapi
|
|
* @description Upload a file for OCR processing via pdftoimageapi
|
|
|
* @icon file-scan
|
|
* @icon file-scan
|
|
|
*/
|
|
*/
|
|
@@ -10,6 +10,11 @@
|
|
|
const configSchema = {
|
|
const configSchema = {
|
|
|
type: 'object',
|
|
type: 'object',
|
|
|
properties: {
|
|
properties: {
|
|
|
|
|
+ fileSource: {
|
|
|
|
|
+ type: 'string',
|
|
|
|
|
+ title: 'File Source',
|
|
|
|
|
+ description: 'Path to file data (e.g., {{item.attachments[0]}} for loop iterations, or {{data.attachments[0]}} for direct input). Leave empty to auto-detect from input.'
|
|
|
|
|
+ },
|
|
|
baseUrl: {
|
|
baseUrl: {
|
|
|
type: 'string',
|
|
type: 'string',
|
|
|
title: 'API Base URL',
|
|
title: 'API Base URL',
|
|
@@ -90,7 +95,22 @@ const outputs = [
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
function isBinaryInput(input) {
|
|
function isBinaryInput(input) {
|
|
|
- return input && input.type === 'binary' && typeof input.data === 'string';
|
|
|
|
|
|
|
+ // Binary input can have either data (base64) or filePath (disk reference)
|
|
|
|
|
+ return input && input.type === 'binary' && (typeof input.data === 'string' || typeof input.filePath === 'string');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function resolveBinaryData(file) {
|
|
|
|
|
+ // If file has filePath, read from disk
|
|
|
|
|
+ if (file.filePath && !file.data) {
|
|
|
|
|
+ const readResult = smartbotic.fs.readFile(file.filePath, 'base64');
|
|
|
|
|
+ if (readResult.success) {
|
|
|
|
|
+ file.data = readResult.data;
|
|
|
|
|
+ smartbotic.log.info(`Loaded binary from disk: ${file.filePath}`);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new Error(`Failed to read file from disk: ${file.filePath} - ${readResult.error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return file;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function generateBoundary() {
|
|
function generateBoundary() {
|
|
@@ -156,29 +176,60 @@ module.exports = {
|
|
|
const baseUrl = (config.baseUrl || 'http://localhost:3000').replace(/\/$/, '');
|
|
const baseUrl = (config.baseUrl || 'http://localhost:3000').replace(/\/$/, '');
|
|
|
let file = null;
|
|
let file = null;
|
|
|
|
|
|
|
|
- if (isBinaryInput(input.file)) {
|
|
|
|
|
- file = input.file;
|
|
|
|
|
- } else if (isBinaryInput(input)) {
|
|
|
|
|
- file = input;
|
|
|
|
|
- } else if (input.storage && input.storage.collection && input.storage.id) {
|
|
|
|
|
- const storageResult = smartbotic.storage.get(input.storage.collection, input.storage.id);
|
|
|
|
|
- if (!storageResult.found) {
|
|
|
|
|
- throw new Error(`File not found in storage: ${input.storage.collection}/${input.storage.id}`);
|
|
|
|
|
|
|
+ // First priority: use configured fileSource if provided
|
|
|
|
|
+ // The expression (e.g., {{item.attachments[0]}}) is evaluated by the workflow engine,
|
|
|
|
|
+ // so config.fileSource contains the actual file object
|
|
|
|
|
+ if (config.fileSource && typeof config.fileSource === 'object') {
|
|
|
|
|
+ if (isBinaryInput(config.fileSource)) {
|
|
|
|
|
+ file = config.fileSource;
|
|
|
|
|
+ smartbotic.log.info('OCR Upload: Using configured file source');
|
|
|
|
|
+ } else if (Array.isArray(config.fileSource) && config.fileSource.length > 0) {
|
|
|
|
|
+ // If fileSource resolved to an array (e.g., attachments array), use first item
|
|
|
|
|
+ file = config.fileSource[0];
|
|
|
|
|
+ smartbotic.log.info(`OCR Upload: Using first item from configured file source array: ${file.filename}`);
|
|
|
}
|
|
}
|
|
|
- const doc = storageResult.document;
|
|
|
|
|
- file = {
|
|
|
|
|
- type: 'binary',
|
|
|
|
|
- data: doc.data,
|
|
|
|
|
- mimeType: doc.mimeType,
|
|
|
|
|
- filename: doc.filename,
|
|
|
|
|
- size: doc.size
|
|
|
|
|
- };
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Fallback: auto-detect from various input formats
|
|
|
if (!file) {
|
|
if (!file) {
|
|
|
- throw new Error('No file provided. Provide either a binary file object or a storage reference.');
|
|
|
|
|
|
|
+ if (isBinaryInput(input.file)) {
|
|
|
|
|
+ file = input.file;
|
|
|
|
|
+ } else if (isBinaryInput(input)) {
|
|
|
|
|
+ file = input;
|
|
|
|
|
+ } else if (input.data && isBinaryInput(input.data)) {
|
|
|
|
|
+ // Handle data wrapper from upstream nodes
|
|
|
|
|
+ file = input.data;
|
|
|
|
|
+ } else if (input.attachments && Array.isArray(input.attachments) && input.attachments.length > 0) {
|
|
|
|
|
+ // Handle output from IMAP Extract Attachments - use first attachment
|
|
|
|
|
+ file = input.attachments[0];
|
|
|
|
|
+ smartbotic.log.info(`Using first attachment from array: ${file.filename}`);
|
|
|
|
|
+ } else if (input.storage && input.storage.collection && input.storage.id) {
|
|
|
|
|
+ // Load from storage database (metadata with filePath)
|
|
|
|
|
+ const storageResult = smartbotic.storage.get(input.storage.collection, input.storage.id);
|
|
|
|
|
+ if (!storageResult.found) {
|
|
|
|
|
+ throw new Error(`File not found in storage: ${input.storage.collection}/${input.storage.id}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ const doc = storageResult.document;
|
|
|
|
|
+ file = {
|
|
|
|
|
+ type: 'binary',
|
|
|
|
|
+ filePath: doc.filePath, // Reference to disk location
|
|
|
|
|
+ mimeType: doc.mimeType,
|
|
|
|
|
+ filename: doc.filename,
|
|
|
|
|
+ size: doc.size
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (!file) {
|
|
|
|
|
+ // Log available input keys for debugging
|
|
|
|
|
+ const inputKeys = Object.keys(input || {}).join(', ');
|
|
|
|
|
+ smartbotic.log.warn(`OCR Upload: No binary file found. Input keys: ${inputKeys}`);
|
|
|
|
|
+ throw new Error('No file provided. Configure the "File Source" field with an expression like {{item.attachments[0]}} for loop iterations, or connect to IMAP Extract Attachments.');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Resolve file data from disk if needed
|
|
|
|
|
+ file = resolveBinaryData(file);
|
|
|
|
|
+
|
|
|
const headers = {};
|
|
const headers = {};
|
|
|
|
|
|
|
|
if (config.credentialId) {
|
|
if (config.credentialId) {
|