{
  "id": "8gEQB8UrTY0j4VV2",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Extract Recipe Using Tesseract",
  "tags": [],
  "nodes": [
    {
      "id": "ecd439fe-ccbb-4653-9880-165a6f69426b",
      "name": "Format Summary Message",
      "type": "n8n-nodes-base.code",
      "position": [
        100,
        200
      ],
      "parameters": {
        "jsCode": "// Get input data from Parser node\nconst inputData = $input.all()[0].json.output || {};\n\n// Default values if data is incomplete\nconst store = inputData.store || { store_name: 'not available', store_location: 'not available' };\nconst transaction = inputData.transaction || { date: 'not available', time: 'not available' };\nconst items = inputData.items || [];\nconst summary = inputData.summary || { total: 'not available', payment_method: 'not available', expense_category: 'not available' };\n\n// Create message with available information\nlet message = '';\n\nif (store.store_name !== 'not available') {\n  message += `\ud83d\udccb Store: ${store.store_name}\\n`;\n}\nif (store.store_location !== 'not available') {\n  message += `\ud83d\udccd Location: ${store.store_location}\\n`;\n}\nif (transaction.date !== 'not available' || transaction.time !== 'not available') {\n  message += `\ud83d\udcc5 Date: ${transaction.date} ${transaction.time}\\n`;\n}\n\nif (items.length > 0) {\n  message += `\\n\ud83d\uded2 Items:\\n`;\n  items.forEach(item => {\n    message += `- ${item.description || 'not available'}: ${item.total_price || 'not available'}\\n`;\n  });\n}\n\nif (summary.total !== 'not available') {\n  if (parseFloat(summary.total) === 0) {\n    message = 'Looks like an input error, total is 0? Did you get this for free? Please check again.';\n  } else {\n    message += `\\n\ud83d\udcb8 Total: Rp ${summary.total}\\n`;\n  }\n}\n\nif (summary.expense_category !== 'not available' && parseFloat(summary.total) !== 0) {\n  message += `\ud83d\udccc Category: ${summary.expense_category}\\n`;\n}\n\n// Default message if no information is available\nif (!message) {\n  message = 'No information available from the input.';\n}\n\n// Return message as output\nreturn [\n  {\n    json: {\n      message: message\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "14a47f09-075d-47c6-a56f-8b44b2079e6e",
      "name": "Get Telegram File",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -600,
        -180
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{ $credentials.yourbottoken }}/getFile?file_id={{ $json.message.photo[3].file_id }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "8f50e858-6cbc-4999-bf27-6253fc0fcd41",
      "name": "Download Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -300,
        -180
      ],
      "parameters": {
        "url": "=https://api.telegram.org/file/bot{{ $credentials.yourbottoken }}/{{ $node['Get Telegram File'].json['result']['file_path'] }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "45b7b3c5-c6d4-45b6-8806-a0804b6a6551",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1280,
        0
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "721e7f94-27a4-4d93-b362-aa449e8404a9",
      "name": "Sticky - Telegram Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1280,
        -140
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "height": 180,
        "content": "## \ud83d\udcf2 **Telegram Trigger**\nReceives user messages (text or photo) from Telegram to start the expense tracking flow."
      },
      "typeVersion": 1
    },
    {
      "id": "563a242d-fe74-4d42-9a72-79cb2945acc9",
      "name": "AI Categorizer",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -200,
        200
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "messages": {
          "messageValues": [
            {
              "message": "=You are a financial planner expert with a robust parser algorithm. Category options are:\n- Income\n- Expense\n\nExpense options are:\n- Food & Beverages\n- Household\n- Transport\n\nInput may be in English, or Bahasa Indonesia. Always generate output in Input Language.\n\nAnalyze the input. If no expenses or income detected, return 'not found' and 0 for the total. If date is not specified, use {{ $('Telegram Trigger').item.json.message.date}}. For relative dates (e.g., yesterday, tomorrow), use {{ $('Telegram Trigger').item.json.message.date}} as the base. Example: yesterday is {{ $('Telegram Trigger').item.json.message.date}} - 1."
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.6
    },
    {
      "id": "b8db4655-b419-424f-b5e9-2111d5831507",
      "name": "Check Invalid Input",
      "type": "n8n-nodes-base.if",
      "position": [
        380,
        200
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b8408eb5-502b-48bf-b85d-3cea897f60b9",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.message }}",
              "rightValue": "Looks like an input error, total is 0? Did you get this for free? Please check again."
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "47efaf2d-23e9-43d9-bf82-1fa32b5e76fb",
      "name": "Extract Text Input",
      "type": "n8n-nodes-base.set",
      "position": [
        -600,
        200
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "aa52b49e-1087-4623-83cb-905500c36d3c",
              "name": "message",
              "type": "string",
              "value": "={{ $json.message.text }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "490fe4dc-5456-4f08-ace7-8ee9f4bc87fb",
      "name": "Check for Image",
      "type": "n8n-nodes-base.if",
      "position": [
        -980,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c5999c0e-853d-45e6-bec6-f446defe909d",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.photo }}",
              "rightValue": "="
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "970fe327-8b82-4d8c-9f81-b38deb768dd1",
      "name": "Sticky - Check for Image",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -980,
        -140
      ],
      "parameters": {
        "color": null,
        "height": 180,
        "content": "## \ud83d\udd0d **Check for Image**\nDetermines whether the input is an image or text to route accordingly."
      },
      "typeVersion": 1
    },
    {
      "id": "de5ac510-d757-449e-92cf-ad22976bf06d",
      "name": "Receipt Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -40,
        380
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"store\": {\n    \"store_name\": \"Store A\",\n    \"store_location\": \"Store location\"\n  },\n  \"transaction\": {\n    \"date\": \"Transaction date\",\n    \"time\": \"Transaction time\",\n    \"receipt_number\": \"Receipt number\"\n  },\n  \"items\": [\n    {\n      \"description\": \"Item name\",\n      \"quantity\": \"Quantity\",\n      \"unit_price\": \"Unit price\",\n      \"total_price\": \"Item total price\"\n    }\n  ],\n  \"summary\": {\n    \"total\": \"Total (number)\",\n    \"payment_method\": \"Payment method\",\n    \"expense_category\": \"Household\"\n  }\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "a2b4ffb7-abe8-4298-abee-8d14390ad242",
      "name": "AI Analyzer",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -200,
        380
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "aa36fb3b-fc38-419d-b520-7fd5cc474697",
      "name": "Send Error Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        700,
        180
      ],
      "parameters": {
        "text": "=hello  {{ $('Telegram Trigger').item.json.message.from.first_name }}\n\n{{ $json.message }}",
        "chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e1e9ecb9-c40f-4031-8d40-01ce7fb01ddc",
      "name": "Send Expense Summary",
      "type": "n8n-nodes-base.telegram",
      "position": [
        700,
        460
      ],
      "parameters": {
        "text": "=hello  {{ $('Telegram Trigger').item.json.message.from.first_name }}\n\nIni Rekap Belanjamu\n{{ $json.message }}",
        "chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d416dcad-b156-40c7-a0de-e46b268dd878",
      "name": "Sticky - Parse Receipt Data1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        680,
        -300
      ],
      "parameters": {
        "color": 4,
        "width": 360,
        "height": 200,
        "content": "## **MoneyMate is free to use!**\nGot feedback, ideas, or just wanna chat? Find me at [khmuhtadin.com](https://khmuhtadin.com).  \n\nWanna buy me a coffee to fuel more workflows? Head to [buymeacoffee.com/khmuhtadin](https://buymeacoffee.com/khmuhtadin)! \u2615"
      },
      "typeVersion": 1
    },
    {
      "id": "958bcce1-d9a2-4318-b6fd-47351631af7d",
      "name": "Extract Value From Image",
      "type": "n8n-nodes-tesseractjs.tesseractNode",
      "position": [
        20,
        -180
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "bf5e529b-f6a7-433c-bf91-1d6d55542766",
      "name": "Sticky - Send Expense Summary1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        700,
        360
      ],
      "parameters": {
        "color": null,
        "width": 340,
        "content": "## \ud83d\udcec **Send Expense Summary**\nSends a summary of the recognized receipt or input to the user's Telegram chat."
      },
      "typeVersion": 1
    },
    {
      "id": "482b1aca-67ff-4c5c-8201-35799a032990",
      "name": "Sticky - Extract Text Input1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -600,
        100
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "content": "## \ud83d\udcdd **Extract Text Input**\nHandles plain text inputs when no image is provided by the user."
      },
      "typeVersion": 1
    },
    {
      "id": "3a0e917f-acae-48ca-93ee-bc48b94c61e6",
      "name": "Sticky - Parse Receipt Data2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        500
      ],
      "parameters": {
        "color": null,
        "width": 300,
        "content": "## \ud83d\udcca **Parse Receipt Data**\nConverts AI output into structured JSON with store, transaction, items, and totals."
      },
      "typeVersion": 1
    },
    {
      "id": "4dc34baf-b732-47c2-932f-be2e67752cf2",
      "name": "Sticky - Get Telegram File1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -600,
        -280
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "content": "## \ud83d\udce6 **Get Telegram File**\nFetches the file ID of a receipt image uploaded via Telegram."
      },
      "typeVersion": 1
    },
    {
      "id": "62a9671e-ad05-40c3-9538-e0d5485c7978",
      "name": "Sticky - Download Image2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -300,
        -280
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "content": "## \u2b07\ufe0f **Download Image**\nDownloads the receipt photo and prepares it for text extraction."
      },
      "typeVersion": 1
    },
    {
      "id": "a4a22a9f-8035-4508-a0b6-b5e2cf95d309",
      "name": "Sticky - Download Image3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -280
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "content": "## \ud83d\uddbc\ufe0f **Text Extractor**\nExtract text from given image "
      },
      "typeVersion": 1
    },
    {
      "id": "c0e74e58-1e17-4ffd-8c01-870e8b750054",
      "name": "Sticky - Format Summary Message1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        100,
        80
      ],
      "parameters": {
        "color": null,
        "width": 260,
        "content": "## \ud83e\uddfe **Format Message**\nCreates a clear summary of expenses with store, date, items, total, and category."
      },
      "typeVersion": 1
    },
    {
      "id": "f5ec65f1-738b-42a2-9114-7b1c694887d1",
      "name": "Sticky - AI Categorizer1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -200,
        80
      ],
      "parameters": {
        "color": null,
        "width": 280,
        "content": "## \ud83e\udde0 **AI Categorizer**\nUses AI to classify input into categories like income or expenses, handling dates and languages."
      },
      "typeVersion": 1
    },
    {
      "id": "5758b4fc-34ce-4451-a328-71528995b28c",
      "name": "Sticky - Send Error Message1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        700,
        80
      ],
      "parameters": {
        "color": null,
        "width": 340,
        "content": "## \u2757 **Send Error Message**\nSends a warning to the user if the input is invalid or incomplete."
      },
      "typeVersion": 1
    },
    {
      "id": "d945a2b3-7c41-41fe-9d89-72f69a42229d",
      "name": "Sticky - Check Invalid Input1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        380,
        80
      ],
      "parameters": {
        "color": null,
        "width": 280,
        "content": "## \ud83d\udeab **Check Invalid Input**\nDetects and flags incorrect or zero-value entries before sending a response."
      },
      "typeVersion": 1
    },
    {
      "id": "101e18a0-1949-41f8-9826-dc2b5f1a2984",
      "name": "Sticky - OpenRouter AI Model1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        500
      ],
      "parameters": {
        "color": null,
        "width": 300,
        "content": "## \ud83e\udd16 **OpenRouter AI Model**\nConfigures the language model to extract structured information from natural language input."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e457070d-1c5c-4768-8749-1abe0a395fbe",
  "connections": {
    "AI Analyzer": {
      "ai_languageModel": [
        [
          {
            "node": "AI Categorizer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Categorizer": {
      "main": [
        [
          {
            "node": "Format Summary Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Image": {
      "main": [
        [
          {
            "node": "Extract Value From Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receipt Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Categorizer",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Check for Image": {
      "main": [
        [
          {
            "node": "Get Telegram File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Extract Text Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Check for Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Telegram File": {
      "main": [
        [
          {
            "node": "Download Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Text Input": {
      "main": [
        [
          {
            "node": "AI Categorizer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Invalid Input": {
      "main": [
        [
          {
            "node": "Send Error Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Expense Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Summary Message": {
      "main": [
        [
          {
            "node": "Check Invalid Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Value From Image": {
      "main": [
        [
          {
            "node": "AI Categorizer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}