Task: Personalize LinkedIn Invitation with GPT4

n8n workflow:
{"id":"17","meta":{"instanceId":"eb11e40cd56b6230ee02fccc1160b93e55a779dfdcf12d80af68ddde0905f94b"},"name":"Personalize Linkedin Invitation","tags":[],"nodes":[{"id":"361a91b0-0f96-4c4a-aa2b-27612834e047","name":"FilterOnPostDate","type":"n8n-nodes-base.code","position":[2220,20],"parameters":{"jsCode":"const maxMonths = 6;\nconst currentTime = new Date();\n\nconst filteredData = items.reduce((result, item) => {\n  const postUrl = item.json.PorifleURL;\n  const posts = item.json.Posts || [];\n  const filteredPosts = posts.filter(post => {\n    const postAge = post.postDate;\n    if (!postAge) {\n      return false;\n    }\n    const value = parseInt(postAge);\n    const unit = postAge.slice(-1);\n\n    switch (unit) {\n      case 'h':\n        return currentTime - new Date(currentTime.getTime() - value * 60 * 60 * 1000) < maxMonths * 30 * 24 * 60 * 60 * 1000;\n      case 'd':\n        return currentTime - new Date(currentTime.getTime() - value * 24 * 60 * 60 * 1000) < maxMonths * 30 * 24 * 60 * 60 * 1000;\n      case 'w':\n        return currentTime - new Date(currentTime.getTime() - value * 7 * 24 * 60 * 60 * 1000) < maxMonths * 30 * 24 * 60 * 60 * 1000;\n      case 'm':\n        return value <= maxMonths;\n      case 'y':\n        return value * 12 < maxMonths;\n      default:\n        return false;\n    }\n  });\n\n  if (filteredPosts.length > 0) {\n    result.push({\n      json: {\n        postUrl,\n        Posts: filteredPosts,\n      },\n    });\n  }\n  \n  return result;\n}, []);\n\nreturn filteredData;\n"},"typeVersion":1,"continueOnFail":true,"alwaysOutputData":true},{"id":"707786b9-5838-4f26-9d9c-13a0c4169f43","name":"Scoring Model","type":"n8n-nodes-base.code","position":[2940,20],"parameters":{"jsCode":"// Assume that your JSON data is stored in an array called `items`\nconst itemsWithScores = items.map(item => {\n  // Retrieve the LikeCount, CommentCount, and RepostCount values from `item.json`\n  const likeCount = item.json.likeCount || 0;\n  const commentCount = item.json.commentCount || 0;\n  const repostCount = item.json.repostCount || 0;\n\n  // Calculate the score using the provided formula\n  const score = likeCount * 1 + commentCount * 4 + repostCount * 7;\n\n  // Add the calculated score to the output JSON object\n  return { ...item, json: { ...item.json, score } };\n});\n\n// Find the item with the highest score\nconst highestScoreItem = itemsWithScores.reduce((maxItem, currentItem) => {\n  return currentItem.json.score > maxItem.json.score ? currentItem : maxItem;\n});\n\n// Return only the item with the highest score\nreturn [highestScoreItem];\n"},"typeVersion":1},{"id":"6f481a78-d292-48e3-9ee1-d34dec1cd53a","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[2880,-240],"parameters":{"height":517.5739044852746,"content":"### Top LinkedIn Post\n\nCalculates engagement scores and returns the highest-scoring LinkedIn post."},"typeVersion":1},{"id":"015854ae-381a-4d99-8f02-3fded9b76a11","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[3440,-240],"parameters":{"width":269.7693811074919,"height":971.3432893154281,"content":"### Generate Personalized message\n\nThis node includes the User and the system specifications"},"typeVersion":1},{"id":"c51e29de-a2e1-4975-9a08-1973edb292ee","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1915.3073615635167,-240],"parameters":{"width":795.1697719869705,"height":503.1984364820845,"content":"## Exclude over 6 months posts\n\nThose two nodes will help to exclude the posts that have been published for more than 6 months"},"typeVersion":1},{"id":"2386975e-8a5e-4f29-8a64-1b85a61d7602","name":"Webhook","type":"n8n-nodes-base.webhook","position":[440,220],"webhookId":"a4215ccc-ce34-41eb-a0e1-67141bf68611","parameters":{"path":"a4215ccc-ce34-41eb-a0e1-67141bf68611","options":{},"httpMethod":"POST"},"typeVersion":1},{"id":"0023c749-01ee-4338-acb1-89164c7a8ff5","name":"Person Active in Linkedin ?","type":"n8n-nodes-base.if","position":[1600,200],"parameters":{"conditions":{"number":[{"value1":"={{ $json.error }}","operation":"isEmpty"}]}},"typeVersion":1},{"id":"3374cc2b-4408-4762-ade8-b8d2fe9e200b","name":"GetData","type":"n8n-nodes-base.set","position":[1960,20],"parameters":{"values":{"string":[{"name":"ProfileUrl","value":"={{ $node.GetOutput.json.profileUrl }}"},{"name":"Posts","value":"={{ $json.posts }}"}]},"options":{},"keepOnlySet":true},"typeVersion":2,"continueOnFail":true,"alwaysOutputData":true},{"id":"a4e03df7-9b16-4178-ae6e-9df5e0f7ef34","name":"GetOutput","type":"n8n-nodes-base.phantombuster","position":[760,220],"parameters":{"agentId":"={{ $json.body.agentId }}","operation":"getOutput","additionalFields":{}},"credentials":{"phantombusterApi":{"id":"16","name":"Phantombuster account Tuto"}},"typeVersion":1},{"id":"a02d14e6-a374-486f-a961-658ac84f5288","name":"Group JSON Items by Profile URL","type":"n8n-nodes-base.code","position":[1040,220],"parameters":{"jsCode":"const data = items.map((item) => item.json);\n\n// Key to group items by\nconst groupByKey = 'profileUrl'; // Replace this with any other key present in your JSON data\n\n// 1. Group items with common key and combine posts details\nconst groupedItems = data.reduce((acc, item) => {\n  const keyValue = item[groupByKey];\n  if (!acc[keyValue]) {\n    acc[keyValue] = { ...item, posts: [item] };\n  } else {\n    acc[keyValue].posts.push(item);\n  }\n  return acc;\n}, {});\n\n// 2. Get the unique items with the specified key and combined posts details\nconst uniqueItemsWithKeyAndPosts = Object.values(groupedItems);\n\n// Process unique items as needed, for example:\nuniqueItemsWithKeyAndPosts.forEach((item) => {\n  console.log(item);\n});\n\nreturn uniqueItemsWithKeyAndPosts.map((item) => ({ json: item }));\n"},"typeVersion":1},{"id":"92aedbb1-8dd3-453e-9373-c55d5afcfe0b","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[980,-20],"parameters":{"width":453.902857142857,"height":463.542857142857,"content":"## I'm a note \n**This node groups JSON items** based on a common 'profileUrl' property and combines their post details into a single 'posts' property for each unique profile."},"typeVersion":1},{"id":"3ed0fdb3-b351-4ba0-a14e-ee3cf63ef4f7","name":"Split In Batches","type":"n8n-nodes-base.splitInBatches","position":[1260,220],"parameters":{"options":{},"batchSize":1},"typeVersion":2},{"id":"8250b18c-cfe2-480d-b347-18064cc0c2a0","name":"Item Lists","type":"n8n-nodes-base.itemLists","position":[2580,20],"parameters":{"options":{},"fieldToSplitOut":"Posts"},"typeVersion":2},{"id":"1b144ad5-4fbf-4ebd-b87e-5e458c239c88","name":"PromptData","type":"n8n-nodes-base.set","position":[3220,20],"parameters":{"values":{"string":[{"name":"ProfileUrl","value":"={{ $node.GetData.json.PorifleURL }}"}]},"options":{}},"typeVersion":2},{"id":"e73bb51e-155e-401f-9cd8-7a02dfb0ad18","name":"IF1","type":"n8n-nodes-base.if","position":[4100,220],"parameters":{"conditions":{"boolean":[{"value1":"={{$node[\"Split In Batches\"].context[\"noItemsLeft\"]}}","value2":true}]}},"typeVersion":1},{"id":"281b8366-f7dd-4c11-a341-1d0be1387eea","name":"No Operation, do nothing","type":"n8n-nodes-base.noOp","position":[4420,200],"parameters":{},"typeVersion":1},{"id":"1850e5f7-5258-429c-ac15-d9a1610f87c1","name":"PostPrompt","type":"n8n-nodes-base.openAi","position":[3520,20],"parameters":{"model":"gpt-4","prompt":{"messages":[{"content":"Vous êtes un assistant virtuel qui aide à personnaliser les invitations LinkedIn"},{"role":"system","content":"=Je m'appelle Abdallag, Head of Growth chez Gemna, et je suis passionné par le Growth. \nJ'ai récemment remarqué que {{ $json.profileUrl }} a partagé un post sur Linkedin {{ $json.postUrl }}, et cela a suscité mon intérêt. Pourriez-vous m'aider à rédiger un message amical pour établir un lien et montrer mon intérêt pour ce sujet, sans être trop direct ou promotionnel ?  \n\nVoici le contenu du post :  {{ $json.postContent }}"},{"role":"system","content":"=Je souhaite également poser une question à  {{ $json.profileUrl }} concernant leur post. Pourriez-vous m'aider à formuler une demande polie pour poser cette question et expliquer que je souhaite les ajouter à mon réseau pour en discuter ?\nle texte ne doit pas dépasser 50 mots.\nUtilise une voix pleine d'esprit."}]},"options":{},"resource":"chat"},"credentials":{"openAiApi":{"id":"15","name":"OpenAi account Mahdi"}},"typeVersion":1},{"id":"685c4f85-0a93-402c-8ee3-3639a9d27439","name":"ScrapProfil","type":"n8n-nodes-base.phantombuster","position":[1960,540],"parameters":{"agentId":"=3928939638003166","additionalFields":{"argumentsUi":{"argumentValues":[{"key":"sessionCookie"},{"key":"spreadsheetUrl","value":"={{ $json.profileUrl }}"}]}}},"credentials":{"phantombusterApi":{"id":"16","name":"Phantombuster account Tuto"}},"typeVersion":1},{"id":"5fc8f9c3-a286-4311-8883-a5aa6e1598f2","name":"GetProfileInfo","type":"n8n-nodes-base.phantombuster","position":[2500,540],"parameters":{"agentId":"=3928939638003166","operation":"getOutput","additionalFields":{}},"credentials":{"phantombusterApi":{"id":"16","name":"Phantombuster account Tuto"}},"typeVersion":1},{"id":"d5bb98cd-2251-40ed-a2ac-dbebd5d6e759","name":"ProfilePrompt","type":"n8n-nodes-base.openAi","position":[3520,540],"parameters":{"model":"gpt-4","prompt":{"messages":[{"content":"Vous êtes un assistant virtuel qui aide à personnaliser les invitations LinkedIn"},{"role":"system","content":"=Je m'appelle Abdallah, Head of Growth chez Gemna, et je suis passionné par le Growth. \nJ'ai récemment consulté le profil LinkedIn de cette personne : {{ $json.general.profileUrl }}"},{"role":"system","content":"=Je souhaite également poser une question à  {{ $json.general.profileUrl }} qui lui intéresse sur son domaine en utilisant ces données.\nPourriez-vous m'aider à formuler une demande polie pour poser cette question et expliquer que je souhaite les ajouter à mon réseau pour en discuter ?\nDonnées : \nHeadline : {{ $json.general.headline }}\nDescription : {{ $json.general.description }}\nDescription de son entreprise actuelle : {{ $json.jobs[0].description }}\n\nle texte ne doit pas dépasser 50 mots.\nUtilise une voix pleine d'esprit.  \nTermine le message avec une question seulement"}]},"options":{},"resource":"chat"},"credentials":{"openAiApi":{"id":"15","name":"OpenAi account Mahdi"}},"typeVersion":1},{"id":"c01c5e91-b947-449a-91ee-f69279ee9487","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[3760,-240],"parameters":{"height":971.106188925082,"content":"## Send data to Campaign\n\nYou can change this node by your tool "},"typeVersion":1},{"id":"476c2cc4-c904-44a7-a708-f04babe0ff6a","name":"LemlistPostIcebreaker","type":"n8n-nodes-base.lemlist","position":[3820,20],"parameters":{"resource":"lead","additionalFields":{"icebreaker":""}},"typeVersion":1},{"id":"d00f9af2-7ce5-4c29-9877-f547df532cea","name":"LemlistProfileIcebreaker","type":"n8n-nodes-base.lemlist","position":[3820,540],"parameters":{"resource":"lead","additionalFields":{"icebreaker":""}},"typeVersion":1},{"id":"61bdbdad-4193-4593-a25d-a1629880cb94","name":"Wait","type":"n8n-nodes-base.wait","position":[2240,540],"webhookId":"9cf2a15f-e312-4ba0-950e-ac1da3a75095","parameters":{"unit":"minutes","amount":5},"typeVersion":1},{"id":"e6744286-5fa1-4b09-8e4f-0db4b4663c4b","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[1940,440],"parameters":{"width":747.8306188925079,"height":301.84234527687255,"content":"## Update your agent Id\n"},"typeVersion":1}],"active":true,"pinData":{},"settings":{},"versionId":"153ec80d-2dbe-4f49-bd28-6b470390aaab","connections":{"IF1":{"main":[[{"node":"No Operation, do nothing","type":"main","index":0}],[{"node":"Split In Batches","type":"main","index":0}]]},"Wait":{"main":[[{"node":"GetProfileInfo","type":"main","index":0}]]},"GetData":{"main":[[{"node":"FilterOnPostDate","type":"main","index":0}]]},"Webhook":{"main":[[{"node":"GetOutput","type":"main","index":0}]]},"GetOutput":{"main":[[{"node":"Group JSON Items by Profile URL","type":"main","index":0}]]},"Item Lists":{"main":[[{"node":"Scoring Model","type":"main","index":0}]]},"PostPrompt":{"main":[[{"node":"LemlistPostIcebreaker","type":"main","index":0}]]},"PromptData":{"main":[[{"node":"PostPrompt","type":"main","index":0}]]},"ScrapProfil":{"main":[[{"node":"Wait","type":"main","index":0}]]},"ProfilePrompt":{"main":[[{"node":"LemlistProfileIcebreaker","type":"main","index":0}]]},"Scoring Model":{"main":[[{"node":"PromptData","type":"main","index":0}]]},"GetProfileInfo":{"main":[[{"node":"ProfilePrompt","type":"main","index":0}]]},"FilterOnPostDate":{"main":[[{"node":"Item Lists","type":"main","index":0}]]},"Split In Batches":{"main":[[{"node":"Person Active in Linkedin ?","type":"main","index":0}]]},"LemlistPostIcebreaker":{"main":[[{"node":"IF1","type":"main","index":0}]]},"LemlistProfileIcebreaker":{"main":[[{"node":"IF1","type":"main","index":0}]]},"Person Active in Linkedin ?":{"main":[[{"node":"GetData","type":"main","index":0}],[{"node":"ScrapProfil","type":"main","index":0}]]},"Group JSON Items by Profile URL":{"main":[[{"node":"Split In Batches","type":"main","index":0}]]}}}