$ cat node-template.py

Test File Processor

// Accepts file inputs, processes them, and produces file outputs. Tests the full file pipeline.

Process
Utility
template.py
1import os2import sys3import json4import shutil5import traceback6from datetime import datetime78EXECUTION_CONTEXT = {9    "workspace_id": os.getenv("WORKSPACE_ID"),10    "node_id": os.getenv("NODE_ID"),11    "execution_id": os.getenv("EXECUTION_ID"),12}1314INPUT_DIR = "/data/input"15OUTPUT_DIR = "/data/output"161718def process_file(input_filename, output_filename):19    """20    Process a file: copy from input to output.21    In a real template this would apply transformations.22    """23    input_path = os.path.join(INPUT_DIR, input_filename)24    output_path = os.path.join(OUTPUT_DIR, output_filename)2526    if not os.path.exists(input_path):27        return None, f"Input file not found: {input_filename}"2829    # Copy file (real processing would transform the content)30    shutil.copy2(input_path, output_path)3132    size = os.path.getsize(output_path)33    return output_filename, f"Processed {input_filename} -> {output_filename} ({size} bytes)"343536def main():37    try:38        input_json = sys.stdin.read()39        execution_input = json.loads(input_json)4041        inputs = execution_input.get("inputs", {})42        suffix = inputs.get("suffix", "_processed")4344        os.makedirs(OUTPUT_DIR, exist_ok=True)4546        outputs = {}47        report_lines = []48        files_processed = 04950        # Process image51        image_input = inputs.get("image", "")52        if image_input:53            name, ext = os.path.splitext(image_input)54            out_name = f"{name}{suffix}{ext}"55            result, msg = process_file(image_input, out_name)56            if result:57                outputs["processed_image"] = result58                files_processed += 159            report_lines.append(msg)6061        # Process audio62        audio_input = inputs.get("audio", "")63        if audio_input:64            name, ext = os.path.splitext(audio_input)65            out_name = f"{name}{suffix}{ext}"66            result, msg = process_file(audio_input, out_name)67            if result:68                outputs["processed_audio"] = result69                files_processed += 170            report_lines.append(msg)7172        # Process video73        video_input = inputs.get("video", "")74        if video_input:75            name, ext = os.path.splitext(video_input)76            out_name = f"{name}{suffix}{ext}"77            result, msg = process_file(video_input, out_name)78            if result:79                outputs["processed_video"] = result80                files_processed += 181            report_lines.append(msg)8283        report = f"Processed {files_processed} file(s) with suffix '{suffix}'.\n"84        report += "\n".join(report_lines) if report_lines else "No files to process."85        outputs["report"] = report8687        # Log metadata to stderr88        print(f"Processed {files_processed} file(s) with suffix '{suffix}'", file=sys.stderr)8990        # Flat output — keys match OUTPUT_SCHEMA91        print(json.dumps(outputs, indent=2))9293    except Exception as e:94        error_output = {95            "error": str(e),96            "errorType": type(e).__name__,97            "traceback": traceback.format_exc(),98            "executionContext": EXECUTION_CONTEXT,99        }100        print(json.dumps(error_output), file=sys.stderr)101        sys.exit(1)102103104if __name__ == "__main__":105    main()