{
  "id": "JvH5loo41aV3kDJS",
  "meta": {
    "instanceId": "1107fae5d5743197ef5b14d25a71cb2ecbb17c99592f39736dd5384c6255b1f4"
  },
  "name": "CV Anonymization",
  "tags": [
    {
      "id": "7KpQ60aaqOmOSCWd",
      "name": "production",
      "createdAt": "2025-12-15T04:58:39.944Z",
      "updatedAt": "2025-12-15T04:58:39.944Z"
    },
    {
      "id": "e1Rw4nSdxQtYN5wl",
      "name": "recruitment",
      "createdAt": "2025-12-15T04:58:39.971Z",
      "updatedAt": "2025-12-15T04:58:39.971Z"
    },
    {
      "id": "8WEb52fbYUF71JRh",
      "name": "cv-anonymization",
      "createdAt": "2025-12-15T04:58:39.909Z",
      "updatedAt": "2025-12-15T04:58:39.909Z"
    }
  ],
  "nodes": [
    {
      "id": "25f4f988-2776-4afd-92e5-29cc85c94a67",
      "name": "Split PDF Pages1",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "POST: http://stirling-pdf:8080...",
      "position": [
        3568,
        432
      ],
      "parameters": {
        "url": "http://stirlingpdf:8080/api/v1/general/split-pages",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fileInput",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "pages",
              "value": "all"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "*/*"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "a27e6703-b38a-4aa2-97c0-9b0cf50271be",
      "name": "Compression",
      "type": "n8n-nodes-base.compression",
      "position": [
        3792,
        432
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9c5bc545-a718-4bcd-bbc4-c1563dfa616e",
      "name": "PDF → Text1",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "POST: http://stirling-pdf:8080...",
      "position": [
        4240,
        432
      ],
      "parameters": {
        "url": "http://stirlingpdf:8080/api/v1/convert/pdf/text",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fileInput",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "file_0"
            },
            {
              "name": "outputFormat",
              "value": "txt"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "*/*"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "95f97f37-7aa0-425f-b5b0-aa35789f1a66",
      "name": "Aggregate1",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        4688,
        432
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "pages"
      },
      "typeVersion": 1
    },
    {
      "id": "6f4b7c90-af7c-4ea9-857e-bac9bbff534d",
      "name": "Basic LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        4944,
        432
      ],
      "parameters": {
        "text": "={{ $json.pages.map(p => p.text).join('\\n\\n') }}",
        "messages": {
          "messageValues": [
            {
              "message": "=You are an expert CV anonymization system.\n\nCRITICAL TASK: Transform the CV text provided in the user message into a clean, anonymized, professionally formatted HTML document.\n\nLANGUAGE HANDLING — ABSOLUTE RULE:\n- The input CV may be written in ANY language.\n- The anonymized CV MUST remain FULLY in the ORIGINAL language of the input.\n\nANONYMIZATION RULES — FOLLOW EXACTLY:\n\n1. Replace ALL personally identifiable information with language-matching placeholders:\n   - Full names → localized equivalent of “[CANDIDATE NAME]”\n   - Email addresses → localized equivalent of “[EMAIL REDACTED]”\n   - Phone numbers → localized equivalent of “[PHONE REDACTED]”\n   - Full addresses → keep only country/region (localized)\n   - Specific city names → remove or replace with localized “[CITY]”\n   - Company names → localized descriptive replacements\n   - University / school names → localized “[TOP UNIVERSITY]” equivalent\n   - Client names → localized “[CLIENT NAME]” equivalent\n   - Any other personal names → localized “[NAME]”\n\n   IMPORTANT:\n   - Do NOT translate the CV.\n   - Use natural, professional wording in the CV’s language.\n   - Do NOT translate Placeholders.\n\n2. PRESERVE exactly as written from the input CV:\n   - Job titles\n   - Skills and technologies\n   - Years and dates\n   - Achievements and metrics\n   - Certifications (remove issuer name only)\n   - Work experience descriptions word-for-word\n   - Testimonials (names anonymized only)\n   - Original language, grammar, and writing style\n\nHTML STRUCTURE REQUIREMENTS:\n- Complete HTML5 document with <!DOCTYPE html>\n- Embedded CSS in <style> tag\n- Use Arial or sans-serif font family\n- Professional color scheme\n- Centered H1 using localized candidate name placeholder\n- Proper RTL support if the language requires it\n- Maximum width: 800px, centered layout\n\nOUTPUT FORMAT — CRITICAL:\nReturn ONLY a valid JSON object:\n{\"html\": \"complete HTML document as a single escaped string\"}\n\nFORMATTING RULES:\n- Escape all double quotes\n- Single continuous JSON string\n- NO markdown\n- NO comments\n- NO extra text\n\nVERIFICATION BEFORE RESPONDING:\n1. Language of output matches input CV exactly\n2. No English text appears unless the CV itself is English\n3. Placeholders are professional\n4. Skills, titles, and metrics are preserved\n5. Output is valid JSON with only the \"html\" key\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.4
    },
    {
      "id": "3730d74c-0831-4091-8825-cf67ea2dff3c",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        4912,
        656
      ],
      "parameters": {
        "model": "gpt-4-turbo",
        "options": {
          "maxTokens": 3000,
          "temperature": 0.3
        }
      },
      "typeVersion": 1
    },
    {
      "id": "177bee50-4cb7-409a-8fc7-757b6568ac09",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        5504,
        432
      ],
      "parameters": {
        "jsCode": "// Extract HTML from Structured Output Parser\nconst item = $input.first().json;\n\n// The HTML is at item.output.html\nlet htmlContent;\n\nif (item.output && item.output.html) {\n  htmlContent = item.output.html;\n} else {\n  throw new Error('No HTML found. Structure: ' + JSON.stringify(Object.keys(item)));\n}\n\n// Unescape the HTML (it comes with escaped quotes)\nhtmlContent = htmlContent\n  .replace(/\\\\\"/g, '\"')\n  .replace(/\\\\n/g, '\\n')\n  .trim();\n\n// Create binary file\nconst htmlBuffer = Buffer.from(htmlContent, 'utf-8');\nconst base64Data = htmlBuffer.toString('base64');\n\nreturn {\n  json: {\n    timestamp: new Date().toISOString()\n  },\n  binary: {\n    data: {\n      data: base64Data,\n      mimeType: 'text/html',\n      fileName: 'anonymized_cv.html',\n      fileExtension: 'html'\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "6f9d3d48-f811-449c-b466-eac7072af16d",
      "name": "Any File → PDF2",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5728,
        432
      ],
      "parameters": {
        "url": "http://root-stirlingpdf-1:8080/api/v1/convert/file/pdf",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fileInput",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "outputFormat",
              "value": "pdf"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "*/*"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "359ce35d-38f6-4b87-827b-59d494241e2e",
      "name": "Auto-fixing Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "position": [
        5040,
        656
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "ae060f63-f97f-43d1-98e6-bf22328d445e",
      "name": "OpenAI Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        5008,
        864
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "a5e6b875-91b4-4719-b77b-db35fdcb77b3",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        5136,
        864
      ],
      "parameters": {
        "autoFix": true,
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"html\": {\n      \"type\": \"string\",\n      \"description\": \"Complete anonymized HTML CV document\"\n    }\n  },\n  \"required\": [\"html\"],\n  \"additionalProperties\": false\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "e97dc72f-684b-44ad-b4fb-c8987fed1182",
      "name": "Any file to pdf",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2896,
        352
      ],
      "parameters": {
        "url": "http://stirlingpdf:8080/api/v1/convert/file/pdf",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fileInput",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "UploadCV0"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "*/*"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "77a52c63-37a1-4d08-856f-5b5fe68e7534",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        4016,
        432
      ],
      "parameters": {
        "jsCode": "// Prepare PDF binary data for Stirling PDF text extraction\nconst items = $input.all();\nconst results = [];\n\nfor (let i = 0; i < items.length; i++) {\n  const item = items[i];\n  \n  // Ensure the binary data is properly formatted\n  if (item.binary && item.binary.file_0) {\n    results.push({\n      json: {\n        ...item.json,\n        pageNumber: i + 1,\n        fileName: item.binary.file_0.fileName || `page_${i + 1}.pdf`\n      },\n      binary: {\n        file_0: item.binary.file_0\n      }\n    });\n  }\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "e0664377-8365-4fa2-9ffd-83f20d0b5738",
      "name": "OpenAI Chat Model2",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        5216,
        1072
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "831640d7-25d2-411f-a858-b158a69f0921",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "position": [
        4464,
        432
      ],
      "parameters": {
        "jsCode": "// Extract text from Stirling PDF response\nconst items = $input.all();\n\nreturn items.map(item => {\n  let extractedText = '';\n  \n  console.log('Processing item:', item.json.pageNumber);\n  console.log('Available keys:', Object.keys(item));\n  \n  // Method 1: Check if text is directly in json\n  if (item.json.text) {\n    extractedText = item.json.text;\n    console.log('Found text in json.text');\n  }\n  // Method 2: Check if text is in response field\n  else if (item.json.response) {\n    extractedText = item.json.response;\n    console.log('Found text in json.response');\n  }\n  // Method 3: Check if text is in output field  \n  else if (item.json.output) {\n    extractedText = item.json.output;\n    console.log('Found text in json.output');\n  }\n  // Method 4: Check binary data (if it exists)\n  else if (item.binary && item.binary.data) {\n    console.log('Checking binary data...');\n    console.log('Binary data type:', typeof item.binary.data);\n    \n    try {\n      // If binary.data is already a Buffer\n      if (Buffer.isBuffer(item.binary.data)) {\n        extractedText = item.binary.data.toString('utf-8');\n      }\n      // If binary.data is a base64 string\n      else if (typeof item.binary.data === 'string') {\n        extractedText = Buffer.from(item.binary.data, 'base64').toString('utf-8');\n      }\n      // If binary.data is an object with 'data' property\n      else if (item.binary.data.data) {\n        extractedText = Buffer.from(item.binary.data.data, 'base64').toString('utf-8');\n      }\n      console.log('Extracted from binary');\n    } catch (error) {\n      console.log('Binary conversion error:', error.message);\n    }\n  }\n  \n  console.log(`Text length: ${extractedText.length}`);\n  console.log(`First 200 chars: ${extractedText.substring(0, 200)}`);\n  \n  return {\n    json: {\n      text: extractedText,\n      pageNumber: item.json.pageNumber || 0,\n      filename: item.json.fileName || item.json.filename || 'unknown'\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "4f8ebb5e-ecd8-4253-9452-fe633cc3294e",
      "name": "Code in JavaScript2",
      "type": "n8n-nodes-base.code",
      "position": [
        3344,
        432
      ],
      "parameters": {
        "jsCode": "// Normalize binary field name to 'data'\nconst items = $input.all();\n\nreturn items.map(item => {\n  // If binary.data already exists, return as-is\n  if (item.binary && item.binary.data) {\n    return item;\n  }\n  \n  // If binary exists but not as 'data', rename it\n  if (item.binary) {\n    const binaryKeys = Object.keys(item.binary);\n    \n    if (binaryKeys.length > 0) {\n      const firstKey = binaryKeys[0]; // Get first binary field (file_0, UploadCV, etc.)\n      \n      return {\n        json: item.json,\n        binary: {\n          data: item.binary[firstKey] // Rename to 'data'\n        }\n      };\n    }\n  }\n  \n  // If no binary at all, return unchanged\n  return item;\n})"
      },
      "typeVersion": 2
    },
    {
      "id": "6e2844b7-b2f5-49bf-bc06-333b1fdd6001",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        2448,
        432
      ],
      "webhookId": "1faa18ed-f037-48a7-b1ff-ee9975836147",
      "parameters": {
        "path": "1faa18ed-f037-48a7-b1ff-ee9975836147",
        "options": {
          "binaryPropertyName": "UploadCV0"
        },
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "bd8a0ba2-41e7-4b29-aebf-abef148c4074",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        3120,
        432
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "aebde939-af4d-4156-88b5-0501e7dc3f37",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        5952,
        432
      ],
      "parameters": {
        "options": {},
        "respondWith": "binary"
      },
      "typeVersion": 1.5
    },
    {
      "id": "36b06d55-ee9d-46ee-abe8-6d2cc4a860bc",
      "name": "If1",
      "type": "n8n-nodes-base.if",
      "position": [
        2672,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "782f6cc8-edc8-45c8-b722-b0953e4c7889",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{$binary.UploadCV0.mimeType}}",
              "rightValue": "application/pdf"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9f0a5bbf-0b01-4142-9505-47f76fbf5367",
      "name": "CV Anonymization Workflow",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        80
      ],
      "parameters": {
        "width": 420,
        "height": 972,
        "content": "# CV Anonymization Workflow\n\nAutomatically removes personally identifiable information from CVs while preserving skills, experience, and achievements.\n\n### How it works\n\n1. **File Upload**: Webhook receives CV files (PDF, DOCX, etc.) via POST request\n2. **PDF Conversion**: Non-PDF files are converted to PDF format using Stirling PDF\n3. **Page Splitting**: Multi-page PDFs are split into individual pages for accurate processing\n4. **Text Extraction**: Each page is converted to plain text\n5. **AI Anonymization**: GPT-4 removes all PII (names, emails, phones, addresses) while maintaining original language and preserving job titles, skills, dates, and achievements\n6. **HTML Generation**: Creates professionally formatted HTML output with structured layout\n7. **PDF Output**: Converts anonymized HTML back to PDF and returns via webhook\n\n### Setup steps\n\n1. Configure OpenAI credentials for all three OpenAI Chat Model nodes\n2. Add Stirling PDF authorization headers to HTTP Request nodes (Any file to pdf, Split PDF Pages1, PDF → Text1, Any File → PDF2)\n3. Test webhook endpoint with sample CV file\n\n### Customization\n\n- Adjust anonymization rules in Basic LLM Chain system message\n- Modify HTML styling requirements in the prompt\n- Change GPT model versions for cost/quality tradeoffs"
      },
      "typeVersion": 1
    },
    {
      "id": "7762a961-3900-416b-bed6-69b4e1c3b1db",
      "name": "File Input & Conversion",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2352,
        320
      ],
      "parameters": {
        "color": 4,
        "width": 560,
        "height": 240,
        "content": "## File Input & Conversion\nWebhook receives files → If checks format → converts to PDF if needed"
      },
      "typeVersion": 1
    },
    {
      "id": "f02af0a2-86e1-45f9-8672-aba1c36aadce",
      "name": "PDF Processing & Text Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3264,
        288
      ],
      "parameters": {
        "color": 4,
        "width": 880,
        "height": 240,
        "content": "## PDF Processing & Text Extraction\nSplit pages → decompress → extract text from each page → aggregate all text"
      },
      "typeVersion": 1
    },
    {
      "id": "4f66f6eb-2916-496b-a139-a5553fe267f0",
      "name": "AI Anonymization1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4928,
        240
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 240,
        "content": "## AI Anonymization\nGPT-4 removes PII, preserves skills/experience, maintains original language, outputs structured HTML"
      },
      "typeVersion": 1
    },
    {
      "id": "e8c749e6-2635-41d4-b2d3-1373e15271eb",
      "name": "Output Generation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5504,
        288
      ],
      "parameters": {
        "color": 4,
        "width": 560,
        "height": 240,
        "content": "## Output Generation\nExtract HTML → convert to PDF → return via webhook"
      },
      "typeVersion": 1
    },
    {
      "id": "6b371946-aa02-4c7f-a6c3-d0e96cd0be0b",
      "name": "Stirling PDF Auth Required",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4176,
        272
      ],
      "parameters": {
        "color": 3,
        "width": 280,
        "height": 180,
        "content": "⚠️ STIRLING PDF AUTH REQUIRED\n\nAll 4 Stirling PDF HTTP nodes need Authorization headers configured before this workflow will function."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "35b0400e-b8ac-4e25-8558-f633995c36e8",
  "connections": {
    "If1": {
      "main": [
        [
          {
            "node": "Any file to pdf",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Any File → PDF2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Code in JavaScript2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "If1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate1": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compression": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF → Text1": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any file to pdf": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split PDF Pages1": {
      "main": [
        [
          {
            "node": "Compression",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any File → PDF2": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "PDF → Text1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Auto-fixing Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Structured Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "Aggregate1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript2": {
      "main": [
        [
          {
            "node": "Split PDF Pages1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Auto-fixing Output Parser",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Auto-fixing Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}