8
n8n 中文网amn8n.com

银行对账单分析器 - 简化版

中级

这是一个Document Extraction, AI Summarization领域的自动化工作流,包含 9 个节点。主要使用 If, Code, OpenAi, Webhook, Postgres 等节点。 AI驱动银行对账单分析与交易分类

前置要求
  • OpenAI API Key
  • HTTP Webhook 端点(n8n 会自动生成)
  • PostgreSQL 数据库连接信息
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "name": "银行对账单分析器 - 简化版",
  "tags": [],
  "nodes": [
    {
      "id": "webhook-001",
      "name": "上传对账单",
      "type": "n8n-nodes-base.webhook",
      "position": [
        400,
        300
      ],
      "parameters": {
        "path": "/upload-statement",
        "options": {
          "rawBody": true
        },
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "file-handler-001",
      "name": "文件处理器",
      "type": "n8n-nodes-base.code",
      "position": [
        600,
        300
      ],
      "parameters": {
        "jsCode": "// Simple file processor\nconst inputData = $input.all()[0];\nconst files = [];\n\n// Handle file uploads\nif (inputData.binary) {\n  Object.keys(inputData.binary).forEach(key => {\n    const file = inputData.binary[key];\n    files.push({\n      filename: file.fileName,\n      contentType: file.mimeType,\n      uploadedAt: new Date().toISOString()\n    });\n  });\n}\n\nreturn files.map(file => ({\n  json: {\n    filename: file.filename,\n    contentType: file.contentType,\n    uploadedAt: file.uploadedAt,\n    status: 'ready_for_processing'\n  },\n  binary: inputData.binary\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "file-type-switch-001",
      "name": "检查文件类型",
      "type": "n8n-nodes-base.if",
      "position": [
        800,
        300
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "pdf-condition",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.contentType }}",
              "rightValue": "application/pdf"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "pdf-extractor-001",
      "name": "提取PDF文本",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1000,
        200
      ],
      "parameters": {
        "operation": "extractText"
      },
      "typeVersion": 1
    },
    {
      "id": "excel-parser-001",
      "name": "解析Excel/CSV",
      "type": "n8n-nodes-base.spreadsheetFile",
      "position": [
        1000,
        400
      ],
      "parameters": {
        "options": {
          "headerRow": 0
        },
        "operation": "parseExcel"
      },
      "typeVersion": 2
    },
    {
      "id": "ai-extractor-001",
      "name": "AI数据提取器",
      "type": "n8n-nodes-base.openAi",
      "position": [
        1200,
        300
      ],
      "parameters": {
        "model": "gpt-4o-mini",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "Extract bank statement data and return clean JSON:\n\n{\n  \"account_number\": \"****1234\",\n  \"bank_name\": \"Bank Name\",\n  \"statement_period\": \"2024-01-01 to 2024-01-31\",\n  \"opening_balance\": 1500.00,\n  \"closing_balance\": 1250.00,\n  \"transactions\": [\n    {\n      \"date\": \"2024-01-15\",\n      \"description\": \"GROCERY STORE\",\n      \"amount\": -45.67,\n      \"category\": \"groceries\"\n    }\n  ]\n}\n\nUse negative amounts for expenses, positive for income. Categorize transactions as: groceries, dining, gas, shopping, utilities, healthcare, entertainment, income, fees, or other."
            },
            {
              "role": "user",
              "content": "{{ $json.data || $json.extracted_text }}"
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "",
          "name": "OpenAI API"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "data-processor-001",
      "name": "处理与汇总",
      "type": "n8n-nodes-base.code",
      "position": [
        1400,
        300
      ],
      "parameters": {
        "jsCode": "// Clean and validate extracted data\nconst inputData = $input.all()[0];\nlet extractedData = {};\n\n// Parse AI response\ntry {\n  const content = inputData.json.message?.content || inputData.json;\n  if (typeof content === 'string') {\n    const jsonMatch = content.match(/{[\\s\\S]*}/);\n    if (jsonMatch) {\n      extractedData = JSON.parse(jsonMatch[0]);\n    }\n  } else {\n    extractedData = content;\n  }\n} catch (error) {\n  console.log('Parse error:', error.message);\n  extractedData = { transactions: [] };\n}\n\n// Clean transaction data\nconst cleanTransactions = (extractedData.transactions || []).map((tx, index) => ({\n  id: `tx_${Date.now()}_${index}`,\n  date: tx.date,\n  description: (tx.description || '').trim().toUpperCase(),\n  amount: parseFloat(tx.amount) || 0,\n  category: tx.category || 'other',\n  processed_at: new Date().toISOString()\n}));\n\n// Calculate summary\nconst totalExpenses = cleanTransactions\n  .filter(tx => tx.amount < 0)\n  .reduce((sum, tx) => sum + Math.abs(tx.amount), 0);\n\nconst totalIncome = cleanTransactions\n  .filter(tx => tx.amount > 0)\n  .reduce((sum, tx) => sum + tx.amount, 0);\n\nconst categoryTotals = {};\ncleanTransactions.forEach(tx => {\n  if (tx.amount < 0) { // Only expenses\n    categoryTotals[tx.category] = (categoryTotals[tx.category] || 0) + Math.abs(tx.amount);\n  }\n});\n\nreturn [{\n  json: {\n    account_info: {\n      account_number: extractedData.account_number || 'Unknown',\n      bank_name: extractedData.bank_name || 'Unknown',\n      statement_period: extractedData.statement_period || 'Unknown',\n      opening_balance: parseFloat(extractedData.opening_balance) || 0,\n      closing_balance: parseFloat(extractedData.closing_balance) || 0\n    },\n    transactions: cleanTransactions,\n    summary: {\n      total_transactions: cleanTransactions.length,\n      total_expenses: totalExpenses,\n      total_income: totalIncome,\n      net_change: totalIncome - totalExpenses,\n      category_breakdown: categoryTotals\n    },\n    processed_at: new Date().toISOString(),\n    status: 'completed'\n  }\n}]);"
      },
      "typeVersion": 2
    },
    {
      "id": "save-to-db-001",
      "name": "保存到数据库",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1600,
        200
      ],
      "parameters": {
        "table": "bank_statements",
        "columns": {
          "value": {
            "raw_data": "={{ JSON.stringify($json) }}",
            "bank_name": "={{ $json.account_info.bank_name }}",
            "processed_at": "={{ $json.processed_at }}",
            "total_income": "={{ $json.summary.total_income }}",
            "account_number": "={{ $json.account_info.account_number }}",
            "total_expenses": "={{ $json.summary.total_expenses }}",
            "statement_period": "={{ $json.account_info.statement_period }}",
            "total_transactions": "={{ $json.summary.total_transactions }}"
          },
          "mappingMode": "defineBelow"
        },
        "resource": "database",
        "operation": "insert"
      },
      "credentials": {
        "postgres": {
          "id": "",
          "name": "PostgreSQL"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "response-001",
      "name": "发送响应",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1600,
        400
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"success\": true,\n  \"message\": \"Statement processed successfully\",\n  \"data\": {\n    \"account\": \"{{ $json.account_info.account_number }}\",\n    \"transactions_processed\": {{ $json.summary.total_transactions }},\n    \"total_expenses\": {{ $json.summary.total_expenses }},\n    \"total_income\": {{ $json.summary.total_income }},\n    \"categories\": {{ JSON.stringify($json.summary.category_breakdown) }}\n  }\n}"
      },
      "typeVersion": 1
    }
  ],
  "notes": [
    {
      "id": "note-001",
      "width": 160,
      "height": 80,
      "content": "📥 **ENTRY POINT**\n\nUsers upload bank statements here via POST request",
      "position": [
        320,
        180
      ]
    },
    {
      "id": "note-002",
      "width": 160,
      "height": 100,
      "content": "🔍 **FILE PREP**\n\nExtracts file info and prepares for processing. Handles multiple file formats.",
      "position": [
        520,
        180
      ]
    },
    {
      "id": "note-003",
      "width": 160,
      "height": 120,
      "content": "🔀 **SMART ROUTING**\n\nPDFs go to text extraction\nExcel/CSV files go to spreadsheet parser\n\nAutomatic format detection",
      "position": [
        720,
        120
      ]
    },
    {
      "id": "note-004",
      "width": 160,
      "height": 90,
      "content": "📄 **PDF HANDLER**\n\nExtracts text from PDF bank statements using OCR",
      "position": [
        920,
        80
      ]
    },
    {
      "id": "note-005",
      "width": 160,
      "height": 90,
      "content": "📊 **SPREADSHEET HANDLER**\n\nParses Excel/CSV files and converts to structured data",
      "position": [
        920,
        480
      ]
    },
    {
      "id": "note-006",
      "width": 160,
      "height": 140,
      "content": "🤖 **AI MAGIC**\n\nGPT-4 extracts:\n• Account details\n• All transactions  \n• Auto-categorizes expenses\n• Calculates balances\n\nSmart & accurate!",
      "position": [
        1120,
        140
      ]
    },
    {
      "id": "note-007",
      "width": 160,
      "height": 120,
      "content": "🧹 **DATA CLEANUP**\n\nCleans & validates:\n• Transaction formatting\n• Amount calculations\n• Category summaries\n• Error handling",
      "position": [
        1320,
        140
      ]
    },
    {
      "id": "note-008",
      "width": 160,
      "height": 80,
      "content": "💾 **PERSISTENCE**\n\nSaves processed data to PostgreSQL database",
      "position": [
        1520,
        80
      ]
    },
    {
      "id": "note-009",
      "width": 160,
      "height": 100,
      "content": "✅ **SUCCESS RESPONSE**\n\nReturns summary:\n• Transaction count\n• Expense totals\n• Category breakdown",
      "position": [
        1520,
        480
      ]
    },
    {
      "id": "note-010",
      "width": 200,
      "height": 120,
      "content": "💡 **WORKFLOW FEATURES**\n\n✓ Handles PDF & Excel files\n✓ AI-powered extraction  \n✓ Auto-categorization\n✓ Database storage\n✓ Clean API responses",
      "position": [
        200,
        450
      ]
    },
    {
      "id": "note-011",
      "width": 180,
      "height": 140,
      "content": "🎯 **TYPICAL OUTPUT**\n\n```json\n{\n  \"success\": true,\n  \"transactions_processed\": 45,\n  \"total_expenses\": 2847.32,\n  \"categories\": {\n    \"groceries\": 450.23,\n    \"dining\": 287.45\n  }\n}\n```",
      "position": [
        1700,
        240
      ]
    }
  ],
  "pinData": {},
  "updatedAt": "2024-01-15T10:30:00.000Z",
  "versionId": "1",
  "staticData": null,
  "connections": {
    "File Handler": {
      "main": [
        [
          {
            "node": "Check File Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check File Type": {
      "main": [
        [
          {
            "node": "Extract PDF Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parse Excel/CSV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Excel/CSV": {
      "main": [
        [
          {
            "node": "AI Data Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract PDF Text": {
      "main": [
        [
          {
            "node": "AI Data Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Statement": {
      "main": [
        [
          {
            "node": "File Handler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Data Extractor": {
      "main": [
        [
          {
            "node": "Process & Summarize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process & Summarize": {
      "main": [
        [
          {
            "node": "Save to Database",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "triggerCount": 0
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

中级 - 文档提取, AI 摘要总结

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量9
分类2
节点类型8
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

外部链接
在 n8n.io 查看

分享此工作流