{
  "id": "usFtj9NVTTqcIUFw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "TyphoonV2.2 Multi-File & Multi-Page & with AI",
  "tags": [],
  "nodes": [
    {
      "id": "bcda99fe-5a10-4c43-af9d-3510ff00fb5e",
      "name": "When clicking \u2018Test workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        912,
        208
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "06b15c69-b854-4956-a6fc-3355f1a72427",
      "name": "Extract Text with Typhoon OCR",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        752,
        640
      ],
      "parameters": {
        "command": "=python -c \"import sys, os; os.environ['TYPHOON_OCR_API_KEY'] = '<Please update your Typhoon OCR>'; from typhoon_ocr import ocr_document; sys.stdout.reconfigure(encoding='utf-8'); input_path = sys.argv[1]; text = ocr_document(input_path); print(text)\" \"/doc/tmp/pages/{{$json[\"fileName\"]}}\"",
        "executeOnce": false
      },
      "typeVersion": 1
    },
    {
      "id": "1c8ac652-4ac9-424e-847b-5b845753c621",
      "name": "Load PDFs from doc Folder",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        1184,
        208
      ],
      "parameters": {
        "options": {},
        "fileSelector": "/doc/multipage/*"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "291f466a-3928-47bb-8cfb-48de2ad0256f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        176
      ],
      "parameters": {
        "width": 1352,
        "height": 968,
        "content": "## Thai OCR to Sheet (V2.2 \u2013 Multi-File & Multi-Page with AI)\n\nWorkflow \u0e19\u0e35\u0e49\u0e2d\u0e2d\u0e01\u0e41\u0e1a\u0e1a\u0e21\u0e32\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e1b\u0e23\u0e30\u0e21\u0e27\u0e25\u0e1c\u0e25\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23 PDF \u0e2b\u0e25\u0e32\u0e22\u0e44\u0e1f\u0e25\u0e4c\u0e17\u0e35\u0e48\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19\u0e42\u0e1f\u0e25\u0e40\u0e14\u0e2d\u0e23\u0e4c\u0e40\u0e14\u0e35\u0e22\u0e27\u0e01\u0e31\u0e19  \n\u0e23\u0e2d\u0e07\u0e23\u0e31\u0e1a\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23\u0e17\u0e35\u0e48\u0e21\u0e35\u0e2b\u0e25\u0e32\u0e22\u0e2b\u0e19\u0e49\u0e32 \u0e42\u0e14\u0e22\u0e08\u0e30\u0e41\u0e22\u0e01\u0e17\u0e38\u0e01\u0e2b\u0e19\u0e49\u0e32\u0e2d\u0e2d\u0e01\u0e21\u0e32\u0e41\u0e25\u0e49\u0e27\u0e17\u0e33 OCR \u0e17\u0e35\u0e25\u0e30\u0e2b\u0e19\u0e49\u0e32 \u0e08\u0e32\u0e01\u0e19\u0e31\u0e49\u0e19\u0e23\u0e27\u0e21\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21 \n\u0e41\u0e25\u0e30\u0e43\u0e0a\u0e49 AI \u0e41\u0e1b\u0e25\u0e07\u0e40\u0e19\u0e37\u0e49\u0e2d\u0e2b\u0e32\u0e43\u0e2b\u0e49\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a\u0e42\u0e04\u0e23\u0e07\u0e2a\u0e23\u0e49\u0e32\u0e07 \u0e01\u0e48\u0e2d\u0e19\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e25\u0e07 Google Sheet\n\n### \u0e01\u0e23\u0e30\u0e1a\u0e27\u0e19\u0e01\u0e32\u0e23\n1. **Load PDFs from doc Folder**  \n   \u0e14\u0e36\u0e07\u0e44\u0e1f\u0e25\u0e4c PDF \u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14\u0e08\u0e32\u0e01\u0e42\u0e1f\u0e25\u0e40\u0e14\u0e2d\u0e23\u0e4c\u0e17\u0e35\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\n\n2. **Loop Over Items**  \n   \u0e27\u0e19\u0e17\u0e33\u0e07\u0e32\u0e19\u0e17\u0e35\u0e25\u0e30\u0e44\u0e1f\u0e25\u0e4c \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e43\u0e2b\u0e49 process \u0e04\u0e23\u0e1a\u0e17\u0e38\u0e01\u0e44\u0e1f\u0e25\u0e4c\n\n3. **Write File to Disk**  \n   \u0e40\u0e02\u0e35\u0e22\u0e19\u0e44\u0e1f\u0e25\u0e4c\u0e25\u0e07\u0e14\u0e34\u0e2a\u0e01\u0e4c\u0e0a\u0e31\u0e48\u0e27\u0e04\u0e23\u0e32\u0e27\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e43\u0e0a\u0e49 split \u0e41\u0e25\u0e30 OCR\n\n4. **Split PDF page**  \n   \u0e41\u0e22\u0e01\u0e44\u0e1f\u0e25\u0e4c PDF \u0e2d\u0e2d\u0e01\u0e21\u0e32\u0e40\u0e1b\u0e47\u0e19\u0e2b\u0e19\u0e49\u0e32 \u0e46\n\n5. **Read Splitted PDF Page**  \n   \u0e42\u0e2b\u0e25\u0e14\u0e44\u0e1f\u0e25\u0e4c\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e41\u0e15\u0e01\u0e2d\u0e2d\u0e01\u0e21\u0e32\n\n6. **Extract Text with Typhoon OCR**  \n   OCR \u0e17\u0e35\u0e25\u0e30\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e43\u0e2b\u0e49\u0e44\u0e14\u0e49\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e14\u0e34\u0e1a\u0e2d\u0e2d\u0e01\u0e21\u0e32\n\n7. **Aggregate**  \n   \u0e23\u0e27\u0e21\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e08\u0e32\u0e01\u0e17\u0e38\u0e01\u0e2b\u0e19\u0e49\u0e32\u0e02\u0e2d\u0e07\u0e44\u0e1f\u0e25\u0e4c\u0e19\u0e31\u0e49\u0e19\u0e40\u0e02\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e01\u0e31\u0e19 \u0e40\u0e1b\u0e47\u0e19\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e40\u0e14\u0e35\u0e22\u0e27\n\n8. **Structure Text to JSON with LLM**  \n   \u0e43\u0e0a\u0e49 AI/LLM \u0e0a\u0e48\u0e27\u0e22\u0e41\u0e22\u0e01\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e08\u0e32\u0e01\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e14\u0e34\u0e1a\u0e43\u0e2b\u0e49\u0e40\u0e1b\u0e47\u0e19 JSON \u0e17\u0e35\u0e48\u0e21\u0e35\u0e42\u0e04\u0e23\u0e07\u0e2a\u0e23\u0e49\u0e32\u0e07 \u0e40\u0e0a\u0e48\u0e19 \u0e27\u0e31\u0e19\u0e17\u0e35\u0e48 \u0e40\u0e25\u0e02\u0e17\u0e35\u0e48\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23 \u0e22\u0e2d\u0e14\u0e23\u0e27\u0e21 \u0e40\u0e1b\u0e47\u0e19\u0e15\u0e49\u0e19\n\n9. **Parse JSON to Sheet Format**  \n   \u0e41\u0e1b\u0e25\u0e07 JSON \u0e17\u0e35\u0e48\u0e44\u0e14\u0e49\u0e43\u0e2b\u0e49\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a row/column \u0e17\u0e35\u0e48\u0e2a\u0e2d\u0e14\u0e04\u0e25\u0e49\u0e2d\u0e07\u0e01\u0e31\u0e1a Google Sheet\n\n10. **Save to Google Sheet**  \n    \u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e25\u0e07\u0e43\u0e19 Google Sheet \u0e40\u0e1b\u0e47\u0e19 1 \u0e41\u0e16\u0e27\u0e15\u0e48\u0e2d 1 \u0e44\u0e1f\u0e25\u0e4c  \n    (\u0e41\u0e15\u0e48\u0e25\u0e30 field \u0e02\u0e2d\u0e07 JSON \u0e08\u0e30\u0e16\u0e39\u0e01\u0e41\u0e22\u0e01\u0e40\u0e1b\u0e47\u0e19 column)\n\n11. **Execute Command (Cleanup)**  \n    \u0e25\u0e1a\u0e44\u0e1f\u0e25\u0e4c temp \u0e41\u0e25\u0e30\u0e22\u0e49\u0e32\u0e22\u0e44\u0e1f\u0e25\u0e4c PDF \u0e17\u0e35\u0e48\u0e17\u0e33\u0e40\u0e2a\u0e23\u0e47\u0e08\u0e41\u0e25\u0e49\u0e27\u0e44\u0e1b\u0e40\u0e01\u0e47\u0e1a\u0e43\u0e19\u0e42\u0e1f\u0e25\u0e40\u0e14\u0e2d\u0e23\u0e4c `Completed`\n\n### \u0e2b\u0e21\u0e32\u0e22\u0e40\u0e2b\u0e15\u0e38\n- \u0e21\u0e35\u0e01\u0e32\u0e23\u0e43\u0e0a\u0e49 AI/LLM \u0e0a\u0e48\u0e27\u0e22\u0e08\u0e31\u0e14\u0e42\u0e04\u0e23\u0e07\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2d\u0e31\u0e15\u0e42\u0e19\u0e21\u0e31\u0e15\u0e34  \n- \u0e40\u0e2b\u0e21\u0e32\u0e30\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e07\u0e32\u0e19\u0e17\u0e35\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23 OCR \u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23\u0e2b\u0e25\u0e32\u0e22\u0e44\u0e1f\u0e25\u0e4c \u0e41\u0e25\u0e49\u0e27\u0e41\u0e22\u0e01\u0e1c\u0e25\u0e25\u0e31\u0e1e\u0e18\u0e4c\u0e43\u0e2b\u0e49\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a column \u0e17\u0e35\u0e48\u0e2d\u0e48\u0e32\u0e19\u0e07\u0e48\u0e32\u0e22  \n- \u0e1c\u0e25\u0e25\u0e31\u0e1e\u0e18\u0e4c: PDF \u0e2b\u0e19\u0e36\u0e48\u0e07\u0e44\u0e1f\u0e25\u0e4c \u2192 1 \u0e41\u0e16\u0e27\u0e43\u0e19 Google Sheet \u0e42\u0e14\u0e22\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e16\u0e39\u0e01\u0e41\u0e22\u0e01\u0e2d\u0e2d\u0e01\u0e40\u0e1b\u0e47\u0e19\u0e2b\u0e25\u0e32\u0e22 column \u0e15\u0e32\u0e21\u0e1f\u0e34\u0e25\u0e14\u0e4c\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d585efcd-9b42-4bea-b128-1e0042e6b67f",
      "name": "Read/Write Files from Disk",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        848,
        416
      ],
      "parameters": {
        "options": {},
        "fileName": "/doc/tmp/in.pdf",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "8fff15da-ea36-4b56-83da-011ae227964b",
      "name": "Set_Input_Path",
      "type": "n8n-nodes-base.code",
      "position": [
        1008,
        416
      ],
      "parameters": {
        "jsCode": "// \u0e23\u0e31\u0e1a items \u0e08\u0e32\u0e01\u0e42\u0e2b\u0e19\u0e14\u0e01\u0e48\u0e2d\u0e19\u0e2b\u0e19\u0e49\u0e32 \u0e41\u0e25\u0e49\u0e27\u0e40\u0e15\u0e34\u0e21\u0e1f\u0e34\u0e25\u0e14\u0e4c inputPath \u0e43\u0e2b\u0e49\u0e40\u0e23\u0e35\u0e22\u0e1a\u0e23\u0e49\u0e2d\u0e22\n// \u0e01\u0e15\u0e34\u0e01\u0e32: \u0e43\u0e0a\u0e49 filePath \u0e16\u0e49\u0e32\u0e21\u0e35; \u0e16\u0e49\u0e32\u0e44\u0e21\u0e48\u0e21\u0e35 \u0e43\u0e2b\u0e49\u0e1b\u0e23\u0e30\u0e01\u0e2d\u0e1a\u0e08\u0e32\u0e01 directory + fileName; \u0e16\u0e49\u0e32\u0e44\u0e21\u0e48\u0e21\u0e35 directory \u0e01\u0e47\u0e43\u0e0a\u0e49 fileName\nreturn items.map(({ json, binary }) => {\n  const filePath =\n    json.filePath\n      ? json.filePath\n      : (json.directory\n          ? `${json.directory.replace(/\\/$/, '')}/${json.fileName}`\n          : json.fileName);\n\n  return {\n    json: {\n      ...json,\n      inputPath: filePath,\n    },\n    binary, // \u0e40\u0e1c\u0e37\u0e48\u0e2d\u0e2d\u0e22\u0e32\u0e01\u0e1e\u0e01 binary \u0e15\u0e48\u0e2d\u0e44\u0e1b\u0e14\u0e49\u0e27\u0e22\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e4d8e648-e26b-4707-adf5-525e88a09ec8",
      "name": "Split PDF page",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1184,
        416
      ],
      "parameters": {
        "command": "=sh -lc '\nset -e\nIN=\"{{ $json.inputPath }}\"\nOUT=\"/doc/tmp/pages\"\nrm -rf \"$OUT\" && mkdir -p \"$OUT\"\n\n# \u0e19\u0e31\u0e1a\u0e08\u0e33\u0e19\u0e27\u0e19\u0e2b\u0e19\u0e49\u0e32 (\u0e15\u0e49\u0e2d\u0e07\u0e21\u0e35 poppler-utils)\nPAGES=$(pdfinfo \"$IN\" 2>/dev/null | awk -F\": *\" \"/^Pages/{print \\$2}\")\n[ -n \"$PAGES\" ] || { echo \"Cannot detect page count for: $IN\" >&2; exit 1; }\n\npdfseparate -f 1 -l \"$PAGES\" \"$IN\" \"$OUT/page_%d.pdf\"\nls -1 \"$OUT\"/page_*.pdf\n'\n",
        "executeOnce": false
      },
      "typeVersion": 1
    },
    {
      "id": "57bb55c3-07e2-4ace-9678-8fafd5b420c6",
      "name": "Read Splite PDF Page",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        1360,
        416
      ],
      "parameters": {
        "options": {},
        "fileSelector": "/doc/tmp/pages/*.pdf"
      },
      "typeVersion": 1
    },
    {
      "id": "33589105-6b44-4d83-bd68-50b381d681e1",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        944,
        640
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "stdout"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a65d7907-3744-4629-a8fa-37c36b31e3f3",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        672,
        400
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "eadb2b7e-4ad3-4a46-8ecd-da1702470f1a",
      "name": "Parse JSON to Sheet Format",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        864
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const raw = $json[\"text\"];\n\n// 1. \u0e25\u0e1a ```json \u0e41\u0e25\u0e30 ``` \u0e17\u0e35\u0e48 LLM \u0e2d\u0e32\u0e08\u0e43\u0e2a\u0e48\u0e21\u0e32\nconst cleaned = raw.replace(/```json\\n?|```/g, \"\").trim();\n\nlet parsed;\ntry {\n  // 2. \u0e41\u0e1b\u0e25\u0e07\u0e40\u0e1b\u0e47\u0e19 object\n  parsed = JSON.parse(cleaned);\n} catch (err) {\n  throw new Error(\"JSON parsing failed: \" + err.message + \"\\n\\nRaw text:\\n\" + cleaned);\n}\n\n// 3. \u0e2b\u0e32\u0e01 contact \u0e40\u0e1b\u0e47\u0e19 object \u0e41\u0e22\u0e01 field \u0e2d\u0e2d\u0e01\u0e21\u0e32\nconst contact = parsed.contact || {};\n\nreturn {\n  book_id: parsed.book_id || \"\",\n  date: parsed.date || \"\",\n  subject: parsed.subject || \"\",\n  to: parsed.to || \"\",\n  attach: parsed.attach || \"\",\n  detail: parsed.detail || \"\",\n  signed_by: parsed.signed_by || \"\",\n  signed_by2: parsed.signed_by2 || \"\",\n  contact_phone: contact.phone || \"\",\n  contact_email: contact.email || \"\",\n  contact_fax: contact.fax || \"\",\n  download_url: parsed.download_url || \"\"\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8f2fb4c3-bbb3-49aa-8796-f85219241f47",
      "name": "Structure Text to JSON with LLM",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1136,
        640
      ],
      "parameters": {
        "text": "=\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07\u0e19\u0e35\u0e49\u0e40\u0e1b\u0e47\u0e19\u0e40\u0e19\u0e37\u0e49\u0e2d\u0e2b\u0e32 OCR \u0e08\u0e32\u0e01\u0e2b\u0e19\u0e31\u0e07\u0e2a\u0e37\u0e2d\u0e23\u0e32\u0e0a\u0e01\u0e32\u0e23 \u0e01\u0e23\u0e38\u0e13\u0e32\u0e41\u0e22\u0e01\u0e2b\u0e31\u0e27\u0e02\u0e49\u0e2d\u0e2a\u0e33\u0e04\u0e31\u0e0d\u0e2d\u0e2d\u0e01\u0e21\u0e32\u0e43\u0e19\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a JSON:\n\n1. book_id: \u0e40\u0e25\u0e02\u0e17\u0e35\u0e48\u0e2b\u0e19\u0e31\u0e07\u0e2a\u0e37\u0e2d\n2. date: \u0e27\u0e31\u0e19\u0e17\u0e35\u0e48\u0e43\u0e19\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23\n3. subject: \u0e2b\u0e31\u0e27\u0e40\u0e23\u0e37\u0e48\u0e2d\u0e07\n4. to: \u0e40\u0e23\u0e35\u0e22\u0e19\n5. attach: \u0e2a\u0e34\u0e48\u0e07\u0e17\u0e35\u0e48\u0e2a\u0e48\u0e07\u0e21\u0e32\u0e14\u0e49\u0e27\u0e22\n6. detail: \u0e40\u0e19\u0e37\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e43\u0e19\u0e2b\u0e19\u0e31\u0e07\u0e2a\u0e37\u0e2d\n7. signed_by: \u0e1c\u0e39\u0e49\u0e25\u0e07\u0e19\u0e32\u0e21\n8. signed_by2: \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e1c\u0e39\u0e49\u0e25\u0e07\u0e19\u0e32\u0e21\n9. contact: \u0e0a\u0e48\u0e2d\u0e07\u0e17\u0e32\u0e07\u0e15\u0e34\u0e14\u0e15\u0e48\u0e2d (\u0e40\u0e0a\u0e48\u0e19 \u0e40\u0e1a\u0e2d\u0e23\u0e4c\u0e42\u0e17\u0e23 \u0e2d\u0e35\u0e40\u0e21\u0e25)\n10. download_url: \u0e25\u0e34\u0e07\u0e01\u0e4c\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e14\u0e32\u0e27\u0e19\u0e4c\u0e42\u0e2b\u0e25\u0e14 (\u0e16\u0e49\u0e32\u0e21\u0e35)\n\nOCR_TEXT:\n\"\"\"\n{{ $json[\"stdout\"] }}\n\"\"\"",
        "promptType": "define"
      },
      "typeVersion": 1.6
    },
    {
      "id": "205beaeb-8532-4768-a2db-e4ab773a2fc8",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1136,
        784
      ],
      "parameters": {
        "model": "openai/gpt-4o-mini",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "aa0f180d-9ae8-4a09-ad09-d409d92b4c6b",
      "name": "Clear tmp files",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1248,
        864
      ],
      "parameters": {
        "command": "=sh -lc '\nset -e\n\n# \u0e25\u0e1a\u0e42\u0e1f\u0e25\u0e40\u0e14\u0e2d\u0e23\u0e4c temp \u0e17\u0e35\u0e48\u0e43\u0e0a\u0e49\u0e40\u0e01\u0e47\u0e1a\u0e44\u0e1f\u0e25\u0e4c\u0e17\u0e35\u0e48 split\nrm -rf /doc/tmp/pages\n\n# \u0e22\u0e49\u0e32\u0e22\u0e44\u0e1f\u0e25\u0e4c\u0e15\u0e49\u0e19\u0e09\u0e1a\u0e31\u0e1a (input PDF) \u0e44\u0e1b\u0e40\u0e01\u0e47\u0e1a\u0e44\u0e27\u0e49\u0e43\u0e19 Completed\nmkdir -p /doc/multipage/Completed\n\n# \u0e43\u0e0a\u0e49 $json.fileName \u0e02\u0e2d\u0e07 node \u0e15\u0e49\u0e19\u0e17\u0e32\u0e07 (Load PDFs from doc Folder)\n# \u0e16\u0e49\u0e32 fileName \u0e40\u0e1b\u0e47\u0e19 path \u0e2d\u0e22\u0e39\u0e48\u0e41\u0e25\u0e49\u0e27 \u0e43\u0e2b\u0e49 basename \u0e2d\u0e2d\u0e01\u0e21\u0e32\u0e01\u0e48\u0e2d\u0e19\nsrc=\"/doc/multipage/{{ $('Load PDFs from doc Folder').item.json.fileName }}\"\ndst=\"/doc/multipage/Completed/{{ $('Load PDFs from doc Folder').item.json.fileName }}\"\n\nmv \"$src\" \"$dst\"\necho \"Moved $src \u2192 $dst\"\n'\n"
      },
      "typeVersion": 1
    },
    {
      "id": "32acc4b4-3bb3-49d7-8a50-984e02f31077",
      "name": "Save to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        992,
        864
      ],
      "parameters": {
        "columns": {
          "value": {
            "to": "={{ $json.to }}",
            "date": "={{ $json.date }}",
            "attach": "={{ $json.attach }}",
            "detail": "={{ $json.detail }}",
            "book_id": "={{ $json.book_id }}",
            "subject": "={{ $json.subject }}",
            "signed_by": "={{ $json.signed_by }}",
            "signed_by2": "={{ $json.signed_by2 }}",
            "contact_fax": "={{ $json.contact_fax }}",
            "download_url": "={{ $json.download_url }}",
            "contact_email": "={{ $json.contact_email }}",
            "contact_phone": "={{ $json.contact_phone }}"
          },
          "schema": [
            {
              "id": "book_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "book_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "subject",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "subject",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "to",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "to",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "attach",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "attach",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "detail",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "detail",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "signed_by",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "signed_by",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "signed_by2",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "signed_by2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "contact_phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "contact_phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "contact_email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "contact_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "contact_fax",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "contact_fax",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "download_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "download_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "book_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1h70cJyLj5i2j0Ag5kqp93ccZjjhJnqpLmz-ee5r4brU/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1h70cJyLj5i2j0Ag5kqp93ccZjjhJnqpLmz-ee5r4brU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1h70cJyLj5i2j0Ag5kqp93ccZjjhJnqpLmz-ee5r4brU/edit?usp=drivesdk",
          "cachedResultName": "TyphoonOCR_Extracted_Data"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7166e717-0700-4f73-872d-a771d37b1e65",
  "connections": {
    "Aggregate": {
      "main": [
        [
          {
            "node": "Structure Text to JSON with LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set_Input_Path": {
      "main": [
        [
          {
            "node": "Split PDF page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split PDF page": {
      "main": [
        [
          {
            "node": "Read Splite PDF Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clear tmp files": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Read/Write Files from Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Splite PDF Page": {
      "main": [
        [
          {
            "node": "Extract Text with Typhoon OCR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Google Sheet": {
      "main": [
        [
          {
            "node": "Clear tmp files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Structure Text to JSON with LLM",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Load PDFs from doc Folder": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse JSON to Sheet Format": {
      "main": [
        [
          {
            "node": "Save to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read/Write Files from Disk": {
      "main": [
        [
          {
            "node": "Set_Input_Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Text with Typhoon OCR": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structure Text to JSON with LLM": {
      "main": [
        [
          {
            "node": "Parse JSON to Sheet Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Test workflow\u2019": {
      "main": [
        [
          {
            "node": "Load PDFs from doc Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}