{
  "name": "LINE Image Handler",
  "nodes": [
    {
      "parameters": {},
      "id": "execute-workflow-trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        250,
        300
      ],
      "notes": "\u89aa\u30ef\u30fc\u30af\u30d5\u30ed\u30fc\u304b\u3089\u547c\u3073\u51fa\u3055\u308c\u308b\u30c8\u30ea\u30ac\u30fc\uff08Image Event\u5c02\u7528\uff09"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "16qhVQNDn_5Y1Ayw_H0ziUw1nu2b70o6IcRn1rr4Pa94",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Master_User_Config",
          "mode": "name"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "line_user_id",
              "lookupValue": "={{ $('Execute Workflow Trigger').item.json.body.events[0].source.userId }}"
            }
          ]
        },
        "options": {}
      },
      "id": "lookup-user-config",
      "name": "\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        450,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "LINE\u30e6\u30fc\u30b6\u30fcID\u304b\u3089\u9867\u5ba2\u8a2d\u5b9a\u3092\u53d6\u5f97"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "condition-drive-folder-exists",
              "leftValue": "={{ $json.drive_folder_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            },
            {
              "id": "condition-sheet-exists",
              "leftValue": "={{ $json.sheet_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-user-exists",
      "name": "IF \u8a2d\u5b9a\u5b8c\u4e86",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        650,
        300
      ],
      "notes": "\u4eee\u767b\u9332\u30e6\u30fc\u30b6\u30fc\uff08drive_folder_id/sheet_id\u672a\u8a2d\u5b9a\uff09\u306f\u8a2d\u5b9a\u5f85\u3061\u30e1\u30c3\u30bb\u30fc\u30b8\u3078"
    },
    {
      "parameters": {
        "url": "=https://api-data.line.me/v2/bot/message/{{ $('Execute Workflow Trigger').item.json.body.events[0].message.id }}/content",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "get-image-node",
      "name": "Get LINE Image",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        850,
        200
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "LINE API\u304b\u3089\u753b\u50cf\u30d0\u30a4\u30ca\u30ea\u3092\u53d6\u5f97"
    },
    {
      "parameters": {
        "name": "={{ $now.format('yyyyMMdd_HHmmss') }}_{{ $('\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167').item.json.line_user_id }}.jpg",
        "driveId": {
          "__rl": true,
          "value": "My Drive",
          "mode": "list"
        },
        "folderId": {
          "__rl": true,
          "value": "={{ $('\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167').item.json.drive_folder_id }}",
          "mode": "id"
        },
        "options": {}
      },
      "id": "gdrive-upload-node",
      "name": "Google Drive Upload",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1050,
        200
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "\u9867\u5ba2\u5225\u30d5\u30a9\u30eb\u30c0\u306b\u4fdd\u5b58\uff08\u52d5\u7684\u632f\u308a\u5206\u3051\uff09"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.id }}",
          "mode": "id"
        },
        "options": {}
      },
      "id": "google-drive-download",
      "name": "Google Drive Download",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1150,
        200
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u305f\u753b\u50cf\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u30d0\u30a4\u30ca\u30ea\u30c7\u30fc\u30bf\u3092\u53d6\u5f97"
    },
    {
      "parameters": {
        "jsCode": "// Google Drive Download\u30ce\u30fc\u30c9\u304b\u3089\u30d0\u30a4\u30ca\u30ea\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\nconst binaryPropertyName = Object.keys($input.item.binary)[0];\nconst mimeType = $input.item.binary[binaryPropertyName].mimeType || 'image/jpeg';\n\n// n8n 2.4.0\u306efilesystem\u30e2\u30fc\u30c9\u3067\u306fgetBinaryDataBuffer()\u3092\u4f7f\u7528\nconst binaryBuffer = await this.helpers.getBinaryDataBuffer(0, binaryPropertyName);\nconst base64String = binaryBuffer.toString('base64');\n\n// Google Drive\u306eURL\uff08\u8a3c\u6191\u7528\uff09\nconst driveFileId = $('Google Drive Upload').item.json.id;\nconst driveUrl = `https://drive.google.com/uc?export=view&id=${driveFileId}`;\n\n// Base64\u5f62\u5f0f\u3067data URI\u3092\u69cb\u7bc9\nconst base64Image = `data:${mimeType};base64,${base64String}`;\n\n// OpenAI API\u30ea\u30af\u30a8\u30b9\u30c8\u30dc\u30c7\u30a3\u3092\u69cb\u7bc9\nconst requestBody = {\n  model: \"gpt-4o\",\n  messages: [\n    {\n      role: \"system\",\n      content: `\u3042\u306a\u305f\u306f\u7d4c\u7406\u306e\u5c02\u9580\u5bb6AI\u3067\u3059\u3002\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3055\u308c\u305f\u9818\u53ce\u66f8\u753b\u50cf\u304b\u3089JSON\u30c7\u30fc\u30bf\u3092\u62bd\u51fa\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n\n# \u30eb\u30fc\u30eb\n1. **transaction_date**: \u65e5\u4ed8\u3092 YYYY-MM-DD \u5f62\u5f0f\u3067\u62bd\u51fa\u3002\u8a18\u8f09\u304c\u306a\u3044\u5834\u5408\u306f null\u3002\n2. **merchant**: \u5e97\u8217\u540d\u30fb\u4f1a\u793e\u540d\u3092\u6b63\u78ba\u306b\u62bd\u51fa\u3002\n3. **amount**: \u5408\u8a08\u91d1\u984d\uff08\u6570\u5024\u306e\u307f\uff09\u3002\u30ab\u30f3\u30de\u3084\u5186\u30de\u30fc\u30af\u306f\u9664\u53bb\u3002\n4. **tax_amount**: \u6d88\u8cbb\u7a0e\u984d\uff08\u8a18\u8f09\u304c\u3042\u308c\u3070\uff09\u3002\n5. **invoice_number**: \"T\"\u304b\u3089\u59cb\u307e\u308b13\u6841\u306e\u767b\u9332\u756a\u53f7\u304c\u3042\u308c\u3070\u62bd\u51fa\u3002\u306a\u3051\u308c\u3070 null\u3002\n6. **description**: \u53d6\u5f15\u306e\u5185\u5bb9\uff08\u4f8b\uff1a\u99d0\u8eca\u5834\u4ee3\u3001\u98f2\u98df\u4ee3\uff09\u3002\u753b\u50cf\u5185\u306e\u6642\u9593\u60c5\u5831\u304c\u3042\u308c\u3070\u305d\u308c\u3082\u542b\u3081\u308b\u3002\n7. **category**: \u53d6\u5f15\u5185\u5bb9\u304b\u3089\u9069\u5207\u306a\u52d8\u5b9a\u79d1\u76ee\u3092\u63a8\u6e2c\u3057\u3066\u9078\u629e\u3002\n   - \u99d0\u8eca\u5834\u30fb\u30bf\u30af\u30b7\u30fc \u2192 \"\u65c5\u8cbb\u4ea4\u901a\u8cbb\"\n   - \u98f2\u98df\uff08\u6253\u3061\u5408\u308f\u305b\uff09 \u2192 \"\u4f1a\u8b70\u8cbb\"\n   - \u6587\u623f\u5177\u30fb\u6d88\u8017\u54c1 \u2192 \"\u6d88\u8017\u54c1\u8cbb\"\n   - \u66f8\u7c4d\u30fb\u30bb\u30df\u30ca\u30fc \u2192 \"\u7814\u4fee\u8cbb\"\n   - \u305d\u306e\u4ed6 \u2192 \"\u96d1\u8cbb\"\n8. **tax_rate**: \u6d88\u8cbb\u7a0e\u7387\uff08\u4f8b\uff1a10 \u307e\u305f\u306f 8\uff09\u3002\u8efd\u6e1b\u7a0e\u7387\u306b\u6ce8\u610f\u3002\n\n# \u51fa\u529b\u5f62\u5f0f\nJSON\u306e\u307f\u3092\u51fa\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u8aac\u660e\u6587\u306f\u4e0d\u8981\u3067\u3059\u3002\n\n{\n  \"transaction_date\": \"YYYY-MM-DD\",\n  \"merchant\": \"\u5e97\u8217\u540d\",\n  \"amount\": 1000,\n  \"tax_amount\": 100,\n  \"invoice_number\": \"T1234567890123\",\n  \"description\": \"\u99d0\u8eca\u5834\u4ee3\uff0816:02-17:15\uff09\",\n  \"category\": \"\u65c5\u8cbb\u4ea4\u901a\u8cbb\",\n  \"tax_rate\": 10\n}`\n    },\n    {\n      role: \"user\",\n      content: [\n        {\n          type: \"text\",\n          text: \"\u3053\u306e\u9818\u53ce\u66f8\u753b\u50cf\u304b\u3089\u60c5\u5831\u3092\u62bd\u51fa\u3057\u3066\u304f\u3060\u3055\u3044\u3002\"\n        },\n        {\n          type: \"image_url\",\n          image_url: {\n            url: base64Image\n          }\n        }\n      ]\n    }\n  ],\n  max_tokens: 500,\n  temperature: 0.2\n};\n\n// \u51fa\u529b\u30c7\u30fc\u30bf\nreturn {\n  json: {\n    requestBody: requestBody,\n    driveUrl: driveUrl\n  }\n};"
      },
      "id": "build-ocr-request-node",
      "name": "OCR\u30ea\u30af\u30a8\u30b9\u30c8\u69cb\u7bc9",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1250,
        200
      ],
      "notes": "\u753b\u50cf\u3092Base64\u30a8\u30f3\u30b3\u30fc\u30c9\u3057\u3066OpenAI API\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u69cb\u7bc9"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.requestBody }}",
        "options": {}
      },
      "id": "ai-ocr-node",
      "name": "AI-OCR\u51e6\u7406\uff08GPT-4o\uff09",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1450,
        200
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "notes": "gpt-4o\u3067\u753b\u50cf\u304b\u3089\u69cb\u9020\u5316\u30c7\u30fc\u30bf\u62bd\u51fa"
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "={{ $('\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167').item.json.sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc",
          "mode": "name"
        },
        "options": {
          "returnAllMatches": true
        }
      },
      "id": "get-knowledge-base-node",
      "name": "\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc\u53d6\u5f97",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        1650,
        200
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "\u9867\u5ba2\u5225\u52d8\u5b9a\u79d1\u76ee\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u3092\u53d6\u5f97",
      "continueOnFail": true,
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "jsCode": "// AI-OCR\u7d50\u679c\u3092\u30d1\u30fc\u30b9\nlet content = $('AI-OCR\u51e6\u7406\uff08GPT-4o\uff09').item.json.choices[0].message.content;\ncontent = content.replace(/^```json\\s*\\n?/, '').replace(/\\n?```\\s*$/, '').trim();\nconst ocrResult = JSON.parse(content);\n\nconst merchant = ocrResult.merchant || '';\nconst description = ocrResult.description || '';\n\n// \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u53d6\u5f97\uff08\u5168\u884c\uff09- \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u8ffd\u52a0\nlet knowledgeBase = [];\ntry {\n  const kbData = $('\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc\u53d6\u5f97').all();\n  // \u30c7\u30fc\u30bf\u304c\u5b58\u5728\u3057\u3001\u30a8\u30e9\u30fc\u3067\u306a\u3044\u5834\u5408\u306e\u307f\u4f7f\u7528\n  if (kbData && Array.isArray(kbData) && kbData.length > 0) {\n    // \u30a8\u30e9\u30fc\u30c7\u30fc\u30bf\uff08pairedItem\u304cnull\u306a\u3069\uff09\u3092\u30d5\u30a3\u30eb\u30bf\u30ea\u30f3\u30b0\n    knowledgeBase = kbData.filter(item => item && item.json && !item.error);\n  }\n} catch (error) {\n  // \u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u305f\u5834\u5408\u306f\u7a7a\u914d\u5217\u3068\u3057\u3066\u51e6\u7406\uff08AI\u63a8\u8ad6\u306b\u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\uff09\n  knowledgeBase = [];\n}\n\n// \u30de\u30c3\u30c1\u30f3\u30b0\u51e6\u7406\nlet matchedCategory = null;\nlet maxConfidence = 0;\nlet matchedRowId = null;\nlet matchedMerchantKeyword = null;\nlet matchedAccountCategory = null;\nlet matchedUsageCount = 0;\nlet matchedLastUsedDate = '';\nlet matchedConfidenceScore = 0;\n\nfor (let i = 0; i < knowledgeBase.length; i++) {\n  const rule = knowledgeBase[i].json;\n  const merchantKeyword = rule.merchant_keyword || '';\n  const descriptionKeyword = rule.description_keyword || '';\n  const confidence = parseInt(rule.confidence_score) || 0;\n  const rowNumber = i + 2; // \u30d8\u30c3\u30c0\u30fc\u884c\u3092\u9664\u304f\uff081\u884c\u76ee=\u30d8\u30c3\u30c0\u30fc\u30012\u884c\u76ee=\u6700\u521d\u306e\u30c7\u30fc\u30bf\uff09\n  \n  // \u5e97\u8217\u540d\u3067\u306e\u5b8c\u5168\u4e00\u81f4\uff08\u6700\u512a\u5148\uff09\n  if (merchantKeyword && merchant.includes(merchantKeyword)) {\n    if (confidence > maxConfidence) {\n      matchedCategory = rule.account_category;\n      maxConfidence = confidence;\n      matchedRowId = rowNumber;\n      matchedMerchantKeyword = merchantKeyword;\n      matchedAccountCategory = rule.account_category;\n      matchedUsageCount = rule.usage_count || 0;\n      matchedLastUsedDate = rule.last_used_date || '';\n      matchedConfidenceScore = confidence;\n    }\n  }\n  \n  // \u53d6\u5f15\u5185\u5bb9\u3067\u306e\u90e8\u5206\u4e00\u81f4\n  if (!matchedCategory && descriptionKeyword && description.includes(descriptionKeyword)) {\n    if (confidence > maxConfidence) {\n      matchedCategory = rule.account_category;\n      maxConfidence = confidence;\n      matchedRowId = rowNumber;\n      matchedMerchantKeyword = merchantKeyword;\n      matchedAccountCategory = rule.account_category;\n      matchedUsageCount = rule.usage_count || 0;\n      matchedLastUsedDate = rule.last_used_date || '';\n      matchedConfidenceScore = confidence;\n    }\n  }\n}\n\n// \u7d50\u679c\u51fa\u529b\nreturn {\n  json: {\n    ...ocrResult,\n    // \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1\u512a\u5148\u3001\u306a\u3051\u308c\u3070AI\u63a8\u8ad6\n    category: matchedCategory || ocrResult.category,\n    match_source: matchedCategory ? 'knowledge_base' : 'ai_inference',\n    matched_confidence: maxConfidence,\n    matched_row_id: matchedRowId,\n    // \u4f7f\u7528\u30c7\u30fc\u30bf\u66f4\u65b0\u7528\u306e\u30d5\u30a3\u30fc\u30eb\u30c9\u8ffd\u52a0\n    merchant_keyword: matchedMerchantKeyword,\n    account_category: matchedAccountCategory,\n    usage_count: matchedUsageCount,\n    last_used_date: matchedLastUsedDate,\n    confidence_score: matchedConfidenceScore\n  }\n};"
      },
      "id": "account-matching-node",
      "name": "\u52d8\u5b9a\u79d1\u76ee\u5224\u5b9a\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u512a\u5148\uff09",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1850,
        200
      ],
      "notes": "\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1\u30f3\u30b0 \u2192 AI\u63a8\u8ad6\u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af"
    },
    {
      "parameters": {
        "jsCode": "// \u52d8\u5b9a\u79d1\u76ee\u5224\u5b9a\u7d50\u679c\u3092\u53d6\u5f97\nconst judgmentResult = $input.item.json;\nconst userConfig = $('\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167').item.json;\nconst fileId = $('Google Drive Upload').item.json.id;\nconst driveUrl = `https://drive.google.com/uc?export=view&id=${fileId}`;\n\n// \u7a0e\u533a\u5206\u306e\u5224\u5b9a\nlet taxType = \"\";\nif (judgmentResult.invoice_number && judgmentResult.invoice_number.startsWith('T')) {\n  taxType = judgmentResult.tax_rate === 10 ? \"\u8ab210% \u30a4\u30f3\u30dc\u30a4\u30b9\" : \"\u8ab28% \u30a4\u30f3\u30dc\u30a4\u30b9\";\n} else {\n  taxType = judgmentResult.tax_rate === 10 ? \"\u8ab210% \u533a\u5206\u8a18\u8f09\" : \"\u8ab28% \u533a\u5206\u8a18\u8f09\";\n}\n\n// \u4f1a\u8a08\u30bd\u30d5\u30c8\u5225CSV\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u751f\u6210\nlet csvRow = \"\";\nif (userConfig.accounting_soft === \"freee\") {\n  csvRow = [\n    judgmentResult.transaction_date,\n    judgmentResult.category,\n    judgmentResult.amount,\n    taxType,\n    \"\u73fe\u91d1\",\n    judgmentResult.amount,\n    `${judgmentResult.merchant}\uff08${judgmentResult.description}\uff09`,\n    \"\"\n  ].join(\",\");\n} else if (userConfig.accounting_soft === \"moneyforward\") {\n  csvRow = [\n    judgmentResult.transaction_date,\n    judgmentResult.category,\n    \"\",\n    judgmentResult.amount,\n    \"\u73fe\u91d1\",\n    \"\",\n    judgmentResult.amount,\n    taxType,\n    `${judgmentResult.merchant}\uff08${judgmentResult.description}\uff09`\n  ].join(\",\");\n}\n\n// \u51fa\u529b\u30c7\u30fc\u30bf\nreturn {\n  json: {\n    // \u5224\u5b9a\u7d50\u679c\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u307e\u305f\u306fAI\u63a8\u8ad6\uff09\n    ...judgmentResult,\n    // \u8ffd\u52a0\u60c5\u5831\n    customer_name: userConfig.customer_name,\n    tax_type: taxType,\n    evidence_url: driveUrl,\n    csv_row: csvRow,\n    status: \"Review_Required\",\n    processed_at: new Date().toISOString(),\n    sheet_id: userConfig.sheet_id\n  }\n};"
      },
      "id": "transform-data-node",
      "name": "\u30c7\u30fc\u30bf\u5909\u63db\u30fbCSV\u751f\u6210",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2050,
        200
      ],
      "notes": "\u7a0e\u533a\u5206\u5224\u5b9a\u30fbCSV\u751f\u6210\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u5224\u5b9a\u7d50\u679c\u3092\u4f7f\u7528\uff09"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "={{ $('\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167').item.json.sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "\u4ed5\u8a33\u53f0\u5e33",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "schema": [
            {
              "id": "\u53d6\u5f15No",
              "displayName": "\u53d6\u5f15No",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u53d6\u5f15\u65e5",
              "displayName": "\u53d6\u5f15\u65e5",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u52d8\u5b9a\u79d1\u76ee",
              "displayName": "\u501f\u65b9\u52d8\u5b9a\u79d1\u76ee",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u88dc\u52a9\u79d1\u76ee",
              "displayName": "\u501f\u65b9\u88dc\u52a9\u79d1\u76ee",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u90e8\u9580",
              "displayName": "\u501f\u65b9\u90e8\u9580",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u53d6\u5f15\u5148",
              "displayName": "\u501f\u65b9\u53d6\u5f15\u5148",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u7a0e\u533a\u5206",
              "displayName": "\u501f\u65b9\u7a0e\u533a\u5206",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9",
              "displayName": "\u501f\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u501f\u65b9\u91d1\u984d(\u5186)",
              "displayName": "\u501f\u65b9\u91d1\u984d(\u5186)",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u52d8\u5b9a\u79d1\u76ee",
              "displayName": "\u8cb8\u65b9\u52d8\u5b9a\u79d1\u76ee",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u88dc\u52a9\u79d1\u76ee",
              "displayName": "\u8cb8\u65b9\u88dc\u52a9\u79d1\u76ee",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u90e8\u9580",
              "displayName": "\u8cb8\u65b9\u90e8\u9580",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u53d6\u5f15\u5148",
              "displayName": "\u8cb8\u65b9\u53d6\u5f15\u5148",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u7a0e\u533a\u5206",
              "displayName": "\u8cb8\u65b9\u7a0e\u533a\u5206",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9",
              "displayName": "\u8cb8\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u8cb8\u65b9\u91d1\u984d(\u5186)",
              "displayName": "\u8cb8\u65b9\u91d1\u984d(\u5186)",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u6458\u8981",
              "displayName": "\u6458\u8981",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u30bf\u30b0",
              "displayName": "\u30bf\u30b0",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "\u30e1\u30e2",
              "displayName": "\u30e1\u30e2",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "value": {
            "\u53d6\u5f15No": "={{ $now.format('yyyyMMddHHmmss') }}",
            "\u53d6\u5f15\u65e5": "={{ $json.transaction_date }}",
            "\u501f\u65b9\u52d8\u5b9a\u79d1\u76ee": "={{ $json.category }}",
            "\u501f\u65b9\u88dc\u52a9\u79d1\u76ee": "",
            "\u501f\u65b9\u90e8\u9580": "",
            "\u501f\u65b9\u53d6\u5f15\u5148": "={{ $json.merchant }}",
            "\u501f\u65b9\u7a0e\u533a\u5206": "={{ $json.tax_type }}",
            "\u501f\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9": "={{ $json.invoice_number || '' }}",
            "\u501f\u65b9\u91d1\u984d(\u5186)": "={{ $json.amount }}",
            "\u8cb8\u65b9\u52d8\u5b9a\u79d1\u76ee": "\u73fe\u91d1",
            "\u8cb8\u65b9\u88dc\u52a9\u79d1\u76ee": "",
            "\u8cb8\u65b9\u90e8\u9580": "",
            "\u8cb8\u65b9\u53d6\u5f15\u5148": "",
            "\u8cb8\u65b9\u7a0e\u533a\u5206": "",
            "\u8cb8\u65b9\u30a4\u30f3\u30dc\u30a4\u30b9": "",
            "\u8cb8\u65b9\u91d1\u984d(\u5186)": "={{ $json.amount }}",
            "\u6458\u8981": "={{ $json.merchant }}\uff08{{ $json.description || 'OCR\u81ea\u52d5\u51e6\u7406' }}\uff09",
            "\u30bf\u30b0": "={{ $json.match_source === 'knowledge_base' ? '\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9' : 'AI\u63a8\u8ad6' }}",
            "\u30e1\u30e2": "={{ $json.evidence_url }} | Status: {{ $json.status }}"
          },
          "matchingColumns": []
        },
        "options": {}
      },
      "id": "append-sheet-node",
      "name": "\u9867\u5ba2\u53f0\u5e33\u3078\u8a18\u5e33",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        2250,
        200
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "\u9867\u5ba2\u5225\u30b9\u30d7\u30ec\u30c3\u30c9\u30b7\u30fc\u30c8\u306b\u884c\u8ffd\u52a0"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "condition-kb-match",
              "leftValue": "={{ $json.match_source }}",
              "rightValue": "knowledge_base",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-kb-match-node",
      "name": "IF \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2450,
        200
      ],
      "notes": "\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1\u306e\u5834\u5408\u306e\u307f\u4f7f\u7528\u30c7\u30fc\u30bf\u66f4\u65b0"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "={{ $json.sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "schema": [
            {
              "id": "merchant_keyword",
              "displayName": "merchant_keyword",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "account_category",
              "displayName": "account_category",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "usage_count",
              "displayName": "usage_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_used_date",
              "displayName": "last_used_date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "confidence_score",
              "displayName": "confidence_score",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ],
          "value": {
            "merchant_keyword": "={{ $json.merchant_keyword }}",
            "account_category": "={{ $json.account_category }}",
            "usage_count": "={{ parseInt($json.usage_count || 0) + 1 }}",
            "last_used_date": "={{ $now.format('yyyy-MM-dd') }}",
            "confidence_score": "={{ Math.min(100, parseInt($json.confidence_score || 0) + 5) }}"
          },
          "matchingColumns": [
            "merchant_keyword",
            "account_category"
          ]
        },
        "options": {
          "range": "={{ 'A' + $json.matched_row_id + ':H' + $json.matched_row_id }}"
        }
      },
      "id": "update-kb-usage-node",
      "name": "\u4f7f\u7528\u30c7\u30fc\u30bf\u66f4\u65b0",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        2650,
        200
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "usage_count +1, last_used_date\u66f4\u65b0, confidence_score +5"
    },
    {
      "parameters": {
        "jsCode": "// \u30c7\u30fc\u30bf\u5909\u63db\u30ce\u30fc\u30c9\u304b\u3089\u53d6\u5f97\u3057\u305f\u30c7\u30fc\u30bf\nconst data = $('\u30c7\u30fc\u30bf\u5909\u63db\u30fbCSV\u751f\u6210').item.json;\nconst userId = $('Execute Workflow Trigger').item.json.body.events[0].source.userId;\n\n// undefined/null\u5024\u3092\u9069\u5207\u306b\u51e6\u7406\u3057\u3066\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u69cb\u7bc9\nconst formatValue = (value, defaultText = '\uff08\u672a\u53d6\u5f97\uff09') => {\n  return (value !== null && value !== undefined && value !== '') ? value : defaultText;\n};\n\nconst formatAmount = (amount) => {\n  if (amount !== null && amount !== undefined) {\n    return '\u00a5' + Number(amount).toLocaleString('ja-JP');\n  }\n  return '\uff08\u672a\u53d6\u5f97\uff09';\n};\n\n// \u5224\u5b9a\u5143\u3092\u8868\u793a\nconst matchInfo = data.match_source === 'knowledge_base' \n  ? `\\n\\n\u5224\u5b9a\u5143: \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\uff08\u4fe1\u983c\u5ea6: ${data.matched_confidence}%\uff09`\n  : '\\n\\n\u5224\u5b9a\u5143: AI\u63a8\u8ad6';\n\n// LINE API\u30ea\u30af\u30a8\u30b9\u30c8\u30dc\u30c7\u30a3\u3092\u69cb\u7bc9\nconst lineMessage = {\n  to: userId,\n  messages: [\n    {\n      type: 'text',\n      text: `\u9818\u53ce\u66f8\u3092\u51e6\u7406\u3057\u307e\u3057\u305f\u2705\n\n\u3010\u51e6\u7406\u5185\u5bb9\u3011\n\u65e5\u4ed8: ${formatValue(data.transaction_date)}\n\u652f\u6255\u5148: ${formatValue(data.merchant)}\n\u91d1\u984d: ${formatAmount(data.amount)}\n\u79d1\u76ee: ${formatValue(data.category)}${matchInfo}\n\n\u8a3c\u6191: ${formatValue(data.evidence_url, '\uff08\u30ea\u30f3\u30af\u306a\u3057\uff09')}`\n    }\n  ]\n};\n\nreturn {\n  json: {\n    lineRequestBody: lineMessage\n  }\n};"
      },
      "id": "build-line-message-node",
      "name": "LINE\u8fd4\u4fe1\u30e1\u30c3\u30bb\u30fc\u30b8\u69cb\u7bc9",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2850,
        200
      ],
      "notes": "\u5224\u5b9a\u5143\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9/AI\uff09\u3092\u542b\u3080\u30e1\u30c3\u30bb\u30fc\u30b8\u69cb\u7bc9"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.line.me/v2/bot/message/push",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.lineRequestBody }}",
        "options": {}
      },
      "id": "line-reply-success",
      "name": "LINE\u8fd4\u4fe1\uff08\u6210\u529f\uff09",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        3050,
        200
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "\u51e6\u7406\u5b8c\u4e86\u3092LINE\u3067\u901a\u77e5"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.line.me/v2/bot/message/push",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {\n  \"to\": $('Execute Workflow Trigger').item.json.body.events[0].source.userId,\n  \"messages\": [\n    {\n      \"type\": \"text\",\n      \"text\": \"\u3054\u767b\u9332\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3059\u3002\\n\\n\u73fe\u5728\u3001\u7ba1\u7406\u8005\u304c\u8a2d\u5b9a\u4e2d\u3067\u3059\u3002\\n\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u3002\\n\\n\u8a2d\u5b9a\u5b8c\u4e86\u5f8c\u3001\u9818\u53ce\u66f8\u753b\u50cf\u3092\u9001\u4fe1\u3044\u305f\u3060\u3051\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002\"\n    }\n  ]\n} }}",
        "options": {}
      },
      "id": "line-reply-user-error",
      "name": "LINE\u8fd4\u4fe1\uff08\u8a2d\u5b9a\u5f85\u3061\uff09",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        850,
        400
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "\u4eee\u767b\u9332\u30e6\u30fc\u30b6\u30fc\uff08\u8a2d\u5b9a\u672a\u5b8c\u4e86\uff09\u3078\u306e\u901a\u77e5"
    }
  ],
  "connections": {
    "Execute Workflow Trigger": {
      "main": [
        [
          {
            "node": "\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u9867\u5ba2\u30de\u30b9\u30bf\u30fc\u53c2\u7167": {
      "main": [
        [
          {
            "node": "IF \u8a2d\u5b9a\u5b8c\u4e86",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u8a2d\u5b9a\u5b8c\u4e86": {
      "main": [
        [
          {
            "node": "Get LINE Image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "LINE\u8fd4\u4fe1\uff08\u8a2d\u5b9a\u5f85\u3061\uff09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get LINE Image": {
      "main": [
        [
          {
            "node": "Google Drive Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive Upload": {
      "main": [
        [
          {
            "node": "Google Drive Download",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive Download": {
      "main": [
        [
          {
            "node": "OCR\u30ea\u30af\u30a8\u30b9\u30c8\u69cb\u7bc9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OCR\u30ea\u30af\u30a8\u30b9\u30c8\u69cb\u7bc9": {
      "main": [
        [
          {
            "node": "AI-OCR\u51e6\u7406\uff08GPT-4o\uff09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI-OCR\u51e6\u7406\uff08GPT-4o\uff09": {
      "main": [
        [
          {
            "node": "\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc\u53d6\u5f97",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u52d8\u5b9a\u79d1\u76ee\u30de\u30b9\u30bf\u30fc\u53d6\u5f97": {
      "main": [
        [
          {
            "node": "\u52d8\u5b9a\u79d1\u76ee\u5224\u5b9a\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u512a\u5148\uff09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u52d8\u5b9a\u79d1\u76ee\u5224\u5b9a\uff08\u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u512a\u5148\uff09": {
      "main": [
        [
          {
            "node": "\u30c7\u30fc\u30bf\u5909\u63db\u30fbCSV\u751f\u6210",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u30c7\u30fc\u30bf\u5909\u63db\u30fbCSV\u751f\u6210": {
      "main": [
        [
          {
            "node": "\u9867\u5ba2\u53f0\u5e33\u3078\u8a18\u5e33",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u9867\u5ba2\u53f0\u5e33\u3078\u8a18\u5e33": {
      "main": [
        [
          {
            "node": "IF \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u30ca\u30ec\u30c3\u30b8\u30d9\u30fc\u30b9\u30de\u30c3\u30c1": {
      "main": [
        [
          {
            "node": "\u4f7f\u7528\u30c7\u30fc\u30bf\u66f4\u65b0",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "LINE\u8fd4\u4fe1\u30e1\u30c3\u30bb\u30fc\u30b8\u69cb\u7bc9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u4f7f\u7528\u30c7\u30fc\u30bf\u66f4\u65b0": {
      "main": [
        [
          {
            "node": "LINE\u8fd4\u4fe1\u30e1\u30c3\u30bb\u30fc\u30b8\u69cb\u7bc9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LINE\u8fd4\u4fe1\u30e1\u30c3\u30bb\u30fc\u30b8\u69cb\u7bc9": {
      "main": [
        [
          {
            "node": "LINE\u8fd4\u4fe1\uff08\u6210\u529f\uff09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    {
      "name": "LINE Bot",
      "id": "line-bot"
    }
  ],
  "triggerCount": 0,
  "updatedAt": "2026-01-19T15:00:00.000Z",
  "versionId": "1"
}