8
n8n 中文网amn8n.com

使用Mistral OCR和Gmail人工验证提取工时表数据

高级

这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 32 个节点。主要使用 Set, Code, Gmail, Switch, Aggregate 等节点。 使用Mistral OCR和Gmail人工验证提取工时表数据

前置要求
  • Google 账号和 Gmail API 凭证
  • Google Drive API 凭证
  • 可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "d2787088d49a05164783f5a9fa37e1730a27b190e51881d2128ba2bcd8c2656e",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "9e684e57-8185-4cdc-9e50-f04772aebc7a",
      "name": "当点击\"测试工作流\"时",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1472,
        80
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "054e0f32-c0f0-4ce0-bf89-c683a6ec58ae",
      "name": "遍历项目2",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -976,
        80
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "bfbb9266-7748-42d1-ad5f-ea9fae83cbcf",
      "name": "读取电子表格文件",
      "type": "n8n-nodes-base.spreadsheetFile",
      "position": [
        16,
        112
      ],
      "parameters": {
        "options": {
          "headerRow": true
        }
      },
      "typeVersion": 1
    },
    {
      "id": "629be4ea-76ae-421a-a6f2-c6c7539e7dec",
      "name": "Mistral Cloud Chat Model2",
      "type": "@n8n/n8n-nodes-langchain.lmChatMistralCloud",
      "position": [
        1120,
        352
      ],
      "parameters": {
        "model": "mistral-small-latest",
        "options": {}
      },
      "credentials": {
        "mistralCloudApi": {
          "id": "mRwBaVJZsN6hIzkX",
          "name": "Mistral Cloud account 2"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f0e86712-6d3d-4e07-8225-1f073a077f47",
      "name": "下载文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -528,
        96
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set File ID1').item.json.file_id }}"
        },
        "options": {
          "googleFileConversion": {
            "conversion": {
              "docsToFormat": "text/plain"
            }
          }
        },
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ukOlw9NKhJMJxRUB",
          "name": "Google Drive account 2"
        }
      },
      "executeOnce": true,
      "typeVersion": 3
    },
    {
      "id": "e333ce08-7cef-4c9b-93fd-d52bfe8d23a0",
      "name": "设置文件ID1",
      "type": "n8n-nodes-base.set",
      "position": [
        -752,
        96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "10646eae-ae46-4327-a4dc-9987c2d76173",
              "name": "file_id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "f4536df5-d0b1-4392-bf17-b8137fb31a44",
              "name": "file_type",
              "type": "string",
              "value": "={{ $json.mimeType }}"
            },
            {
              "id": "77d782de-169d-4a46-8a8e-a3831c04d90f",
              "name": "file_title",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "9bde4d7f-e4f3-4ebd-9338-dce1350f9eab",
              "name": "file_url",
              "type": "string",
              "value": "={{ $json.webViewLink }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ce7e73f0-0cb4-4437-b662-012b4434be93",
      "name": "搜索文件和文件夹",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1248,
        80
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list",
            "value": ""
          }
        },
        "options": {
          "fields": [
            "id",
            "name",
            "webViewLink",
            "mimeType",
            "*"
          ]
        },
        "resource": "fileFolder",
        "searchMethod": "query"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ukOlw9NKhJMJxRUB",
          "name": "Google Drive account 2"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "abe728eb-7a64-4fdc-a287-86a35e35fa87",
      "name": "切换文件类型",
      "type": "n8n-nodes-base.switch",
      "position": [
        -304,
        80
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "pdf/doc",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/pdf"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/msword"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/vnd.google-apps.document"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "excel",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/vnd.ms-excel"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "application/vnd.google-apps.spreadsheet"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "image",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "image/jpeg"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "image/png"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "image/tiff"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "image/gif"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.file_type }}",
                    "rightValue": "image/bmp"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": 3
        }
      },
      "typeVersion": 3
    },
    {
      "id": "afe1a432-5596-4b2c-8933-470e256620da",
      "name": "发送消息",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1952,
        112
      ],
      "webhookId": "a53f176d-af13-41b2-9746-51b0136c45f2",
      "parameters": {
        "sendTo": "addemail",
        "message": "=check if give file data match the extracted data\n\n\n {{ $json.email_body }}",
        "options": {},
        "subject": "timesheet approval required",
        "operation": "sendAndWait",
        "formFields": {
          "values": [
            {
              "fieldLabel": "original file ",
              "placeholder": "={{ $('Download File').item.json.file_url }}"
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "is output accurate ",
              "fieldOptions": {
                "values": [
                  {
                    "option": "yes"
                  },
                  {
                    "option": "no"
                  }
                ]
              }
            },
            {
              "fieldLabel": "comments for correction"
            }
          ]
        },
        "responseType": "customForm"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "sKkv4c543Gh7w7yJ",
          "name": "Gmail account 2 rn"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "55f11060-67a1-4388-ad54-a78e3b82fb59",
      "name": "HTTP 请求1",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        -32,
        384
      ],
      "parameters": {
        "url": "https://universal-file-to-text-extractor.vercel.app/extract",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "mode",
              "value": "single"
            },
            {
              "name": "output_type",
              "value": "jsonl"
            },
            {
              "name": "files",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "include_images",
              "value": "true"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "508571a6-e26b-488d-aca5-3792b1eec2ff",
      "name": "编辑字段3",
      "type": "n8n-nodes-base.set",
      "position": [
        -64,
        -176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e5bd95ba-8269-404a-bf9d-fa0d25398b59",
              "name": "",
              "type": "string",
              "value": ""
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "3756f590-1c44-4739-a673-7cba930b5cb9",
      "name": "Mistral 上传",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        160,
        -176
      ],
      "parameters": {
        "url": "https://api.mistral.ai/v1/files",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "purpose",
              "value": "ocr"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "id": "mRwBaVJZsN6hIzkX",
          "name": "Mistral Cloud account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0074468b-7fbb-4590-a8d5-2506f27f7695",
      "name": "Mistral 签名 URL",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        400,
        -176
      ],
      "parameters": {
        "url": "=https://api.mistral.ai/v1/files/{{ $json.id }}/url",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "expiry",
              "value": "1"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "id": "mRwBaVJZsN6hIzkX",
          "name": "Mistral Cloud account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "82260a41-2b95-46b7-bff2-ccfcab9140ce",
      "name": "Mistral 文档 OCR",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        608,
        -176
      ],
      "parameters": {
        "url": "https://api.mistral.ai/v1/ocr",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"mistral-ocr-latest\",\n  \"document\": {\n    \"document_url\": \"{{ $json.url }}\"\n  },\n  \"bbox_annotation_format\": {\n    \"type\": \"json_schema\",\n    \"json_schema\": {\n      \"schema\": {\n        \"properties\": {\n          \"image_type\": { \"title\": \"Image_Type\", \"type\": \"string\", \"description\": \"type of image\" },\n          \"short_description\": { \"title\": \"Short_Description\", \"type\": \"string\", \"description\": \"short description\" },\n          \"summary\": { \"title\": \"Summary\", \"type\": \"string\", \"description\": \"summary of the image\" }\n        },\n        \"required\": [\"image_type\",\"short_description\",\"summary\"],\n        \"title\": \"BBOXAnnotation\",\n        \"type\": \"object\",\n        \"additionalProperties\": false\n      },\n      \"name\": \"bbox_annotation\",\n      \"strict\": true\n    }\n  },\n  \"include_image_base64\": false\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "mistralCloudApi"
      },
      "credentials": {
        "mistralCloudApi": {
          "id": "mRwBaVJZsN6hIzkX",
          "name": "Mistral Cloud account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "3455c653-2b35-456d-8fb2-d5b99b3f9a9a",
      "name": "聚合",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        464,
        112
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "599c0eb8-803e-4450-966e-03672229f4f0",
      "name": "上传文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2160,
        112
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ukOlw9NKhJMJxRUB",
          "name": "Google Drive account 2"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4c96020e-fa32-4c26-bde9-ace0c69175b0",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        -64
      ],
      "parameters": {
        "color": 4,
        "height": 320,
        "content": "## 从Google Drive获取所有时间表"
      },
      "typeVersion": 1
    },
    {
      "id": "1b74e71a-8bc8-4c40-adf2-26d7633687a6",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        -256
      ],
      "parameters": {
        "width": 896,
        "height": 208,
        "content": "## MISTRAL OCR"
      },
      "typeVersion": 1
    },
    {
      "id": "4fe48089-1a95-43ae-8e9a-af3018321acc",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -288,
        368
      ],
      "parameters": {
        "width": 1232,
        "content": "## 图像OCR提取"
      },
      "typeVersion": 1
    },
    {
      "id": "2e823691-2dfc-4761-bb25-d6f4ab7495ab",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        48
      ],
      "parameters": {
        "width": 416,
        "height": 208,
        "content": "## 清理并将数据格式化为表格"
      },
      "typeVersion": 1
    },
    {
      "id": "3b3c8a3c-c27d-442f-9351-933c9340244f",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        16
      ],
      "parameters": {
        "width": 288,
        "height": 240,
        "content": "## AI代理"
      },
      "typeVersion": 1
    },
    {
      "id": "19fa9b90-2692-48c3-b440-acacb9e5b5b5",
      "name": "便签5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        32
      ],
      "parameters": {
        "width": 480,
        "height": 272,
        "content": "## 发送验证并等待响应,如果接受则保存到drive"
      },
      "typeVersion": 1
    },
    {
      "id": "896f8922-00ed-4906-8739-c0ff00432441",
      "name": "便签6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        48
      ],
      "parameters": {
        "width": 880,
        "height": 192,
        "content": "## EXCEL提取器"
      },
      "typeVersion": 1
    },
    {
      "id": "444cbca3-8ed1-414c-91fc-92ca6ef04a05",
      "name": "便签7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -672,
        0
      ],
      "parameters": {
        "width": 352,
        "height": 256,
        "content": "## 下载时间表"
      },
      "typeVersion": 1
    },
    {
      "id": "c6b6a8d7-a433-4d56-9bb9-01667580cea2",
      "name": "AI代理清理和格式化提取的数据",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1040,
        128
      ],
      "parameters": {
        "text": "=You must respond ONLY with valid raw rendered JSON.\n- Do NOT include the word \"json\".\n- Do NOT include the word \"```json\".\n- Do NOT use triple backticks or markdown formatting.\n- Do NOT wrap the response in any key like \"output\".\n- Do NOT write anything starting at output directly start with valid root-level JSON.\n- Only respond with a valid, root-level JSON object.\n- Do NOT skip any line item. \n\n\n{{ $json.content }}\n",
        "options": {
          "systemMessage": "=your sole function is to be a meticulous data extraction AI. Your task is to analyze the provided timesheet documents (images, PDFs, etc.) and convert the information into a structured JSON format with absolute precision, following the rules below.\n\n For each timesheet, first extract all summary-level information into the document_info object. This includes the contractor's name, the client or project name, the manager's name (if available), the end date of the timesheet period, and the total hours for the week.\n\n Next, extract each daily work log as an individual item. Process all daily entries sequentially. Each day worked must become a single object in the time_entries list. Ensure all fields for that day (date, day of the week, hours worked, and any description/notes) are correctly populated in its corresponding object.\n\nOutput Format\n\n#You must respond ONLY with valid raw rendered JSON.\n\n-Do NOT include the word \"json\".\n\n-Do NOT include ```json.\n\n-Do NOT use triple backticks or markdown formatting.\n\n-Do NOT wrap the response in any key like \"output\".\n\n-Do NOT write anything before the opening [ of the JSON array.\n\n-Only respond with a valid, root-level JSON array.\n\nDo NOT skip any daily line item. Continue extracting all line items until the sum of all hours_worked values from the time_entries array exactly equals the total_hours value extracted into the document_info object. This verification ensures that all entries are fully extracted and no entries are missed. If the totals do not match, keep parsing and extracting additional line items until they do. Only then stop\noutput format\n\n[\n  {\n    \"document_info\": {\n      \"type\": null,\n      \"date\": null,\n      \"customer_name\": null,\n      \"customer_number\": null,\n      \"supplier_number\": null,\n      \"order_number\": null\n    },\n    \"requested_items\": [\n      {\n        \"pos\": null,\n        \"article_number\": null,\n        \"customer_article_number\": null,\n        \"article_name\": null,\n        \"quantity\": null,\n        \"unit\": null,\n        \"delivery_date\": null\n      }\n    ]\n  }\n]\n"
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "0bd7a945-f240-4d42-8874-05f0d60d1b53",
      "name": "便签8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1024,
        -64
      ],
      "parameters": {
        "width": 208,
        "height": 304,
        "content": "## 遍历每个文件"
      },
      "typeVersion": 1
    },
    {
      "id": "ffc35899-5102-48ae-afdb-c025c5e199dd",
      "name": "清理excel数据格式",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        112
      ],
      "parameters": {
        "jsCode": "// Convert Excel serial date -> YYYY-MM-DD\nconst base = new Date(Date.UTC(1899, 11, 30));\nfunction fromSerial(s) {\n  if (!s || isNaN(Number(s))) return s; // skip if not a number\n  const ms = Number(s) * 86400 * 1000;\n  return new Date(base.getTime() + ms).toISOString().slice(0, 10);\n}\n\nreturn items.map(item => {\n  let row = { ...item.json };\n\n  // Convert possible date fields\n  if (row.__EMPTY && !isNaN(row.__EMPTY)) {\n    row.__EMPTY = fromSerial(row.__EMPTY);\n  }\n  if (row.__EMPTY_1 && !isNaN(row.__EMPTY_1) && row[\" Contractor Timesheet\"]?.includes(\"Weekending\")) {\n    row.__EMPTY_1 = fromSerial(row.__EMPTY_1);\n  }\n\n  return { json: row };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c2cde62a-8f6f-45c5-aa6c-1f8a05a9ddf8",
      "name": "规范化输出",
      "type": "n8n-nodes-base.set",
      "position": [
        624,
        112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "530eae36-2bc2-4f6f-8755-73b44da913e4",
              "name": "content",
              "type": "string",
              "value": "={{ $json.data }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b2247031-284b-4312-9169-9782948610eb",
      "name": "规范化输出1",
      "type": "n8n-nodes-base.set",
      "position": [
        816,
        -64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cefc6cbe-dcc3-4cd5-bf3c-735320ece1fe",
              "name": "content",
              "type": "string",
              "value": "={{ $json.pages[0].markdown }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "fd2bc3ff-fd6b-49f5-ab9a-6479ea55a565",
      "name": "规范化输出2",
      "type": "n8n-nodes-base.set",
      "position": [
        560,
        368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cefc6cbe-dcc3-4cd5-bf3c-735320ece1fe",
              "name": "content",
              "type": "string",
              "value": "={{ JSON.parse($json[\"data\"][0]).blocks[0].content }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4d85c2d7-a657-42a0-a6ab-c001e8dfd27e",
      "name": "清理AI输出",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        128
      ],
      "parameters": {
        "jsCode": "// input[0].json contains your JSON\nconst outputString = $json[\"output\"];\n\n// Parse the string\nconst parsedJSON = JSON.parse(outputString);\n\n// Return as n8n items\nreturn parsedJSON.map(item => ({ json: item }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "2120ff01-feb7-43fe-ad96-d2dc3c139dbf",
      "name": "json转html",
      "type": "n8n-nodes-base.code",
      "position": [
        1664,
        128
      ],
      "parameters": {
        "jsCode": "const data = $items()[0].json;\n\nlet html = `\n<h2>Timesheet Verification</h2>\n<p>Contractor: ${data.document_info.contractor_name}<br>\nClient: ${data.document_info.client_name}<br>\nManager: ${data.document_info.manager_name}<br>\nEnd Date: ${data.document_info.end_date}<br>\nTotal Hours: ${data.document_info.total_hours}</p>\n\n<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n<tr>\n<th>Day</th>\n<th>Date</th>\n<th>Hours</th>\n<th>Description</th>\n</tr>\n`;\n\ndata.time_entries.forEach(entry => {\n  // Safely handle null or empty description\n  const desc = entry.description ? entry.description.replace(/\\n/g, '<br>') : '';\n  \n  html += `\n<tr>\n<td>${entry.day_of_week}</td>\n<td>${entry.date}</td>\n<td>${entry.hours_worked}</td>\n<td>${desc}</td>\n</tr>`;\n});\n\nhtml += `</table>`;\n\nreturn [{ json: { email_body: html } }];\n"
      },
      "typeVersion": 2
    }
  ],
  "pinData": {},
  "connections": {
    "Aggregate": {
      "main": [
        [
          {
            "node": "normalize output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields3": {
      "main": [
        [
          {
            "node": "Mistral Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set File ID1": {
      "main": [
        [
          {
            "node": "Download File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "json to html": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download File": {
      "main": [
        [
          {
            "node": "Switch File Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "normalize output2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Upload": {
      "main": [
        [
          {
            "node": "Mistral Signed URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send a message": {
      "main": [
        [
          {
            "node": "Loop Over Items2",
            "type": "main",
            "index": 0
          },
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral DOC OCR": {
      "main": [
        [
          {
            "node": "normalize output1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "clean ai output": {
      "main": [
        [
          {
            "node": "json to html",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items2": {
      "main": [
        [],
        [
          {
            "node": "Set File ID1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch File Type": {
      "main": [
        [
          {
            "node": "Edit Fields3",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read Spreadsheet File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "normalize output": {
      "main": [
        [
          {
            "node": "AI Agent to clean and format exctracred data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "normalize output1": {
      "main": [
        [
          {
            "node": "AI Agent to clean and format exctracred data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "normalize output2": {
      "main": [
        [
          {
            "node": "AI Agent to clean and format exctracred data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Signed URL": {
      "main": [
        [
          {
            "node": "Mistral DOC OCR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Spreadsheet File": {
      "main": [
        [
          {
            "node": "Clean excel data format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean excel data format": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search files and folders": {
      "main": [
        [
          {
            "node": "Loop Over Items2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Cloud Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent to clean and format exctracred data",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "Search files and folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent to clean and format exctracred data": {
      "main": [
        [
          {
            "node": "clean ai output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

高级 - 内容创作, 多模态 AI

需要付费吗?

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

工作流信息
难度等级
高级
节点数量32
分类2
节点类型13
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

外部链接
在 n8n.io 查看

分享此工作流