8
n8n 中文网amn8n.com

使用Claude AI、GoMarble MCP和Google幻灯片自动生成每周营销摘要演示文稿副本

中级

这是一个Document Extraction, Multimodal AI领域的自动化工作流,包含 15 个节点。主要使用 Set, Code, Gmail, GoogleDrive, HttpRequest 等节点。 使用Claude AI、GoMarble MCP和Google幻灯片自动化每周Meta广告报告

前置要求
  • Google 账号和 Gmail API 凭证
  • Google Drive API 凭证
  • 可能需要目标 API 的认证凭证
  • Anthropic API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "AmaZWuAXZJlrGq5l",
  "meta": {
    "instanceId": "07ccff49d71cc6b20dddb867ba4ad10dc1f2bd4ad81c28a9330420f0a4ac0b51",
    "templateCredsSetupCompleted": true
  },
  "name": "使用 Claude AI、GoMarble MCP 和 Google Slides 自动生成每周营销摘要演示文稿副本",
  "tags": [],
  "nodes": [
    {
      "id": "4bf29e91-9786-4035-9cae-c795795aded5",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        580,
        -40
      ],
      "parameters": {
        "text": "={{ $json['Report Prompt'] }}",
        "options": {
          "systemMessage": "You are a senior digital marketing professional. You MUST always return exactly 5 slides in your JSON response. There should be no made up data or hallucination, but if insufficient data exists for a slide, use placeholder text like 'Data pending analysis' or 'No significant changes this period'."
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "97d9bdf1-4758-4222-b05f-4544e8e64fcc",
      "name": "定时触发器",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": ":alarm_clock: Runs every Monday at 8 AM - adjust schedule as needed",
      "position": [
        100,
        -40
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ed8dddf4-fe74-49b4-922e-a390c53a03d4",
      "name": "GoMarble MCP",
      "type": "@n8n/n8n-nodes-langchain.mcpClientTool",
      "notes": ":closed_lock_with_key: Add your GoMarble Bearer token - get it from https://www.gomarble.ai/docs/connect-to-n8n",
      "position": [
        800,
        160
      ],
      "parameters": {
        "sseEndpoint": "https://apps.gomarble.ai/mcp-api/sse",
        "authentication": "bearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "6F65J7hlA4wzSeid",
          "name": "Bearer Auth account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "21fa31be-5754-4917-bd6b-20862d3ea4bc",
      "name": "下载文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1780,
        -40
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{$json.presentationId}}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "daPp0U6XEYaYQnlD",
          "name": "Google Drive account 2"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "5a805b50-3ae4-4488-9536-e3a569602fd4",
      "name": "Anthropic 聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        520,
        160
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-20250514",
          "cachedResultName": "Claude 4 Sonnet"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "id": "XMYEac7S3M6Hi7I5",
          "name": "Anthropic account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "381eafea-79d6-46ed-b0cb-8d0802f83e9a",
      "name": "发送电子邮件",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1940,
        -40
      ],
      "webhookId": "be82cd6b-8d18-4459-9b02-9ad01db01d38",
      "parameters": {
        "sendTo": "amancliff1@gmail.com",
        "message": "=Here is the Weekly Ad Performance Summary Deck - {{ $now.format('MM-DD') }}\".",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "=Weekly Summary Deck - {{ $now.format('MM-DD') }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "NMqbcdXNnH8EIv8G",
          "name": "Gmail account 7"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "13fde168-5855-4509-8490-2dac61abd7f1",
      "name": "报告提示",
      "type": "n8n-nodes-base.set",
      "notes": "🔧 EDIT THIS NODE to change:\n• Account Name & ID\n• Email Recipients\n• Report Settings",
      "position": [
        420,
        -40
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f2864549-d51c-4aad-b1cf-9a731e86b816",
              "name": "=Report Prompt",
              "type": "string",
              "value": "=You are a **senior performance‑marketing analyst**.\n\nVoice: sharp, concise, insight‑driven (no fluff, no marketing hype).  \nGoal: craft a weekly digest that a busy CMO can scan in < 3 min and act on immediately.  \n\nAd Account: {{ $json.accountName }}.\nTime Period: last 7 days  \n\n---\n\nCALL TOOL  \nUse **GoMarble MCP** with:  \n{\n  \"period\": \"last_7_days\"\n}  \nIt returns JSON metrics for Meta Ads.\n\n---\n\nAFTER the tool result is returned, you MUST output exactly ONE valid JSON object with EXACTLY 5 slides—nothing else:\n\n{\n  \"slides\": [\n    {\n      \"title\": \"Executive Snapshot\",\n      \"body\": \"<3‑line paragraph>  ▸ One‑sentence topline: combined spend, revenue, ROAS, and WoW % change.\\n▸ One‑sentence highlight of the biggest win.\\n▸ One‑sentence note on the main risk / action gap.\"\n    },\n    {\n      \"title\": \"Channel KPIs\",\n      \"tableData\": {\n        \"Spend\": \"$X,XXX\",\n        \"Impressions\": \"XXX,XXX\",\n        \"Clicks\": \"X,XXX\",\n        \"CTR\": \"X.XX%\",\n        \"CPC\": \"$X.XX\",\n        \"Conversions\": \"XX\",\n        \"CPA\": \"$XXX\",\n        \"Revenue\": \"$X,XXX\",\n        \"ROAS\": \"X.XX\",\n        \"WoW Change\": \"+/-XX%\"\n      }\n    },\n    {\n      \"title\": \"Top Campaigns\",\n      \"body\": \"<bullet list of the single best campaign per platform with why it won (1‑sentence each)>\"\n    },\n    {\n      \"title\": \"Under‑performers\",\n      \"body\": \"<bullet list of key weak campaigns with brief reason & WoW drop (1‑sentence each)>\"\n    },\n    {\n      \"title\": \"Action Recos\",\n      \"body\": \"<2‑3 crisp, prioritised recommendations the team should execute next week>\"\n    }\n  ]\n}\n\nCRITICAL RULES  \n– Return ONLY JSON (no Markdown fences, no explanations).  \n– EXACTLY 5 slide objects - NO MORE, NO LESS. This is mandatory.\n– For Channel KPIs: Use \"tableData\" object with key-value pairs for metrics (no pipe separators)\n– Use \\n for line breaks and keep sections tight and scannable\n– Keep each \"body\" < 120 words; use \\n for line breaks.  \n– Do NOT include any keys other than \"slides\".\n– The JSON must be valid and parseable.\n– Count your slides before responding - there must be exactly 5."
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8ca128ec-4f51-4d38-9c3e-bbcff815e765",
      "name": "创建演示文稿",
      "type": "n8n-nodes-base.httpRequest",
      "notes": ":bar_chart: Creates empty presentation",
      "position": [
        1080,
        -40
      ],
      "parameters": {
        "url": "https://slides.googleapis.com/v1/presentations",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"title\": \"Weekly Ad Report – {{ $now.format('MM-DD') }}\"\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSlidesOAuth2Api"
      },
      "credentials": {
        "googleSlidesOAuth2Api": {
          "id": "gSaMa5Jnq7KRBH8v",
          "name": "Google Slides account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "8f85ce4e-ac53-45b3-9b59-0052787abebd",
      "name": "广告账户",
      "type": "n8n-nodes-base.set",
      "notes": "🔧 EDIT THIS NODE to change:\n• Account Name & ID\n• Email Recipients\n• Report Settings",
      "position": [
        260,
        -40
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "account-name",
              "name": "accountName",
              "type": "string",
              "value": "Long Surf"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ed8739ef-8efb-466b-8ca6-99548c809e66",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        220,
        -180
      ],
      "parameters": {
        "width": 220,
        "height": 100,
        "content": "请在下方节点中添加需要生成摘要演示文稿的 Facebook 广告账户名称。"
      },
      "typeVersion": 1
    },
    {
      "id": "632111c0-3c1e-42cb-b605-83f39d55bb0d",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        -180
      ],
      "parameters": {
        "width": 200,
        "height": 100,
        "content": "请在下方节点中添加您希望接收摘要演示文稿的电子邮件地址。"
      },
      "typeVersion": 1
    },
    {
      "id": "7319e6ac-e678-4bcb-b0ab-6648490e5cf0",
      "name": "验证幻灯片输出",
      "type": "n8n-nodes-base.code",
      "notes": ":lock: GUARANTEES exactly 5 slides - no more, no less",
      "position": [
        900,
        -40
      ],
      "parameters": {
        "jsCode": "console.log('Raw AI output:', $json.output);\n\ntry {\n  let jsonString = $json.output;\n  \n  // Remove markdown code fences if present\n  if (jsonString.includes('```json')) {\n    console.log('Removing markdown fences');\n    jsonString = jsonString.replace(/```json\\n?/g, '').replace(/```\\n?$/g, '');\n  }\n  \n  // Remove any leading \"json\\n\" or similar\n  jsonString = jsonString.replace(/^json\\n/g, '');\n  \n  // Clean up any extra whitespace\n  jsonString = jsonString.trim();\n  \n  console.log('Cleaned JSON string:', jsonString.substring(0, 200) + '...');\n  \n  const output = JSON.parse(jsonString);\n  console.log(`Successfully parsed! Found ${output.slides.length} slides`);\n  \n  // Return the slides directly from AI (now with tableData support)\n  return [{ json: { slides: output.slides } }];\n  \n} catch (e) {\n  console.error('JSON parsing failed:', e.message);\n  console.log('Attempting manual extraction...');\n  \n  // Try to extract JSON from between { and }\n  const match = $json.output.match(/\\{[\\s\\S]*\\}/);\n  if (match) {\n    try {\n      const output = JSON.parse(match[0]);\n      console.log('Manual extraction successful!');\n      return [{ json: { slides: output.slides } }];\n    } catch (e2) {\n      console.log('Manual extraction also failed');\n    }\n  }\n  \n  // Last resort: return fallback with table structure for Channel KPIs\n  const fallbackSlides = [\n    { \n      title: \"Executive Snapshot\", \n      body: \"Weekly performance data is currently being processed. Report will be available shortly.\" \n    },\n    { \n      title: \"Channel KPIs\", \n      tableData: {\n        \"Spend\": \"Data pending\",\n        \"Impressions\": \"Data pending\",\n        \"Clicks\": \"Data pending\",\n        \"CTR\": \"Data pending\",\n        \"CPC\": \"Data pending\",\n        \"Conversions\": \"Data pending\",\n        \"CPA\": \"Data pending\",\n        \"Revenue\": \"Data pending\",\n        \"ROAS\": \"Data pending\",\n        \"WoW Change\": \"Data pending\"\n      }\n    },\n    { \n      title: \"Top Campaigns\", \n      body: \"Campaign performance analysis is in progress. Top-performing campaigns will be highlighted once data processing is complete.\" \n    },\n    { \n      title: \"Under-performers\", \n      body: \"Performance analysis not available at this time. Underperforming campaigns will be identified in the next report.\" \n    },\n    { \n      title: \"Action Recos\", \n      body: \"Strategic recommendations will be provided once performance data analysis is complete. Please check the next scheduled report.\" \n    }\n  ];\n  \n  return [{ json: { slides: fallbackSlides } }];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "7a17068d-a6ae-46e5-9b37-3c5157291bf1",
      "name": "格式化幻灯片数据",
      "type": "n8n-nodes-base.code",
      "notes": ":wrench: Prepares the batch request with slide data",
      "position": [
        1440,
        -40
      ],
      "parameters": {
        "jsCode": "// Get the data from the Combine Data node\nconst presentationId = $json.presentationId;\nconst slides = $json.slides;\n\nconst requests = [\n  // Delete the default slide first\n  {\n    deleteObject: { objectId: 'p' }\n  }\n];\n\n// Create exactly 5 slides with content\nslides.forEach((slide, index) => {\n  const slideId = `slide_${index + 1}`;\n  const titleId = `${slideId}_title`;\n  \n  // Create slide\n  requests.push({\n    createSlide: {\n      objectId: slideId,\n      slideLayoutReference: { predefinedLayout: 'TITLE_AND_BODY' },\n      placeholderIdMappings: [\n        { layoutPlaceholder: { type: 'TITLE', index: 0 }, objectId: titleId },\n        { layoutPlaceholder: { type: 'BODY', index: 0 }, objectId: `${slideId}_body` }\n      ]\n    }\n  });\n  \n  // Add title\n  requests.push({\n    insertText: { objectId: titleId, insertionIndex: 0, text: slide.title }\n  });\n  \n  // Handle Channel KPIs slide with table\n  if (slide.title === \"Channel KPIs\" && slide.tableData) {\n    const tableId = `${slideId}_table`;\n    \n    // Create table (2 columns, 10 rows for the metrics)\n    requests.push({\n      createTable: {\n  objectId: tableId,\n  elementProperties: {\n    pageObjectId: slideId,\n    size: { width: { magnitude: 350, unit: 'PT' }, height: { magnitude: 200, unit: 'PT' } },\n    transform: {\n      scaleX: 1, scaleY: 1, translateX: 185, translateY: 80, unit: 'PT'\n    }\n  },\n  rows: 10,\n  columns: 2\n}\n    });\n    \n    // Populate table with data\n    const metrics = Object.entries(slide.tableData);\n    metrics.forEach(([metric, value], rowIndex) => {\n      // Insert metric name in first column\n      requests.push({\n        insertText: {\n          objectId: tableId,\n          cellLocation: { rowIndex: rowIndex, columnIndex: 0 },\n          insertionIndex: 0,\n          text: metric\n        }\n      });\n      \n      // Insert metric value in second column\n      requests.push({\n        insertText: {\n          objectId: tableId,\n          cellLocation: { rowIndex: rowIndex, columnIndex: 1 },\n          insertionIndex: 0,\n          text: value\n        }\n      });\n    });\n    \n  } else {\n    // For all other slides, use regular text insertion\n    const bodyId = `${slideId}_body`;\n    requests.push({\n      insertText: { objectId: bodyId, insertionIndex: 0, text: slide.body }\n    });\n  }\n});\n\nreturn [{\n  json: {\n    presentationId: presentationId,\n    batchUpdateBody: { requests: requests }\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "cd89420c-20be-4d70-b4b3-2b7fc0a80315",
      "name": "构建演示文稿",
      "type": "n8n-nodes-base.httpRequest",
      "notes": ":page_facing_up: Executes the batch update to create all slides",
      "position": [
        1600,
        -40
      ],
      "parameters": {
        "url": "=https://slides.googleapis.com/v1/presentations/{{$json.presentationId}}:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={{JSON.stringify($json.batchUpdateBody)}}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSlidesOAuth2Api"
      },
      "credentials": {
        "googleSlidesOAuth2Api": {
          "id": "gSaMa5Jnq7KRBH8v",
          "name": "Google Slides account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "27755c4f-b75f-45c8-a674-21b3826082e9",
      "name": "合并演示文稿信息",
      "type": "n8n-nodes-base.set",
      "notes": ":link: Combines presentation ID with slide data",
      "position": [
        1260,
        -40
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "presentation-id",
              "name": "presentationId",
              "type": "string",
              "value": "={{$json.presentationId}}"
            },
            {
              "id": "slides-data",
              "name": "slides",
              "type": "array",
              "value": "={{$items('Validate slide output')[0].json.slides}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "6f834adc-d3d9-466e-8f9b-36668904af1f",
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Validate slide output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ad Account": {
      "main": [
        [
          {
            "node": "Report Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GoMarble MCP": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Download file": {
      "main": [
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Report Prompt": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Ad Account",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Slides Data": {
      "main": [
        [
          {
            "node": " Build Presentation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    " Build Presentation": {
      "main": [
        [
          {
            "node": "Download file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Presentation": {
      "main": [
        [
          {
            "node": "Merge Presentation Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Validate slide output": {
      "main": [
        [
          {
            "node": "Create Presentation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Presentation Info": {
      "main": [
        [
          {
            "node": "Format Slides Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

中级 - 文档提取, 多模态 AI

需要付费吗?

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

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

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

外部链接
在 n8n.io 查看

分享此工作流