229 lines
6.9 KiB
JSON
229 lines
6.9 KiB
JSON
{
|
|
"name": "Receipt OCR Analysis",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "receipt-upload",
|
|
"responseMode": "responseNode",
|
|
"options": {}
|
|
},
|
|
"id": "webhook-receipt-upload",
|
|
"name": "Webhook - Receipt Upload",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 1,
|
|
"position": [250, 300],
|
|
"webhookId": "receipt-upload-webhook"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"assignments": {
|
|
"assignments": [
|
|
{
|
|
"id": "extract-image",
|
|
"name": "image",
|
|
"value": "={{ $json.body.image }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "extract-user-id",
|
|
"name": "userId",
|
|
"value": "={{ $json.body.userId }}",
|
|
"type": "string"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "extract-data",
|
|
"name": "Extract Receipt Data",
|
|
"type": "n8n-nodes-base.set",
|
|
"typeVersion": 1,
|
|
"position": [450, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"httpHeaderAuth": {
|
|
"name": "Authorization",
|
|
"value": "Bearer {{ $env.OCR_API_KEY }}"
|
|
},
|
|
"requestMethod": "POST",
|
|
"url": "https://api.ocr.space/parse/image",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "apikey",
|
|
"value": "={{ $env.OCR_API_KEY }}"
|
|
},
|
|
{
|
|
"name": "base64Image",
|
|
"value": "={{ $json.image }}"
|
|
},
|
|
{
|
|
"name": "language",
|
|
"value": "eng"
|
|
},
|
|
{
|
|
"name": "isOverlayRequired",
|
|
"value": "false"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "ocr-api-call",
|
|
"name": "OCR API Call",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 1,
|
|
"position": [650, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "// Extract text from OCR response\nconst ocrResponse = $input.item.json;\nconst parsedText = ocrResponse.ParsedResults?.[0]?.ParsedText || '';\n\n// Regular expressions to extract receipt data\nconst amountRegex = /(?:total|amount|sum|\\$|€|£)\\s*:?\\s*([\\d,]+\\.[\\d]{2})/i;\nconst dateRegex = /(\\d{1,2}[\\/\\-]\\d{1,2}[\\/\\-]\\d{2,4})/;\nconst vendorRegex = /^([A-Z][A-Za-z\\s&]+?)(?:\\s|$)/m;\nconst taxRegex = /(?:tax|vat|gst)\\s*:?\\s*([\\d,]+\\.[\\d]{2})/i;\n\n// Extract amount\nlet amount = null;\nconst amountMatch = parsedText.match(amountRegex);\nif (amountMatch) {\n amount = parseFloat(amountMatch[1].replace(/,/g, ''));\n}\n\n// Extract date\nlet date = null;\nconst dateMatch = parsedText.match(dateRegex);\nif (dateMatch) {\n date = dateMatch[1];\n}\n\n// Extract vendor (first line or company name)\nlet vendor = null;\nconst vendorMatch = parsedText.match(vendorRegex);\nif (vendorMatch) {\n vendor = vendorMatch[1].trim();\n}\n\n// Extract tax\nlet tax = null;\nconst taxMatch = parsedText.match(taxRegex);\nif (taxMatch) {\n tax = parseFloat(taxMatch[1].replace(/,/g, ''));\n}\n\n// Calculate confidence score based on extracted data\nlet confidence = 0;\nif (amount) confidence += 0.4;\nif (date) confidence += 0.2;\nif (vendor) confidence += 0.2;\nif (tax) confidence += 0.2;\n\nreturn {\n json: {\n userId: $input.item.json.userId,\n originalImage: $input.item.json.image,\n extractedText: parsedText,\n amount: amount,\n date: date,\n vendor: vendor,\n tax: tax || 0,\n confidence: confidence,\n status: confidence >= 0.6 ? 'needs_review' : 'pending',\n ocrRawResponse: ocrResponse\n }\n};"
|
|
},
|
|
"id": "parse-receipt-data",
|
|
"name": "Parse Receipt Data",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 1,
|
|
"position": [850, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"httpHeaderAuth": {
|
|
"name": "Authorization",
|
|
"value": "Bearer {{ $env.BACKEND_API_KEY }}"
|
|
},
|
|
"requestMethod": "POST",
|
|
"url": "={{ $env.BACKEND_API_URL }}/api/receipts",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "userId",
|
|
"value": "={{ $json.userId }}"
|
|
},
|
|
{
|
|
"name": "amount",
|
|
"value": "={{ $json.amount }}"
|
|
},
|
|
{
|
|
"name": "date",
|
|
"value": "={{ $json.date }}"
|
|
},
|
|
{
|
|
"name": "vendor",
|
|
"value": "={{ $json.vendor }}"
|
|
},
|
|
{
|
|
"name": "tax",
|
|
"value": "={{ $json.tax }}"
|
|
},
|
|
{
|
|
"name": "confidence",
|
|
"value": "={{ $json.confidence }}"
|
|
},
|
|
{
|
|
"name": "status",
|
|
"value": "={{ $json.status }}"
|
|
},
|
|
{
|
|
"name": "extractedText",
|
|
"value": "={{ $json.extractedText }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "save-to-backend",
|
|
"name": "Save to Backend",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 1,
|
|
"position": [1050, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ { \"success\": true, \"receiptId\": $json.id, \"amount\": $json.amount, \"confidence\": $json.confidence, \"status\": $json.status } }}"
|
|
},
|
|
"id": "respond-success",
|
|
"name": "Respond Success",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1,
|
|
"position": [1250, 300]
|
|
}
|
|
],
|
|
"connections": {
|
|
"Webhook - Receipt Upload": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Extract Receipt Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Extract Receipt Data": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "OCR API Call",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"OCR API Call": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse Receipt Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Parse Receipt Data": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Save to Backend",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Save to Backend": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Respond Success",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"pinData": {},
|
|
"settings": {
|
|
"executionOrder": "v1"
|
|
},
|
|
"staticData": null,
|
|
"tags": [],
|
|
"triggerCount": 1,
|
|
"updatedAt": "2024-01-01T00:00:00.000Z",
|
|
"versionId": "1"
|
|
}
|
|
|
|
|