{
  "nodes": [
    {
      "id": "4f90c351-3a27-4cef-8165-84b81f339462",
      "name": "Mistral Cloud Chat Model4",
      "type": "@n8n/n8n-nodes-langchain.lmChatMistralCloud",
      "position": [
        -416,
        544
      ],
      "parameters": {
        "model": "mistral-medium-latest",
        "options": {
          "temperature": 0.7
        }
      },
      "typeVersion": 1
    },
    {
      "id": "02d5fb5f-8410-4d2a-9dc6-9a4e3964fa84",
      "name": "Simple Memory1",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -112,
        560
      ],
      "parameters": {
        "contextWindowLength": 15
      },
      "typeVersion": 1.3
    },
    {
      "id": "d09cc06a-b1a5-4d19-90c3-0c58add13b4f",
      "name": "Calculator1",
      "type": "@n8n/n8n-nodes-langchain.toolCalculator",
      "position": [
        160,
        560
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "ce7fb065-c77e-4b31-b98c-ac18abe4d983",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -1952,
        176
      ],
      "parameters": {
        "public": true,
        "options": {},
        "initialMessages": "hi this is cost estimate agent"
      },
      "typeVersion": 1.3
    },
    {
      "id": "54e74d07-150d-440f-a53e-9995baa5cff1",
      "name": "Send a message in Gmail",
      "type": "n8n-nodes-base.gmailTool",
      "position": [
        352,
        544
      ],
      "parameters": {
        "sendTo": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('To', ``, 'string') }}",
        "message": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}",
        "options": {},
        "subject": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "eb045f4b-b2e3-477c-8559-8398a886ca16",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2064,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 464,
        "content": "## Input endpoints\nWebhook and chat trigger receive user queries from website or n8n chat UI.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f868877e-a47e-4366-9800-424072efbdc9",
      "name": "ai agent cost estimate",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        96,
        176
      ],
      "parameters": {
        "text": "={{ $json.chatInput }}",
        "options": {
          "systemMessage": "=# Persona  \nYou are a helpful, intelligent **AI Cost Estimation & Catalog Assistant** for the **Fabrics & Surfaces** brand.  \nYou guide users \u2014 whether they upload a document, reference an existing order, or start fresh \u2014 through a smooth, conversational process to extract, confirm, and calculate costs.  \nYour role: stay proactive, transparent, and supportive from start to finish.\n\n---\n\n## Core Purpose\n- Help users estimate or verify costs for **fabrics** and **tiles**.  \n- Work seamlessly with both **OCR data (stored in Supabase)** and **manual user inputs**.  \n- Extract or retrieve structured data (vendor, line items, quantities, rates, totals).  \n- Perform **step-by-step cost calculations** using MATERIAL_COSTS and PROCESSING_COSTS.  \n- Confirm results conversationally and provide a clear cost summary.  \n- Escalate to human support through **Gmail** when required.\n\n---\n\n## Primary Duties\n1. **Detect Input Source**\n   - If OCR data exists in Supabase \u2192 retrieve, summarize, and confirm with user before calculating.  \n   - If the user uploads a new document \u2192 parse it via OCR, save to Supabase, then confirm details.  \n   - If no data exists \u2192 guide the user step-by-step to collect inputs interactively.\n\n2. **Conversational Confirmation**\n   - Always confirm material, dimensions, and quantity before final computation.  \n   - Ask only for missing or unclear data.  \n   - Rephrase numeric or technical values clearly (\u201cYou entered 150 cm width and 10 m length \u2014 correct?\u201d).\n\n3. **Computation**\n   - Use Calculator for all cost logic.  \n   - Apply formulas transparently (MATERIAL_COSTS, PROCESSING_COSTS).  \n   - Show each stage: base cost \u2192 add-ons \u2192 taxes \u2192 total.  \n   - Handle GSM \u2194 sqm and mm \u2194 sqm conversions automatically.\n\n4. **Output**\n   - Display itemized breakdown + total cost.  \n   - Include assumptions or substitutions if applied.  \n   - Offer next steps: **Save Quote**, **Email via Gmail**, or **Modify Inputs**.\n\n---\n\n## Conversation Flow\n1. **Greeting:**  \n   \u201cHi! I can help you estimate fabric or tile costs, review invoices, or create a new quote.  \n   Would you like me to use stored data, upload a bill, or start a new estimate?\u201d\n2. **Flow continues** depending on source:  \n   - *Stored Data*: Retrieve \u2192 summarize \u2192 confirm \u2192 calculate \u2192 show results.  \n   - *New Upload*: OCR extract \u2192 confirm \u2192 calculate \u2192 show results.  \n   - *Manual Entry*: Ask specs step-by-step \u2192 confirm \u2192 calculate \u2192 show results.\n3. **Always guide and explain:** never skip user interaction, even if data is complete.  \n\n---\n\n## Cost Rules\n\n### Fabric (per m or sqm)\n| Material | Base \u20ac/m | Add-ons \u20ac/m |\n|-----------|-----------|-------------|\n| Cotton | 2.5 | Printing 1.2 \u00b7 Hemming 0.5 |\n| Polyester | 2.0 | Coating 1.8 |\n| Linen | 6.0 | \u2013 |\n| Silk | 20.0 | \u2013 |\n| Wool | 10.0 | \u2013 |\n\nFormula:  \n`sqm = (width_cm / 100) \u00d7 length_m`  \n`total = sqm \u00d7 (base_rate + add_ons) + misc_costs`\n\n---\n\n### Tile (per sqm)\n| Type | \u20ac/sqm | Add-ons \u20ac/sqm |\n|-------|-------|---------------|\n| Ceramic | 8 | Glaze 2.5 |\n| Porcelain | 15 | Rectify 1.0 |\n| Stone | 30 | Seal 2.0 |\n\nFormula:  \n`area = pieces \u00d7 (L_mm \u00d7 W_mm / 1e6)`  \n`total = area \u00d7 (base + add_ons) + 10 (packaging)`\n\n---\n\n## Behavior\n- Always behave as a conversational guide, not just a calculator.  \n- Confirm, clarify, and educate users while computing results.  \n- If OCR data is present: use it, but still engage in dialogue.  \n- If OCR data is missing: guide user through completion.  \n- Automatically handle GSM, sqm, and area conversions.  \n- Clearly state any assumptions or corrections made.  \n- If the user asks for help or escalation \u2192 send a Gmail message summarizing context and results.  \n- Maintain a calm, precise, and professional tone throughout.\n\n---\n\n**End of prompt**\n",
          "returnIntermediateSteps": false
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "85b0230d-f7ce-43d1-b482-6468a25f1cc4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 288,
        "content": "## AI Agent\nGuides users through the cost estimation form for fabrics and tiles and runs calculations.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "dcc5f3ad-3a88-4fed-9d15-3d798d8eb46a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 256,
        "content": "## Tools: Calculator & Gmail\nCalculator: performs numeric calculations. Gmail: sends quotes or escalations to support.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "660ec177-6b8f-4591-a9e2-8be6edc8eedd",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2624,
        16
      ],
      "parameters": {
        "width": 416,
        "height": 624,
        "content": "## Cost Estimate Agent \u2014 Overview\n\n## How it works\n- Scans uploaded bills or receipts using OCR.  \n- Extracts key details like items, quantities, and prices.  \n- Calculates total cost and tax automatically.  \n- Estimates prices for fabrics and tiles based on size, finish, and material.  \n- Saves all parsed and computed data in Supabase.  \n- even  if no ocr data is present this  chat agent guide users through forms, show product info, and suggest alternatives.  \n- Core flow: **OCR \u2192 Parse / user query \u2192 Calculate \u2192 Store \u2192 Chat.**\n\n## Setup steps\n1. Add Google Drive (or other storage) and Supabase credentials.  \n2. Connect OCR and parsing nodes to handle PDF / image uploads.  \n3. Review material and processing cost tables in the calculator node; adjust values for your currency.  \n4. Test by uploading a sample invoice or selecting a fabric / tile in chat mode.  \n5. Verify results are written to the Supabase table, then enable the webhook or chat trigger for live use.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d41425c9-72a5-47e6-b1d4-00ee48725736",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        464
      ],
      "parameters": {
        "color": 7,
        "height": 192,
        "content": "### Memory \nStores short-term session context so the agent can recall prior user inputs "
      },
      "typeVersion": 1
    },
    {
      "id": "caa00085-20b6-46f4-84b5-61e9da0e0423",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 272,
        "height": 192,
        "content": "## Mistral Model\nHandles conversation logic for the cost estimation agent. "
      },
      "typeVersion": 1
    },
    {
      "id": "897a43ec-b434-41cd-aa4b-713bf05fa406",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1440,
        96
      ],
      "parameters": {
        "options": {
          "includeBinary": true,
          "destinationFieldName": "data"
        },
        "fieldToSplitOut": "$binary"
      },
      "typeVersion": 1
    },
    {
      "id": "0c8127b4-405d-452f-9874-e05e684d764d",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -176,
        144
      ],
      "parameters": {},
      "typeVersion": 3.1
    },
    {
      "id": "d6099fc1-790e-4bc1-8cb3-ebdc2ab488eb",
      "name": "CHECK IF BINARY FILE IS PRESENT OR NOT",
      "type": "n8n-nodes-base.if",
      "position": [
        -1664,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "463448a5-b323-4682-8674-24bee0df163b",
              "operator": {
                "type": "array",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.files }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "fde26d6a-7a41-443e-9973-f0d2c68ffde3",
      "name": "NORMALIZE binary file",
      "type": "n8n-nodes-base.code",
      "position": [
        -1216,
        96
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  const binaryKeys = Object.keys(item.binary || {});\n  const firstKey = binaryKeys[0];\n\n  if (!firstKey) {\n    return item;\n  }\n\n  return {\n    json: item.json,\n    binary: {\n      data: item.binary[firstKey]\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bae39571-4a46-40a3-8a5e-f8fd977cf72d",
      "name": "OCR (ANY OCR API )",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -736,
        -256
      ],
      "parameters": {
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "mode",
              "value": "single"
            },
            {
              "name": "output_type",
              "value": "jsonl"
            },
            {
              "name": "include_images",
              "value": "false"
            },
            {
              "name": "files",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5296f45c-fe21-4b06-adea-63bb93ece610",
      "name": "STORE OCR OUTPUT",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -320,
        80
      ],
      "parameters": {
        "tableId": "temp_table",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "session_id",
              "fieldValue": "={{ $('When chat message received').item.json.sessionId }}"
            },
            {
              "fieldId": "file",
              "fieldValue": "={{ $json.data[0].parseJson().blocks }}"
            },
            {
              "fieldId": "file_name",
              "fieldValue": "={{ $json.data[0].parseJson().source }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d580dab1-84ca-4e21-8d51-d451cd6851f8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -352
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 272,
        "content": "### use any ocr(mistral or own hosted ocr)"
      },
      "typeVersion": 1
    },
    {
      "id": "a1e5e3cc-e235-48c8-be61-babcd43dadc9",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1280,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 272,
        "content": "## normalize binary file name "
      },
      "typeVersion": 1
    },
    {
      "id": "c6fac97d-7110-4cf7-911d-10a03fe4a2b4",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -352,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 160,
        "height": 288,
        "content": "### store ocr output in supbase"
      },
      "typeVersion": 1
    },
    {
      "id": "822d5178-03f4-4553-bf53-83eb05f26cd8",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1728,
        48
      ],
      "parameters": {
        "color": 7,
        "height": 256,
        "content": "## check if user query have binary file or not ?"
      },
      "typeVersion": 1
    },
    {
      "id": "a577dfab-3f20-47bd-be7b-64c1cf0f85ec",
      "name": "Supabase Get",
      "type": "n8n-nodes-base.supabaseTool",
      "position": [
        720,
        528
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "session_id",
              "keyValue": "={{ $('When chat message received').item.json.sessionId }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "temp_table",
        "operation": "getAll"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "50fe88db-002a-49b6-a124-270a5e7d43ec",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 272,
        "height": 240,
        "content": "## get ocr output from supbase"
      },
      "typeVersion": 1
    },
    {
      "id": "15d4bfb8-d049-422c-8541-3bf7aaacedf7",
      "name": "Mistral Upload",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1008,
        96
      ],
      "parameters": {
        "url": "https://api.mistral.ai/v1/files",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "purpose",
              "value": "ocr"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9de46179-9b2d-4aca-8b4c-c3b8938e7646",
      "name": "Mistral Signed URL",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -768,
        96
      ],
      "parameters": {
        "url": "=https://api.mistral.ai/v1/files/{{ $json.id }}/url",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "expiry",
              "value": "24"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "49df803d-8805-483b-8598-a616c589edb2",
      "name": "Mistral DOC OCR",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -560,
        96
      ],
      "parameters": {
        "url": "https://api.mistral.ai/v1/ocr",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"mistral-ocr-latest\",\n  \"document\": {\n    \"type\": \"document_url\",\n    \"document_url\": \"{{ $json.url }}\"\n  },\n  \"include_image_base64\": true\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "db0b917c-8843-4061-a88f-d3263ec1d4b0",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 320,
        "content": "## MISTRAL OCR\n [OCR Guide](https://mistral.ai/news/mistral-ocr)\n1. UPLOAD FILE\n2. GET SIGNED URL\n3. GET EXTRACT DATA AFTER USING MISTRAL OCR"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "NORMALIZE binary file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculator1": {
      "ai_tool": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Get": {
      "ai_tool": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Upload": {
      "main": [
        [
          {
            "node": "Mistral Signed URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory1": {
      "ai_memory": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Mistral DOC OCR": {
      "main": [
        [
          {
            "node": "STORE OCR OUTPUT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "STORE OCR OUTPUT": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Signed URL": {
      "main": [
        [
          {
            "node": "Mistral DOC OCR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OCR (ANY OCR API )": {
      "main": [
        []
      ]
    },
    "NORMALIZE binary file": {
      "main": [
        [
          {
            "node": "Mistral Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send a message in Gmail": {
      "ai_tool": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Cloud Chat Model4": {
      "ai_languageModel": [
        [
          {
            "node": "ai agent cost estimate",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "CHECK IF BINARY FILE IS PRESENT OR NOT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CHECK IF BINARY FILE IS PRESENT OR NOT": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}