Stirling-PDF/frontend/src/utils/automationExecutor.ts

158 lines
5.7 KiB
TypeScript
Raw Normal View History

import axios from 'axios';
import { ToolRegistry } from '../data/toolsTaxonomy';
import { AutomationConfig, AutomationExecutionCallbacks } from '../types/automation';
import { AUTOMATION_CONSTANTS } from '../constants/automation';
import { AutomationFileProcessor } from './automationFileProcessor';
import { ResourceManager } from './resourceManager';
/**
* Execute a tool operation directly without using React hooks
*/
export const executeToolOperation = async (
2025-08-18 15:45:05 +01:00
operationName: string,
parameters: any,
files: File[],
toolRegistry: ToolRegistry
): Promise<File[]> => {
console.log(`🔧 Executing tool: ${operationName}`, { parameters, fileCount: files.length });
2025-08-18 15:45:05 +01:00
const config = toolRegistry[operationName]?.operationConfig;
if (!config) {
console.error(`❌ Tool operation not supported: ${operationName}`);
throw new Error(`Tool operation not supported: ${operationName}`);
}
console.log(`📋 Using config:`, config);
try {
// Check if tool uses custom processor (like Convert tool)
if (config.customProcessor) {
console.log(`🎯 Using custom processor for ${config.operationType}`);
const resultFiles = await config.customProcessor(parameters, files);
console.log(`✅ Custom processor returned ${resultFiles.length} files`);
return resultFiles;
}
2025-08-18 15:45:05 +01:00
if (config.toolType === 'multiFile') {
// Multi-file processing - single API call with all files
2025-08-18 15:45:05 +01:00
const endpoint = typeof config.endpoint === 'function'
? config.endpoint(parameters)
: config.endpoint;
2025-08-18 15:45:05 +01:00
console.log(`🌐 Making multi-file request to: ${endpoint}`);
const formData = (config.buildFormData as (params: any, files: File[]) => FormData)(parameters, files);
console.log(`📤 FormData entries:`, Array.from(formData.entries()));
2025-08-18 15:45:05 +01:00
const response = await axios.post(endpoint, formData, {
responseType: 'blob',
timeout: AUTOMATION_CONSTANTS.OPERATION_TIMEOUT
});
console.log(`📥 Response status: ${response.status}, size: ${response.data.size} bytes`);
// Multi-file responses are typically ZIP files, but may be single files
const result = await AutomationFileProcessor.extractAutomationZipFiles(response.data);
2025-08-18 15:45:05 +01:00
if (result.errors.length > 0) {
console.warn(`⚠️ File processing warnings:`, result.errors);
}
2025-08-18 15:45:05 +01:00
console.log(`📁 Processed ${result.files.length} files from response`);
return result.files;
} else {
// Single-file processing - separate API call per file
console.log(`🔄 Processing ${files.length} files individually`);
const resultFiles: File[] = [];
2025-08-18 15:45:05 +01:00
for (let i = 0; i < files.length; i++) {
const file = files[i];
2025-08-18 15:45:05 +01:00
const endpoint = typeof config.endpoint === 'function'
? config.endpoint(parameters)
: config.endpoint;
2025-08-18 15:45:05 +01:00
console.log(`🌐 Making single-file request ${i+1}/${files.length} to: ${endpoint} for file: ${file.name}`);
const formData = (config.buildFormData as (params: any, file: File) => FormData)(parameters, file);
console.log(`📤 FormData entries:`, Array.from(formData.entries()));
2025-08-18 15:45:05 +01:00
const response = await axios.post(endpoint, formData, {
responseType: 'blob',
timeout: AUTOMATION_CONSTANTS.OPERATION_TIMEOUT
});
console.log(`📥 Response ${i+1} status: ${response.status}, size: ${response.data.size} bytes`);
// Create result file
const resultFile = ResourceManager.createResultFile(
2025-08-18 15:45:05 +01:00
response.data,
file.name,
AUTOMATION_CONSTANTS.FILE_PREFIX
);
resultFiles.push(resultFile);
console.log(`✅ Created result file: ${resultFile.name}`);
}
console.log(`🎉 Single-file processing complete: ${resultFiles.length} files`);
return resultFiles;
}
} catch (error: any) {
console.error(`Tool operation ${operationName} failed:`, error);
throw new Error(`${operationName} operation failed: ${error.response?.data || error.message}`);
}
};
/**
* Execute an entire automation sequence
*/
export const executeAutomationSequence = async (
2025-08-18 15:45:05 +01:00
automation: any,
initialFiles: File[],
toolRegistry: ToolRegistry,
onStepStart?: (stepIndex: number, operationName: string) => void,
onStepComplete?: (stepIndex: number, resultFiles: File[]) => void,
onStepError?: (stepIndex: number, error: string) => void
): Promise<File[]> => {
console.log(`🚀 Starting automation sequence: ${automation.name || 'Unnamed'}`);
console.log(`📁 Initial files: ${initialFiles.length}`);
console.log(`🔧 Operations: ${automation.operations?.length || 0}`);
2025-08-18 15:45:05 +01:00
if (!automation?.operations || automation.operations.length === 0) {
throw new Error('No operations in automation');
}
let currentFiles = [...initialFiles];
for (let i = 0; i < automation.operations.length; i++) {
const operation = automation.operations[i];
2025-08-18 15:45:05 +01:00
console.log(`📋 Step ${i + 1}/${automation.operations.length}: ${operation.operation}`);
console.log(`📄 Input files: ${currentFiles.length}`);
console.log(`⚙️ Parameters:`, operation.parameters || {});
2025-08-18 15:45:05 +01:00
try {
onStepStart?.(i, operation.operation);
2025-08-18 15:45:05 +01:00
const resultFiles = await executeToolOperation(
2025-08-18 15:45:05 +01:00
operation.operation,
operation.parameters || {},
currentFiles,
toolRegistry
);
2025-08-18 15:45:05 +01:00
console.log(`✅ Step ${i + 1} completed: ${resultFiles.length} result files`);
currentFiles = resultFiles;
onStepComplete?.(i, resultFiles);
2025-08-18 15:45:05 +01:00
} catch (error: any) {
console.error(`❌ Step ${i + 1} failed:`, error);
onStepError?.(i, error.message);
throw error;
}
}
console.log(`🎉 Automation sequence completed: ${currentFiles.length} final files`);
return currentFiles;
2025-08-18 15:45:05 +01:00
};