Génération automatique de présentations de résumé marketing hebdomadaire avec Claude AI, GoMarble MCP et Google Slides

Intermédiaire

Ceci est unDocument Extraction, Multimodal AIworkflow d'automatisation du domainecontenant 15 nœuds.Utilise principalement des nœuds comme Set, Code, Gmail, GoogleDrive, HttpRequest. Automatiser les rapports publicitaires hebdomadaires Meta avec Claude AI, GoMarble MCP et Google Slides

Prérequis
  • Compte Google et informations d'identification Gmail API
  • Informations d'identification Google Drive API
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
  • Clé API Anthropic
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "id": "AmaZWuAXZJlrGq5l",
  "meta": {
    "instanceId": "07ccff49d71cc6b20dddb867ba4ad10dc1f2bd4ad81c28a9330420f0a4ac0b51",
    "templateCredsSetupCompleted": true
  },
  "name": "Copy ofAutomate Weekly Marketing Summary Deck with Claude AI, GoMarble MCP & Google Slides",
  "tags": [],
  "nodes": [
    {
      "id": "4bf29e91-9786-4035-9cae-c795795aded5",
      "name": "Agent IA",
      "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": "Déclencheur programmé",
      "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": "Télécharger le fichier",
      "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 Chat Model",
      "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": "Envoyer un e-mail",
      "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": "Invite de rapport",
      "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": "Créer une présentation",
      "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": "Compte publicitaire",
      "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": "Note autocollante",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        220,
        -180
      ],
      "parameters": {
        "width": 220,
        "height": 100,
        "content": "Please add the name of the Facebook ad account in the node below for which you need the summary deck."
      },
      "typeVersion": 1
    },
    {
      "id": "632111c0-3c1e-42cb-b605-83f39d55bb0d",
      "name": "Note autocollante 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        -180
      ],
      "parameters": {
        "width": 200,
        "height": 100,
        "content": "Please add the email ID in the node below to which you want the summary deck sent."
      },
      "typeVersion": 1
    },
    {
      "id": "7319e6ac-e678-4bcb-b0ab-6648490e5cf0",
      "name": "Valider le contenu des diapositives",
      "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": "Formater les données des diapositives",
      "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": "Construire la présentation",
      "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": "Fusionner les informations de présentation",
      "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": {
    "4bf29e91-9786-4035-9cae-c795795aded5": {
      "main": [
        [
          {
            "node": "7319e6ac-e678-4bcb-b0ab-6648490e5cf0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8f85ce4e-ac53-45b3-9b59-0052787abebd": {
      "main": [
        [
          {
            "node": "13fde168-5855-4509-8490-2dac61abd7f1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ed8dddf4-fe74-49b4-922e-a390c53a03d4": {
      "ai_tool": [
        [
          {
            "node": "4bf29e91-9786-4035-9cae-c795795aded5",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "21fa31be-5754-4917-bd6b-20862d3ea4bc": {
      "main": [
        [
          {
            "node": "381eafea-79d6-46ed-b0cb-8d0802f83e9a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "13fde168-5855-4509-8490-2dac61abd7f1": {
      "main": [
        [
          {
            "node": "4bf29e91-9786-4035-9cae-c795795aded5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "97d9bdf1-4758-4222-b05f-4544e8e64fcc": {
      "main": [
        [
          {
            "node": "8f85ce4e-ac53-45b3-9b59-0052787abebd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7a17068d-a6ae-46e5-9b37-3c5157291bf1": {
      "main": [
        [
          {
            "node": "cd89420c-20be-4d70-b4b3-2b7fc0a80315",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "cd89420c-20be-4d70-b4b3-2b7fc0a80315": {
      "main": [
        [
          {
            "node": "21fa31be-5754-4917-bd6b-20862d3ea4bc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8ca128ec-4f51-4d38-9c3e-bbcff815e765": {
      "main": [
        [
          {
            "node": "27755c4f-b75f-45c8-a674-21b3826082e9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5a805b50-3ae4-4488-9536-e3a569602fd4": {
      "ai_languageModel": [
        [
          {
            "node": "4bf29e91-9786-4035-9cae-c795795aded5",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "7319e6ac-e678-4bcb-b0ab-6648490e5cf0": {
      "main": [
        [
          {
            "node": "8ca128ec-4f51-4d38-9c3e-bbcff815e765",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "27755c4f-b75f-45c8-a674-21b3826082e9": {
      "main": [
        [
          {
            "node": "7a17068d-a6ae-46e5-9b37-3c5157291bf1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Intermédiaire - Extraction de documents, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Intermédiaire
Nombre de nœuds15
Catégorie2
Types de nœuds10
Description de la difficulté

Adapté aux utilisateurs expérimentés, avec des workflows de complexité moyenne contenant 6-15 nœuds

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34