n8n 实操攻略 10:搭建发票处理机器人(下)

10 months ago

上一篇我们已经拿到了发票的信息,并且保存到了 Google 表格中,接下来,我们要把关键信息,发送到我们的邮箱中。

https://appstore.lazycat.cloud/#/shop/detail/cloud.lazycat.app.n8n

提取邮箱地址

这一步需要把第一步中,我们输入的邮箱提取出来,参考代码

const raw =  $('When chat message received').first().json.chatInput|| "";

// 匹配第一个邮箱格式
const match = raw.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);

return [
  {
    json: {
      email: match ? match[0] : null
    }
  }
];

执行后,可以看到能正常提取

image.png

if判断

这一步,如果我们识别出来了邮箱,并且不为空的话,就执行下一步

image.png

发邮件

发邮件之前,可以把我们前面的节点名称改一下,方便我们看

image.png

回到 Google 控制台 点击 API 和服务

image.png

在这里搜索 Gmail

image.png

启用 API 的权限

image.png

这时候,回到 n8n,新建一个凭证 输入客户端 id 和密钥

image.png

授权成功会有提示

image.png

操作选择 send,邮箱就是我们识别出来的邮箱

image.png

邮件类型选择 html,message 参考下面的代码

<div style="font-family: Arial, Helvetica, sans-serif; color:#222; line-height:1.6; max-width:720px; margin:0 auto; border:1px solid #eee; border-radius:8px; overflow:hidden;">
  <!-- 顶部标题 -->
  <div style="background:#f6f8fa; padding:16px 20px; border-bottom:1px solid #eee;">
    <div style="font-size:18px; font-weight:700;">
      {{ $('GoogleSheets').first().json["发票标题"] || "发票" }}
    </div>
    <div style="font-size:13px; color:#666;">
      发票号码:{{ $('GoogleSheets').first().json["发票号码"] || "" }} 
      开票日期:{{ $('GoogleSheets').first().json["开票日期"] || "" }}
    </div>
  </div>

  <!-- 购方/销方 -->
  <table role="presentation" cellspacing="0" cellpadding="0" style="width:100%; border-collapse:collapse;">
    <tr>
      <td style="padding:16px 20px; width:50%; vertical-align:top; border-right:1px solid #f0f0f0;">
        <div style="font-weight:700; margin-bottom:6px;">购方信息</div>
        <div>名称:{{ $('GoogleSheets').first().json["购方名称"] || "" }}</div>
        <div>税号:{{ $('GoogleSheets').first().json["购方税号"] || "" }}</div>
        <div style="color:#666;">备注:{{ $('GoogleSheets').first().json["购方备注"] || "" }}</div>
      </td>
      <td style="padding:16px 20px; width:50%; vertical-align:top;">
        <div style="font-weight:700; margin-bottom:6px;">销方信息</div>
        <div>名称:{{ $('GoogleSheets').first().json["销方名称"] || "" }}</div>
        <div>税号:{{ $('GoogleSheets').first().json["销方税号"] || "" }}</div>
      </td>
    </tr>
  </table>

  <!-- 行项目 -->
  <div style="padding:0 20px 16px 20px;">
    <div style="font-weight:700; margin:6px 0 8px;">商品 / 服务明细</div>
    <table role="presentation" cellspacing="0" cellpadding="0" style="width:100%; border-collapse:collapse; border:1px solid #eee;">
      <thead>
        <tr style="background:#fafbfc;">
          <th style="text-align:left; padding:10px; border-bottom:1px solid #eee;">商品名称</th>
          <th style="text-align:left; padding:10px; border-bottom:1px solid #eee;">规格型号</th>
          <th style="text-align:center; padding:10px; border-bottom:1px solid #eee;">单位</th>
          <th style="text-align:right; padding:10px; border-bottom:1px solid #eee;">数量</th>
          <th style="text-align:right; padding:10px; border-bottom:1px solid #eee;">单价</th>
          <th style="text-align:right; padding:10px; border-bottom:1px solid #eee;">不含税金额</th>
          <th style="text-align:right; padding:10px; border-bottom:1px solid #eee;">税率</th>
          <th style="text-align:right; padding:10px; border-bottom:1px solid #eee;">税额</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td style="padding:10px; border-bottom:1px solid #f5f5f5;">{{ $('GoogleSheets').first().json["商品名称"] || "" }}</td>
          <td style="padding:10px; border-bottom:1px solid #f5f5f5;">{{ $('GoogleSheets').first().json["规格型号"] || "" }}</td>
          <td style="padding:10px; text-align:center; border-bottom:1px solid #f5f5f5;">{{ $('GoogleSheets').first().json["单位"] || "" }}</td>
          <td style="padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;">{{ $('GoogleSheets').first().json["数量"] || "" }}</td>
          <td style="padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;">¥{{ parseFloat($('GoogleSheets').first().json["单价"] || 0).toFixed(2) }}</td>
          <td style="padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;">¥{{ parseFloat($('GoogleSheets').first().json["不含税金额"] || 0).toFixed(2) }}</td>
          <td style="padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;">
            {{ $('GoogleSheets').first().json["税率显示"] || (parseFloat($('GoogleSheets').first().json["税率"] || 0)*100).toFixed(0) + "%" }}
          </td>
          <td style="padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;">¥{{ parseFloat($('GoogleSheets').first().json["税额"] || 0).toFixed(2) }}</td>
        </tr>
      </tbody>
    </table>
  </div>

  <!-- 合计 -->
  <div style="padding:0 20px 20px 20px;">
    <table role="presentation" cellspacing="0" cellpadding="0" style="margin-left:auto; border-collapse:collapse;">
      <tr>
        <td style="padding:6px 12px; color:#666;">合计不含税金额:</td>
        <td style="padding:6px 12px; text-align:right; font-weight:700;">
          ¥{{ parseFloat($('GoogleSheets').first().json["合计不含税金额"] || 0).toFixed(2) }}
        </td>
      </tr>
      <tr>
        <td style="padding:6px 12px; color:#666;">合计税额:</td>
        <td style="padding:6px 12px; text-align:right; font-weight:700;">
          ¥{{ parseFloat($('GoogleSheets').first().json["合计税额"] || 0).toFixed(2) }}
        </td>
      </tr>
      <tr>
        <td style="padding:6px 12px; color:#666;">合计价税合计金额:</td>
        <td style="padding:6px 12px; text-align:right; font-weight:700;">
          ¥{{ parseFloat($('GoogleSheets').first().json["合计价税合计金额"] || 0).toFixed(2) }}
        </td>
      </tr>
    </table>
  </div>

  <!-- 底部 -->
  <div style="padding:10px 20px; background:#f9fafb; border-top:1px solid #eee; font-size:13px; color:#555;">
    开票人:{{ $('GoogleSheets').first().json["开票人"] || "" }}
  </div>
</div>

点开看一下,如果不飙红并且能看到数据,说明是正常的

image.png

点击执行,输出结果是正常的

image.png

邮件也收到了

image.png

打开邮件可以看到内容:

image.png

以上就是发票机器人的完整流程。

如果你想偷懒,可以直接导入我的 json 文件,再参考攻略,配置自己的节点就可以了

{
  "name": "analyze image and send email",
  "nodes": [
    {
      "parameters": {
        "jsCode": "// n8n Code 节点 - 发票数据解析\n// 获取输入数据(处理可能的字符串格式)\nconst inputData = $input.first().json.choices[0].message.content;\n\n// 如果输入是字符串,先解析为 JSON\nlet invoiceData;\nif (typeof inputData === 'string') {\n  // 移除可能的 markdown 代码块标记\n  const cleanData = inputData.replace(/^```json\\s*/, '').replace(/\\s*```$/, '').trim();\n  invoiceData = JSON.parse(cleanData);\n} else {\n  invoiceData = inputData;\n}\n\n// 提取发票数据\nconst invoice = invoiceData.invoice;\n\n// 返回扁平化的 JSON 数据\nreturn [{\n  json: {\n    title: invoice.title,\n    invoiceNumber: invoice.number,\n    issueDate: invoice.issue_date,\n    currency: invoice.currency,\n    issuer: invoice.issuer,\n    buyerName: invoice.buyer.name,\n    buyerTaxId: invoice.buyer.tax_id,\n    buyerNote: invoice.buyer.note,\n    sellerName: invoice.seller.name,\n    sellerTaxId: invoice.seller.tax_id,\n    itemName: invoice.items[0].name,\n    itemSpec: invoice.items[0].spec,\n    itemUnit: invoice.items[0].unit,\n    quantity: invoice.items[0].quantity,\n    unitPrice: invoice.items[0].unit_price,\n    amountWithoutTax: invoice.items[0].amount_without_tax,\n    taxRate: invoice.items[0].tax_rate,\n    taxRateDisplay: invoice.items[0].tax_rate_display,\n    taxAmount: invoice.items[0].tax_amount,\n    subtotal: invoice.totals.amount_without_tax,\n    totalTax: invoice.totals.tax_total,\n    grandTotal: invoice.totals.amount_with_tax\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        200
      ],
      "id": "70bef82b-f44f-4389-adc2-d1e41a1ef12a",
      "name": "Code"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo",
          "mode": "list",
          "cachedResultName": "发票",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "发票标题": "={{ $json.title }}",
            "发票号码": "={{ $json.invoiceNumber }}",
            "开票日期": "={{ $json.issueDate }}",
            "购方名称": "={{ $json.buyerName }}",
            "购方税号": "={{ $json.buyerTaxId }}",
            "购方备注": "={{ $json.buyerNote }}",
            "销方名称": "={{ $json.sellerName }}",
            "商品名称": "={{ $json.itemName }}",
            "销方税号": "={{ $json.sellerTaxId }}",
            "规格型号": "={{ $json.itemSpec }}",
            "单位": "={{ $json.itemUnit }}",
            "数量": "={{ $json.quantity }}",
            "单价": "={{ $json.unitPrice }}",
            "不含税金额": "={{ $json.amountWithoutTax }}",
            "税率": "={{ $json.taxRate }}",
            "税率显示": "={{ $json.taxRateDisplay }}",
            "税额": "={{ $json.taxAmount }}",
            "合计不含税金额": "={{ $json.subtotal }}",
            "合计税额": "={{ $json.totalTax }}",
            "合计价税合计金额": "={{ $json.grandTotal }}",
            "开票人": "={{ $json.issuer }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "发票标题",
              "displayName": "发票标题",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "发票号码",
              "displayName": "发票号码",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "开票日期",
              "displayName": "开票日期",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "购方名称",
              "displayName": "购方名称",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "购方税号",
              "displayName": "购方税号",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "购方备注",
              "displayName": "购方备注",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "销方名称",
              "displayName": "销方名称",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "销方税号",
              "displayName": "销方税号",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "商品名称",
              "displayName": "商品名称",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "规格型号",
              "displayName": "规格型号",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "单位",
              "displayName": "单位",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "数量",
              "displayName": "数量",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "单价",
              "displayName": "单价",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "不含税金额",
              "displayName": "不含税金额",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "税率",
              "displayName": "税率",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "税率显示",
              "displayName": "税率显示",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "税额",
              "displayName": "税额",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "合计不含税金额",
              "displayName": "合计不含税金额",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "合计税额",
              "displayName": "合计税额",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "合计价税合计金额",
              "displayName": "合计价税合计金额",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "开票人",
              "displayName": "开票人",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.6,
      "position": [
        260,
        80
      ],
      "id": "9a9b3088-7722-4dd5-b2b7-28726fd64f8f",
      "name": "Google Sheets",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "jflKNS6HMBOKZok2",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const raw =  $('When chat message received').first().json.chatInput|| \"\";\n\n// 匹配第一个邮箱格式\nconst match = raw.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/);\n\nreturn [\n  {\n    json: {\n      email: match ? match[0] : null\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        -80
      ],
      "id": "5e71f0be-bebb-42ac-9d64-413d98b4e5db",
      "name": "Code1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "a44e6c17-4473-4dfe-bab9-5c98caa8fa31",
              "leftValue": "={{ $json.email }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        640,
        -80
      ],
      "id": "e50264b2-51e1-4c2a-bb0d-66447b6f3b0d",
      "name": "If"
    },
    {
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "subject": "发票",
        "message": "=<div style=\"font-family: Arial, Helvetica, sans-serif; color:#222; line-height:1.6; max-width:720px; margin:0 auto; border:1px solid #eee; border-radius:8px; overflow:hidden;\">\n  <!-- 顶部标题 -->\n  <div style=\"background:#f6f8fa; padding:16px 20px; border-bottom:1px solid #eee;\">\n    <div style=\"font-size:18px; font-weight:700;\">\n      {{ $('Google Sheets').item.json[\"发票标题\"] || \"发票\" }}\n    </div>\n    <div style=\"font-size:13px; color:#666;\">\n      发票号码:{{ $('Google Sheets').item.json[\"发票号码\"] || \"\" }} \n      开票日期:{{ $('Google Sheets').item.json[\"开票日期\"] || \"\" }} \n     \n    </div>\n  </div>\n\n  <!-- 购方/销方 -->\n  <table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" style=\"width:100%; border-collapse:collapse;\">\n    <tr>\n      <td style=\"padding:16px 20px; width:50%; vertical-align:top; border-right:1px solid #f0f0f0;\">\n        <div style=\"font-weight:700; margin-bottom:6px;\">购方信息</div>\n        <div>名称:{{ $('Google Sheets').item.json[\"购方名称\"] || \"\" }}</div>\n        <div>税号:{{ $('Google Sheets').item.json[\"购方税号\"] || \"\" }}</div>\n        <div style=\"color:#666;\">备注:{{ $('Google Sheets').item.json[\"购方备注\"] || \"\" }}</div>\n      </td>\n      <td style=\"padding:16px 20px; width:50%; vertical-align:top;\">\n        <div style=\"font-weight:700; margin-bottom:6px;\">销方信息</div>\n        <div>名称:{{ $('Google Sheets').item.json[\"销方名称\"] || \"\" }}</div>\n        <div>税号:{{ $('Google Sheets').item.json[\"销方税号\"] || \"\" }}</div>\n      </td>\n    </tr>\n  </table>\n\n  <!-- 行项目 -->\n  <div style=\"padding:0 20px 16px 20px;\">\n    <div style=\"font-weight:700; margin:6px 0 8px;\">商品 / 服务明细</div>\n    <table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" style=\"width:100%; border-collapse:collapse; border:1px solid #eee;\">\n      <thead>\n        <tr style=\"background:#fafbfc;\">\n          <th style=\"text-align:left; padding:10px; border-bottom:1px solid #eee;\">商品名称</th>\n          <th style=\"text-align:left; padding:10px; border-bottom:1px solid #eee;\">规格型号</th>\n          <th style=\"text-align:center; padding:10px; border-bottom:1px solid #eee;\">单位</th>\n          <th style=\"text-align:right; padding:10px; border-bottom:1px solid #eee;\">数量</th>\n          <th style=\"text-align:right; padding:10px; border-bottom:1px solid #eee;\">单价</th>\n          <th style=\"text-align:right; padding:10px; border-bottom:1px solid #eee;\">不含税金额</th>\n          <th style=\"text-align:right; padding:10px; border-bottom:1px solid #eee;\">税率</th>\n          <th style=\"text-align:right; padding:10px; border-bottom:1px solid #eee;\">税额</th>\n        </tr>\n      </thead>\n      <tbody>\n        <tr>\n          <td style=\"padding:10px; border-bottom:1px solid #f5f5f5;\">{{ $('Google Sheets').item.json[\"商品名称\"] || \"\" }}</td>\n          <td style=\"padding:10px; border-bottom:1px solid #f5f5f5;\">{{ $('Google Sheets').item.json[\"规格型号\"] || \"\" }}</td>\n          <td style=\"padding:10px; text-align:center; border-bottom:1px solid #f5f5f5;\">{{ $('Google Sheets').item.json[\"单位\"] || \"\" }}</td>\n          <td style=\"padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;\">{{ $('Google Sheets').item.json[\"数量\"] ?? \"\" }}</td>\n          <td style=\"padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;\">{{ Number($('Google Sheets').item.json[\"单价\"] ?? 0).toFixed(6) }}</td>\n          <td style=\"padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;\">{{ Number($('Google Sheets').item.json[\"不含税金额\"] ?? 0).toFixed(2) }}</td>\n          <td style=\"padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;\">\n            {{ $('Google Sheets').item.json[\"税率显示\"] || (Number($('Google Sheets').item.json[\"税率\"] ?? 0)*100).toFixed(0) + \"%\" }}\n          </td>\n          <td style=\"padding:10px; text-align:right; border-bottom:1px solid #f5f5f5;\">{{ Number($('Google Sheets').item.json[\"税额\"] ?? 0).toFixed(2) }}</td>\n        </tr>\n      </tbody>\n    </table>\n  </div>\n\n  <!-- 合计 -->\n  <div style=\"padding:0 20px 20px 20px;\">\n    <table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin-left:auto; border-collapse:collapse;\">\n      <tr>\n        <td style=\"padding:6px 12px; color:#666;\">合计不含税金额:</td>\n        <td style=\"padding:6px 12px; text-align:right; font-weight:700;\">\n          {{ Number($('Google Sheets').item.json[\"合计不含税金额\"] ?? 0).toFixed(2) }}\n        </td>\n      </tr>\n      <tr>\n        <td style=\"padding:6px 12px; color:#666;\">合计税额:</td>\n        <td style=\"padding:6px 12px; text-align:right; font-weight:700;\">\n          {{ Number($('Google Sheets').item.json[\"合计税额\"] ?? 0).toFixed(2) }}\n        </td>\n      </tr>\n      <tr>\n        <td style=\"padding:6px 12px; color:#666;\">合计价税合计金额:</td>\n        <td style=\"padding:6px 12px; text-align:right; font-weight:700;\">\n          {{ Number($('Google Sheets').item.json[\"合计价税合计金额\"] ?? 0).toFixed(2) }}\n        </td>\n      </tr>\n    </table>\n  </div>\n\n  <!-- 底部 -->\n  <div style=\"padding:10px 20px; background:#f9fafb; border-top:1px solid #eee; font-size:13px; color:#555;\">\n    开票人:{{ $('Google Sheets').item.json[\"开票人\"] || \"\" }}\n  </div>\n</div>\n",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1060,
        -60
      ],
      "id": "16486451-dabf-48d7-98a9-77851add9d47",
      "name": "Gmail",
      "webhookId": "7f924497-ae8b-4b4e-8cad-3b4cd7a162d9",
      "credentials": {
        "gmailOAuth2": {
          "id": "lLR0rjkd7MVl0WuY",
          "name": "Gmail account"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "allowFileUploads": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "typeVersion": 1.1,
      "position": [
        -760,
        200
      ],
      "id": "7e8689a3-250d-466a-a4b1-1e42a8f014d4",
      "name": "When chat message received",
      "webhookId": "d7c99574-86d3-42f4-adf2-69f9fc1f7d3d"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.imgbb.com/1/upload?expiration=6000&key=80ddf220f655b5887b8a5eeee2a3652e",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "image",
              "inputDataFieldName": "data0"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -560,
        200
      ],
      "id": "0849a0c5-dafc-4af7-ac7d-8b463df5abb9",
      "name": "IMGBB"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.gpt.ge/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n    \"model\": \"gpt-4o\",\n    \"messages\": [\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\n                    \"type\": \"text\",\n                     \"text\": \"## 角色\\n你是一个专业的\\\"发票信息抽取器\\\"。输入是一段发票文字(可能来自 OCR、邮件正文或聊天粘贴),输出是严格有效的 JSON,适合直接写入数据库/Google Sheets。\\n## 任务\\n从给定的发票文本中识别并抽取字段,返回单个 JSON 对象,放在一个标记代码块里(json ... )。不要输出任何解释、注释或多余字符。\\n## 输出要求\\n仅输出一个 JSON 代码块,不得包含额外文字。\\n不存在或不确定的值一律填 null。\\n日期统一为 YYYY-MM-DD(ISO 8601);\\n金额/数量等数值字段用 数字类型(而非字符串),保留精度但不要添加货币符号或千分位。\\n税率使用小数(例如 1% → 0.01),并同时提供显示字段(例如 \\\"1%\\\")。\\nitems 数组必须存在;若无行项目,输出空数组 []。\\n## 字段定义(Schema)\\n{\\n  \\\"invoice\\\": {\\n    \\\"title\\\": \\\"string|null\\\",\\n    \\\"number\\\": \\\"string|null\\\",\\n    \\\"issue_date\\\": \\\"YYYY-MM-DD|null\\\",\\n    \\\"currency\\\": \\\"string|null\\\",\\n    \\\"buyer\\\": {\\n      \\\"name\\\": \\\"string|null\\\",\\n      \\\"tax_id\\\": \\\"string|null\\\",\\n      \\\"note\\\": \\\"string|null\\\"\\n    },\\n    \\\"seller\\\": {\\n      \\\"name\\\": \\\"string|null\\\",\\n      \\\"tax_id\\\": \\\"string|null\\\"\\n    },\\n    \\\"items\\\": [\\n      {\\n        \\\"name\\\": \\\"string|null\\\",\\n        \\\"spec\\\": \\\"string|null\\\",\\n        \\\"unit\\\": \\\"string|null\\\",\\n        \\\"quantity\\\": \\\"number|null\\\",\\n        \\\"unit_price\\\": \\\"number|null\\\",\\n        \\\"amount_without_tax\\\": \\\"number|null\\\",\\n        \\\"tax_rate\\\": \\\"number|null\\\",\\n        \\\"tax_rate_display\\\": \\\"string|null\\\",\\n        \\\"tax_amount\\\": \\\"number|null\\\"\\n      }\\n    ],\\n    \\\"totals\\\": {\\n      \\\"amount_without_tax\\\": \\\"number|null\\\",\\n      \\\"tax_total\\\": \\\"number|null\\\",\\n      \\\"amount_with_tax\\\": \\\"number|null\\\"\\n    },\\n    \\\"issuer\\\": \\\"string|null\\\"\\n  }\\n}\"\n                },\n                {\n                    \"type\": \"image_url\",\n                    \"image_url\": {\n                        \"url\": \"{{ $json.data.url }}\"\n                    }\n                }\n            ]\n        }\n    ]\n} ",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -240,
        200
      ],
      "id": "24b25ed1-18d8-4c8a-9d2e-d903168e9b8e",
      "name": "识别图片",
      "retryOnFail": true,
      "credentials": {
        "httpHeaderAuth": {
          "id": "BKtGro8HEgz5LcZM",
          "name": "V3 Header Auth account"
        }
      }
    }
  ],
  "pinData": {},
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "IMGBB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IMGBB": {
      "main": [
        [
          {
            "node": "识别图片",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "识别图片": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "fb865209-ec18-41a6-b252-def147580997",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "3cb07a731a78af260d8c81716bfc0e842ef01e898e945b902a3871e6a1cd0d48"
  },
  "id": "OWymQVChmL3XifYL",
  "tags": []
}

作者
天天