銀行取引明細書アナライザー - 簡易版

中級

これはDocument Extraction, AI Summarization分野の自動化ワークフローで、9個のノードを含みます。主にIf, Code, OpenAi, Webhook, Postgresなどのノードを使用。 AI駆動による銀行取引明細書の分析と取引分類

前提条件
  • OpenAI API Key
  • HTTP Webhookエンドポイント(n8nが自動生成)
  • PostgreSQLデータベース接続情報

カテゴリー

ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "name": "Bank Statement Analyzer - Simplified",
  "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-001": {
      "main": [
        [
          {
            "node": "file-type-switch-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "file-type-switch-001": {
      "main": [
        [
          {
            "node": "pdf-extractor-001",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "excel-parser-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "excel-parser-001": {
      "main": [
        [
          {
            "node": "ai-extractor-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "pdf-extractor-001": {
      "main": [
        [
          {
            "node": "ai-extractor-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "webhook-001": {
      "main": [
        [
          {
            "node": "file-handler-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ai-extractor-001": {
      "main": [
        [
          {
            "node": "data-processor-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "data-processor-001": {
      "main": [
        [
          {
            "node": "save-to-db-001",
            "type": "main",
            "index": 0
          },
          {
            "node": "response-001",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "triggerCount": 0
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

中級 - 文書抽出, AI要約

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
中級
ノード数9
カテゴリー2
ノードタイプ8
難易度説明

経験者向け、6-15ノードの中程度の複雑さのワークフロー

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34