Générateur de posts LinkedIn
Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 39 nœuds.Utilise principalement des nœuds comme Code, Merge, GoogleDrive, GoogleSheets, ScheduleTrigger. Usine de contenu LinkedIn : génération automatique de publications via GPT-5, DALL·E et Google Sheets
- •Informations d'identification Google Drive API
- •Informations d'identification Google Sheets API
- •Clé API OpenAI
Nœuds utilisés (39)
Catégorie
{
"id": "vnFLiG5oPRaa0GLT",
"meta": {
"instanceId": "4864679018d565a892ca43ce23dcbf870b964133cd1081846447be064da60377",
"templateCredsSetupCompleted": true
},
"name": "Linkedin Post Generator",
"tags": [],
"nodes": [
{
"id": "5d8195ac-0e4d-46a2-b215-e76088726704",
"name": "01_DémarrageAuto",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-336,
96
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 10
}
]
}
},
"typeVersion": 1.2
},
{
"id": "3606e466-c0e3-47e6-aac8-000cd2960fab",
"name": "02_ConstruireBrief",
"type": "n8n-nodes-base.code",
"position": [
-112,
96
],
"parameters": {
"jsCode": "return [{\n json: {\n brief: {\n audience: \"Product Managers, Senior Product Managers, founders, RMG players, startup & AI enthusiasts, Product Management enthusiasts, AI agent enthusiasts, AI product Management, AI workflow Enthusiasts, AI Productivity hackers\",\n geography: \"Global + India\",\n goals: [\"Reach/Awareness\", \"Authority building\", \"Personal branding\"],\n cta: [\"Comments\", \"Share\", \"Follow\"],\n topics: \"Anything relevant to target audience (startups, AI, fintech, gaming, RMG, etc.)\",\n angles: [\"Educational\", \"Contrarian\", \"Storytelling\", \"Framework-based\", \"Case study\"],\n tone: \"Sharp\",\n constraints: \"Avoid too much jargon, include data & sources\",\n link: null,\n avoid_duplication: false,\n trigger: \"cron\"\n }\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "d27e676c-fe72-41d0-ba06-64a31b0c2170",
"name": "03_GénérerIdée",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
96,
96
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-chat-latest",
"cachedResultName": "GPT-5-CHAT-LATEST"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are an AI that generates LinkedIn post ideas based on a given brief."
},
{
"content": "=Audience: {{$json[\"brief\"][\"audience\"]}}\nGeography: {{$json[\"brief\"][\"geography\"]}}\nGoals: {{$json[\"brief\"][\"goals\"].join(\", \")}}\nCall-to-action: {{$json[\"brief\"][\"cta\"].join(\", \")}}\nTopics: {{$json[\"brief\"][\"topics\"]}}\nAngles: {{$json[\"brief\"][\"angles\"].join(\", \")}}\nTone: {{$json[\"brief\"][\"tone\"]}}\nConstraints: {{$json[\"brief\"][\"constraints\"]}}\n\nTask:\n- Give me 5 raw LinkedIn post ideas (short titles or one-line descriptions only).\n- Do not write the full post.\n- Make them relevant, engaging, and fit the brief.\n- Avoid repeating themes from the last 60 days.\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "2c5ad466-a960-421d-b65e-7343957d354b",
"name": "Fusion",
"type": "n8n-nodes-base.merge",
"position": [
-304,
512
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "e2fc1a59-8082-4b57-b907-62b6f9ef6ad4",
"name": "05_ChoisirIdéeIA",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-144,
512
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are an editorial board for a LinkedIn thought-leadership account.\nYour job: pick ONE best idea from a shortlist of 3–8 ideas. \nYou must explain WHY and also RANK all candidates.\n\nConstraints:\n- Keep audience, geography, goals, tone, and constraints from the brief.\n- Prefer ideas with strong comment potential, data-backed, contrarian or framework-based angles.\n- Be very strict with clarity: avoid jargon-heavy picks.\n- Return STRICT JSON only, no extra text.\n"
},
{
"content": "=BRIEF:\n{{ JSON.stringify($item(0,\"02_BuildBrief\").$json.brief) }}\n\nCANDIDATE_IDEAS (after fuzzy-dedupe):\n{{ JSON.stringify($json.message.content.kept_fuzzy) }}\n\nTASK:\n1. Pick ONE best idea → \"chosenIdea\"\n2. Explain briefly why → \"why\"\n3. Rank ALL ideas with scores (1–10) and short notes → \"ranked\"\n\nOUTPUT SCHEMA:\n{\n \"chosenIdea\": \"<the one>\",\n \"why\": \"<reason>\",\n \"ranked\": [\n { \"idea\": \"<candidate>\", \"score\": <int>, \"note\": \"<short reason>\" }\n ]\n}\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "9aecf953-5e89-4434-b430-077ec3a598e1",
"name": "05b_FusionnerBriefEtChoix",
"type": "n8n-nodes-base.merge",
"position": [
144,
512
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "6881cd94-a7ed-43a5-9824-9594a9631596",
"name": "06_GénérerPublication",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
496,
512
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are an expert LinkedIn content strategist who writes sharp, scroll-stopping posts for Product Managers, founders, and AI enthusiasts. \nYou always:\n- Write in a clear, concise, and engaging style.\n- Use strong hooks, frameworks, and storytelling.\n- Avoid jargon and filler words.\n- Support with credible data/examples when relevant.\n- End with a simple call-to-action (CTA).\n"
},
{
"content": "=Generate a LinkedIn post draft.\n\n### Inputs:\n- Chosen Idea: {{$json.chosenIdea}}\n- Why it was chosen: {{$json.why}}\n- Brief:\n - Audience: {{$json.brief.audience}}\n - Geography: {{$json.brief.geography}}\n - Goals: {{$json.brief.goals}}\n - CTA options: {{$json.brief.cta}}\n - Topics: {{$json.brief.topics}}\n - Angles: {{$json.brief.angles}}\n - Tone: {{$json.brief.tone}}\n - Constraints: {{$json.brief.constraints}}\n\n### Requirements:\n1. Start with a strong hook (1–2 lines).\n2. Expand into insight or framework (4-5 short paragraphs, max 20 lines each).\n3. Add supporting data/reference if relevant (keep sharp, not academic).\n4. End with a clear CTA (pick from the CTA options).\n5. Keep tone = {{$json.brief.tone}}.\n6. Avoid jargon, keep sentences punchy.\n\n\nReturn the output in JSON:\n{\n \"post\": \"final LinkedIn post draft here\"\n}\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "2038c6a7-a0a1-47b4-8f8c-07ecc9219f2c",
"name": "05a_AnalyserIdéeChoisie",
"type": "n8n-nodes-base.code",
"position": [
320,
512
],
"parameters": {
"jsCode": "try {\n const raw = $json?.message?.content || \"{}\";\n const data = JSON.parse(raw); // content ke andar jo JSON string hai, use parse karte hain\n return [{\n json: {\n brief: $json.brief, // brief ko carry forward\n chosenIdea: data.chosenIdea, // TOP-LEVEL bana diya\n why: data.why,\n ranked: data.ranked\n }\n }];\n} catch (e) {\n return [{ json: { error: \"ParseError: content was not valid JSON\", detail: String(e), raw: $json?.message?.content } }];\n}\n"
},
"typeVersion": 2
},
{
"id": "f82d70ea-08fa-49db-8c88-dca6637ab547",
"name": "04_ExtraireListeIdées",
"type": "n8n-nodes-base.code",
"position": [
416,
96
],
"parameters": {
"jsCode": "// 1) Get the raw text from LLM\nconst raw = $json?.message?.content || \"\";\n\n// 2) Remove the meta lead-in and split lines\nlet lines = raw.split(\"\\n\")\n .map(l => l.trim())\n .filter(Boolean);\n\n// 3) Keep only likely idea lines (numbered items or bold lines)\n// e.g. \"1. **\\\"Why ...\\\"**\"\nconst ideaLines = lines.filter(l =>\n /^\\d+\\.\\s*/.test(l) || // numbered\n /^\\*\\*.+\\*\\*$/.test(l) // fully bold\n);\n\n// 4) Clean each line: strip numbering, bold, surrounding quotes, trailing punctuation\nfunction cleanOne(s){\n return s\n .replace(/^\\d+\\.\\s*/, \"\") // remove \"1. \"\n .replace(/^\\*\\*|\\*\\*$/g, \"\") // remove **bold**\n .replace(/^[-–•\\s]+/, \"\") // leading bullets/dashes\n .replace(/^\"+|\"+$/g, \"\") // leading/trailing quotes\n .replace(/[”“]/g, '\"') // smart quotes normalize\n .replace(/^\"|\"$/g, \"\") // quotes again (after normalize)\n .replace(/\\s{2,}/g, \" \") // collapse spaces\n .replace(/\\.*\\s*$/,\".\") // ensure single period end\n .trim();\n}\n\n// 5) Extract ideas; also catch cases where the text spans next line (ignore empty)\nlet ideas = ideaLines.map(cleanOne)\n .filter(i => i.length > 0);\n\n// 6) If we somehow got nothing (format changed), fallback: regex capture quoted chunks or numbered after the colon\nif (ideas.length === 0) {\n const numbered = [...raw.matchAll(/^\\s*\\d+\\.\\s*(.+)$/gm)].map(m => cleanOne(m[1]));\n const quoted = [...raw.matchAll(/\"([^\"]{10,})\"/g)].map(m => cleanOne(m[1]));\n ideas = (numbered.length ? numbered : quoted).filter(Boolean);\n}\n\n// 7) Deduplicate exacts and strip trailing doubled quotes if any\nideas = [...new Set(ideas.map(i => i.replace(/\"+$/,\"\").trim()))];\n\n// 8) Return as a single item\nreturn [{ json: { ideas } }];\n"
},
"typeVersion": 2
},
{
"id": "7a9e1242-f84c-4fc0-ba23-4fc3196479fe",
"name": "05_VérifDéduplicationExacte",
"type": "n8n-nodes-base.code",
"position": [
1264,
80
],
"parameters": {
"jsCode": "const past = items[0].json.pastIdeas.map(p => p.trim().toLowerCase());\nconst ideas = items[0].json.ideas;\n\n\nconst kept_exact = [];\nconst rejected_exact = [];\n\nfor (const idea of ideas) {\n if (past.includes(idea.trim().toLowerCase())) {\n rejected_exact.push(idea);\n } else {\n kept_exact.push(idea);\n }\n}\n\nreturn [{\n json: {\n kept_exact,\n rejected_exact,\n counts: {\n kept: kept_exact.length,\n rejected: rejected_exact.length,\n past\n }\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "8866dafc-c386-46ae-a75a-2402ecd35903",
"name": "02_LireIdéesAntérieures",
"type": "n8n-nodes-base.googleSheets",
"position": [
656,
96
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA/edit?usp=drivesdk",
"cachedResultName": "Idea_Log"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "x2LQk3hNWfQ8t8iy",
"name": "Google Sheets account 3"
}
},
"typeVersion": 4.7
},
{
"id": "c606437f-5680-4691-adf3-1fbb17eaf9bf",
"name": "03_NormaliserIdéesAntérieures",
"type": "n8n-nodes-base.code",
"position": [
864,
96
],
"parameters": {
"jsCode": "const pastIdeas = items.map(i => i.json.idea).filter(Boolean);\n\nreturn [{\n json: {\n pastIdeas\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "2db1b5aa-eb84-4291-a43a-60c3353affe3",
"name": "04.5_FusionnerIdéesEtIdéesAntérieures",
"type": "n8n-nodes-base.merge",
"position": [
1088,
80
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "00f18696-842e-4261-ae0e-e24a07c9917f",
"name": "06_DéduplicationApproximative",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1456,
80
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You remove near-duplicate LinkedIn post ideas using semantic similarity. \nBe conservative: if uncertain, KEEP the idea.\nReturn STRICT JSON only, no extra text.\n"
},
{
"content": "=BRIEF (context only):\n{{ JSON.stringify($item(0,\"02_BuildBrief\").$json) }}\n\nCANDIDATE_IDEAS (after exact-dedupe):\n{{ JSON.stringify($json.kept_exact) }}\n\nPAST_IDEAS (from Idea_Log):\n{{ $json.counts.past }}\n\n\nRULES:\n- Mark an idea as duplicate only if it conveys the SAME core advice/angle as a past idea (not just same topic).\n- Prefer variety across angle (framework vs case study vs contrarian), audience (India + global), and metric focus.\n- If unsure, KEEP the idea (soft fuzzy dedupe).\n- Do NOT rewrite text; only classify.\n- Output STRICT JSON only.\n\nOUTPUT SCHEMA:\n{\n \"kept_fuzzy\": [\"<idea 1>\", \"<idea 2>\"],\n \"rejected_fuzzy\": [\n { \"idea\": \"<candidate duplicated>\", \"matched\": \"<closest past idea>\", \"reason\": \"near-duplicate (same angle/advice)\" }\n ]\n}\n"
}
]
},
"jsonOutput": true
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "2cc8e18a-4f29-4456-802d-68bb1c5a829e",
"name": "10_ExtrairePackPublication",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1008,
528
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You extract structured components from a LinkedIn draft. \nReturn STRICT JSON only. No extra text. \nPreserve facts/sources; do not invent.\n"
},
{
"content": "=INPUT DRAFT (JSON):\n{{ $json.message?.content || $json.post || \"{}\" }}\n\nBRIEF (for constraints; do not rewrite content):\n{{ JSON.stringify($item(0,\"08_ParseChosenIdea\").$json.brief) }}\n\nTASK:\n- HOOK: pick the strongest one-line opener from the draft (or rewrite lightly).\n- BODY: the cleaned post text (fix spacing only).\n- CTA: choose exactly one from {{ JSON.stringify($item(0,\"08_ParseChosenIdea\").$json.brief.cta) }} that best fits the draft ending.\n- HASHTAGS: suggest up to 8 relevant hashtags (start with #; audience/topic aligned).\n- FIRST_COMMENT: 1 line to invite discussion (optional).\n- CHAR_COUNT: integer = characters of BODY (not counting first_comment).\n\nOUTPUT (STRICT JSON):\n{\n \"hook\": \"<one line>\",\n \"body\": \"<full post text>\",\n \"cta\": \"<one of the allowed list>\",\n \"hashtags\": [\"#tag1\", \"#tag2\"],\n \"first_comment\": \"<optional, 0-140 chars>\",\n \"char_count\": 0\n}\nRULES:\n- Max 8 hashtags.\n- Keep numbers/sources exactly as in the draft.\n- No prose outside JSON.\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "fd3c747c-5164-403e-9ca3-9de40e7bfc9b",
"name": "Fusion1",
"type": "n8n-nodes-base.merge",
"position": [
832,
528
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "a1bff2e1-c584-4f05-983c-e93623947469",
"name": "Fusion2",
"type": "n8n-nodes-base.merge",
"position": [
1296,
528
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "4beb81f3-d5e0-44d9-b6b6-183314ca883c",
"name": "11_AnalyserPackPublication",
"type": "n8n-nodes-base.code",
"position": [
1504,
528
],
"parameters": {
"jsCode": "try {\n // 1) Extract the JSON string from LLM output\n const raw = $json?.message?.content ?? \"{}\";\n const pack = (typeof raw === \"string\") ? JSON.parse(raw) : raw;\n\n // 2) Normalize fields\n const hook = (pack.hook || \"\").trim();\n const body = (pack.body || \"\").trim();\n const cta = (pack.cta || \"\").trim();\n const hashtags = Array.isArray(pack.hashtags) ? pack.hashtags : [];\n const first_comment = (pack.first_comment || \"\").trim();\n\n // 3) Attach brief from earlier node\n const brief = $item(0, \"08_ParseChosenIdea\")?.$json?.brief\n || $item(0, \"02_BuildBrief\")?.$json?.brief\n || {};\n\n // 4) Recompute char_count (hook + body as user sees on LinkedIn)\n const combined = (hook ? hook + \"\\n\\n\" : \"\") + body;\n const char_count = combined.length;\n\n return [{\n json: { hook, body, cta, hashtags, first_comment, char_count, brief }\n }];\n} catch (e) {\n return [{\n json: {\n error: \"ParseError_PublishPack\",\n detail: String(e),\n raw: $json?.message?.content ?? null\n }\n }];\n}\n"
},
"typeVersion": 2
},
{
"id": "c3536683-2e43-4920-a169-38ab9e338ce3",
"name": "12_VérificationSpécificité",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-336,
896
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are a precision editor for LinkedIn posts. \nYour job is to add crisp specificity (examples, concrete details, brief citations) without bloating length or changing the core claim.\nFollow the brief’s tone. Preserve facts; never invent numbers.\nReturn STRICT JSON only. No extra text.\n"
},
{
"content": "=INPUT:\nHOOK:\n{{$json.hook}}\n\nBODY:\n{{$json.body}}\n\nBRIEF (context/constraints):\n{{ JSON.stringify($json.brief) }}\n\nRULES:\n- Keep the hook’s intent. You may tighten phrasing slightly.\n- Add 2–3 specific details/examples that strengthen the argument (company names, UX patterns, workflow examples, market contexts).\n- DO NOT add new numeric claims beyond what’s already in BODY. You may add source NAMES (e.g., NPCI, ACI, FIS) if they’re already referenced, but no new figures.\n- Prefer one India and one global example when relevant.\n- Keep sentences punchy; avoid jargon. Preserve bullets and spacing.\n- Net length change ≤ +50 words (target total 150–230 words including hook).\n- End with the existing CTA sentiment intact (don’t change intent).\n\nOUTPUT (STRICT JSON):\n{\n \"hook\": \"<tightened or original hook>\",\n \"body\": \"<revised body with added specificity>\",\n \"notes\": [\n \"What was clarified or made specific in 1–2 bullets\"\n ]\n}\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "b51b8336-95f0-498c-9997-73fd6c8f2d0a",
"name": "Fusion3",
"type": "n8n-nodes-base.merge",
"position": [
-16,
896
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "391ac3da-c92c-4a5c-b2da-944af179c253",
"name": "13_ConformitéVoix",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
336,
896
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5",
"cachedResultName": "GPT-5"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are a voice refinement assistant.\nYour job is to take a draft post (hook, body, notes, brief) and adjust the language so it matches the user’s preferred voice:\n- Tone: Sharp, crisp, authoritative\n- Avoid heavy jargon; keep sentences short and punchy\n- Use simple, data-backed phrasing\n- Ensure scannability (short paragraphs, clean bullets if needed)\n\nDo NOT drop or alter the \"brief\" field.\nDo NOT remove citations, numbers, or data.\nAlways return the same JSON schema with {hook, body, notes, brief}.\n"
},
{
"content": "=INPUT_HOOK:\n{{ $json.hook }}\n\nINPUT_BODY:\n{{ $json.body }}\n\nNOTES_FOR_CONTEXT (optional):\n{{ JSON.stringify($json.notes || []) }}\n\nBRIEF (do not modify; include unchanged in output):\n{{ JSON.stringify($json.brief) }}\n\nTASK:\n- Adjust HOOK and BODY to match the voice above.\n- Keep all citations/numbers intact.\n- Improve rhythm and scannability (line breaks, bullets).\n- Do not add new claims or change meaning.\n- Output JSON only:\n{\n \"hook\": \"<refined one-liner>\",\n \"body\": \"<refined post body>\",\n \"notes\": {{ JSON.stringify($json.notes || []) }},\n \"brief\": {{ JSON.stringify($json.brief) }}\n}\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "ddb1f7e4-861f-4849-b228-50b695449e62",
"name": "12a_AnalyserJSONSpécificité",
"type": "n8n-nodes-base.code",
"position": [
160,
896
],
"parameters": {
"jsCode": "try {\n const raw = $json?.message?.content ?? $json;\n const data = typeof raw === 'string' ? JSON.parse(raw) : (raw || {});\n return [{\n json: {\n hook: data.hook || \"\",\n body: data.body || \"\",\n notes: Array.isArray(data.notes) ? data.notes : [],\n brief: $json.brief || $item(0,\"11_ParsePublishPack\")?.$json?.brief || {}\n }\n }];\n} catch (e) {\n return [{ json: { error: \"ParseError_Specificity\", detail: String(e), raw: $json?.message?.content || null } }];\n}\n"
},
"typeVersion": 2
},
{
"id": "ef02a5d6-5e50-4f22-aef9-41785fe92290",
"name": "13a_AnalyserJSONVoix",
"type": "n8n-nodes-base.code",
"position": [
656,
896
],
"parameters": {
"jsCode": "try {\n const raw = $json?.message?.content ?? $json;\n const data = typeof raw === 'string' ? JSON.parse(raw) : (raw || {});\n return [{\n json: {\n hook: data.hook || \"\",\n body: data.body || \"\",\n notes: Array.isArray(data.notes) ? data.notes : [],\n brief: data.brief || {}\n }\n }];\n} catch (e) {\n return [{\n json: { error: \"ParseError_VoiceConformity\", detail: String(e), raw: $json?.message?.content || null }\n }];\n}\n"
},
"typeVersion": 2
},
{
"id": "b13a9c53-e561-4b10-8062-58a4c65260ee",
"name": "14_ConstruireCTAEtHashtags_LLM",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
880,
896
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You build CTA + hashtags + an optional first comment for a LinkedIn post.\nBe deterministic and rule-following.\n\nRules:\n- Choose exactly ONE CTA from the allowed list provided in \"brief.cta\".\n- Generate up to 8 hashtags. Short, relevant, no spaces, no emojis. Use PascalCase or established tags (e.g., #ProductManagement, #UPI). No duplicates.\n- First comment: 1 line, ≤ 140 characters, invites discussion (optional but preferred).\n- Compute char_count for the final visible text = length of:\n <HOOK>[two newlines]<BODY>\n- Preserve facts and numbers from the body; do not add new numeric claims.\n- Return STRICT JSON only. No prose.\n- Do NOT rewrite hook or body; they will be merged downstream.\n"
},
{
"content": "=INPUT:\n{\n \"hook\": \"{{$json.hook}}\",\n \"body\": \"{{$json.body}}\",\n \"brief\": {{ JSON.stringify($json.brief) }}\n}\n\nTASK:\n1) Pick \"cta\" from brief.cta exactly (e.g., \"Comments\", \"Share\", or \"Follow\").\n2) Create \"hashtags\": max 8, relevant to the post and audience, PascalCase when possible, no spaces, no emojis, no duplicates.\n3) Write a concise \"first_comment\" (≤140 chars) that invites discussion; avoid repeating the hook verbatim.\n4) Compute \"char_count\" = character length of:\n HOOK + \"\\n\\n\" + BODY\n (count every character; do not include first_comment in this count).\n5) Output JSON ONLY in this schema:\n\n{\n \"cta\": \"Comments\",\n \"hashtags\": [\"#AI\", \"#ProductManagement\"],\n \"first_comment\": \"Your one-line discussion prompt here...\",\n \"char_count\": 1234\n}\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "afb9ea3a-1c87-4e58-be14-ae140c074748",
"name": "Fusion4",
"type": "n8n-nodes-base.merge",
"position": [
1264,
912
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "cfc7e722-2b69-44ae-a42e-6fc99fd304fc",
"name": "14b_StructurerPackFusionné",
"type": "n8n-nodes-base.code",
"position": [
1504,
912
],
"parameters": {
"jsCode": "try {\n // 1) Bring forward core fields (from Input A of Merge)\n const hook = ($json.hook || \"\").trim();\n const body = ($json.body || \"\").trim();\n const notes = Array.isArray($json.notes) ? $json.notes : [];\n const brief = $json.brief || {};\n\n // 2) Parse LLM pack (from Input B of Merge)\n let llmPack = {};\n if ($json?.message?.content) {\n llmPack = JSON.parse($json.message.content);\n } else {\n // if your LLM ever returns plain JSON at top-level\n llmPack = $json;\n }\n\n // 3) Normalize CTA against allowed list from brief\n const allowedCTAs = Array.isArray(brief.cta) && brief.cta.length ? brief.cta : [\"Comments\",\"Share\",\"Follow\"];\n let cta = (llmPack.cta || \"\").trim();\n if (!allowedCTAs.includes(cta)) cta = allowedCTAs[0];\n\n // 4) Normalize hashtags: #prefix, dedupe, cap 8\n let hashtags = Array.isArray(llmPack.hashtags) ? llmPack.hashtags : [];\n hashtags = [...new Set(hashtags.map(h => \"#\" + h.replace(/^#/, \"\").replace(/\\s+/g, \"\")))].slice(0, 8);\n\n // 5) First comment\n const first_comment = (llmPack.first_comment || \"\").trim();\n\n // 6) Deterministic visible char count (hook + body only)\n const char_count = ((hook ? hook + \"\\n\\n\" : \"\") + body).length;\n\n return [{\n json: {\n hook,\n body,\n notes,\n cta,\n hashtags,\n first_comment,\n char_count,\n brief\n }\n }];\n} catch (e) {\n return [{\n json: { error: \"ShapeError_14b\", detail: String(e), raw: $json?.message?.content || null }\n }];\n}\n"
},
"typeVersion": 2
},
{
"id": "62b0dd6b-e736-456e-8cbb-cd27f721cbbe",
"name": "15_HygièneEngagement",
"type": "n8n-nodes-base.code",
"position": [
-320,
1248
],
"parameters": {
"jsCode": "try {\n const hook = ($json.hook || \"\").trim();\n let body = ($json.body || \"\").trim();\n const notes = Array.isArray($json.notes) ? $json.notes : [];\n const brief = $json.brief || {};\n let cta = ($json.cta || \"Comments\").trim();\n let hashtags = Array.isArray($json.hashtags) ? $json.hashtags.slice(0, 32) : [];\n let first_comment = ($json.first_comment || \"\").trim();\n\n // -------------------------\n // 1) Normalize spacing & punctuation\n // -------------------------\n // Collapse 3+ newlines to 2\n body = body.replace(/\\r/g, \"\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/[ \\t]+\\n/g, \"\\n\");\n\n // Fix spaced hyphenated words: \"AI- native\" -> \"AI-native\"\n // Avoid bullet lines that begin with \"- \"\n body = body.split(\"\\n\").map(line => {\n if (/^\\s*-\\s/.test(line)) return line; // keep bullets as-is for now\n return line.replace(/\\b([A-Za-z0-9]+)\\s*-\\s*([A-Za-z0-9]+)\\b/g, \"$1-$2\");\n }).join(\"\\n\");\n\n // -------------------------\n // 2) Bullet hygiene & scannability\n // -------------------------\n // Ensure \"- \" (hyphen + space) bullets\n body = body.replace(/^\\s*-\\s*/gm, \"- \");\n // Add a blank line before and after bullet blocks\n body = body.replace(/([^\\n])\\n(- .+(?:\\n- .+)+)/g, \"$1\\n\\n$2\")\n .replace(/((?:- .+(?:\\n|$))+)(\\S)/g, \"$1\\n$2\");\n\n // -------------------------\n // 3) Ensure a question if CTA = Comments\n // -------------------------\n const endsWithQuestion = /\\?\\s*$/.test(body.trim());\n if (cta === \"Comments\" && !endsWithQuestion) {\n // If last 2 lines already contain a question, skip\n const tail = body.split(\"\\n\").slice(-3).join(\" \");\n if (!/\\?/.test(tail)) {\n body = body.trim() + \"\\n\\nWhat do you think?\";\n }\n }\n\n // -------------------------\n // 4) Hashtag hygiene (dedupe, cap 8, casing)\n // -------------------------\n // Preferred casing map for common tags\n const preferred = {\n \"ai\": \"AI\",\n \"upi\": \"UPI\",\n \"productmanagement\": \"ProductManagement\",\n \"productstrategy\": \"ProductStrategy\",\n \"a iagents\": \"AIAgents\", // guard against odd spacing\n \"aiagents\": \"AIAgents\",\n \"indiatch\": \"IndiaTech\",\n \"indiatech\": \"IndiaTech\",\n \"distribution\": \"Distribution\",\n \"growth\": \"Growth\",\n \"fintech\": \"Fintech\",\n \"digitalpayments\": \"DigitalPayments\",\n \"developerexperience\": \"DeveloperExperience\",\n \"platformstrategy\": \"PlatformStrategy\",\n \"startups\": \"Startups\",\n \"innovation\": \"Innovation\",\n \"workflows\": \"Workflows\",\n };\n\n const toPascal = (s) => s\n .split(/[^A-Za-z0-9]+/).filter(Boolean)\n .map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\"\");\n\n hashtags = hashtags\n .map(h => String(h).trim())\n .filter(Boolean)\n .map(h => h.replace(/^#/, \"\")) // strip leading #\n .map(h => h.replace(/\\s+/g, \"\")) // no spaces\n .map(h => preferred[h.toLowerCase()] || toPascal(h)) // apply preferred casing or PascalCase\n .map(h => \"#\" + h)\n .filter((h, i, arr) => arr.indexOf(h) === i) // dedupe\n .slice(0, 8); // cap 8\n\n // -------------------------\n // 5) First comment fallback (optional)\n // -------------------------\n if (!first_comment) {\n first_comment = (cta === \"Comments\")\n ? \"What’s one rail that would make your AI unavoidable this quarter?\"\n : \"Follow for more product + AI breakdowns.\";\n }\n\n // -------------------------\n // 6) Recompute char_count (visible: hook + body)\n // -------------------------\n const char_count = ((hook ? hook + \"\\n\\n\" : \"\") + body).length;\n\n return [{\n json: {\n hook,\n body,\n notes,\n cta,\n hashtags,\n first_comment,\n char_count,\n brief\n }\n }];\n} catch (e) {\n return [{\n json: {\n error: \"EngagementHygieneError\",\n detail: String(e),\n raw: $json\n }\n }];\n}\n"
},
"typeVersion": 2
},
{
"id": "53d3ea8a-56d2-469c-9410-8d858f2b0e8e",
"name": "16_ConformitéFormat",
"type": "n8n-nodes-base.code",
"position": [
-96,
1248
],
"parameters": {
"jsCode": "// Cleans duplicates of the hook from body, enforces LinkedIn limits, and returns a compliant pack.\n\nfunction smartTrim(text, limit) {\n if (text.length <= limit) return text;\n const cut = text.slice(0, limit);\n // Try to end at a sentence or line boundary\n const lastStop = Math.max(\n cut.lastIndexOf(\". \"),\n cut.lastIndexOf(\"! \"),\n cut.lastIndexOf(\"? \"),\n cut.lastIndexOf(\"\\n\")\n );\n if (lastStop > 40) return cut.slice(0, lastStop + 1).trim(); // keep a sensible boundary\n return cut.trimEnd() + \"…\";\n}\n\nreturn items.map(item => {\n const data = item.json || {};\n const MAX_CHARS = 3000; // LinkedIn hard limit\n const hook = (data.hook || \"\").trim();\n let body = (data.body || \"\").replace(/\\r/g, \"\");\n let hashtags = Array.isArray(data.hashtags) ? data.hashtags : [];\n const cta = (data.cta || \"\").trim();\n const first_comment = (data.first_comment || \"\").trim();\n const brief = data.brief || {};\n const notes = Array.isArray(data.notes) ? data.notes : [];\n\n // 1) Remove duplicate hook lines from the start of body\n const hookNorm = hook.trim();\n let lines = body.split(\"\\n\");\n while (lines.length && lines[0].trim() === hookNorm) lines.shift(); // remove repeated hook(s)\n while (lines.length && lines[0].trim() === \"\") lines.shift(); // remove leading blank lines\n body = lines.join(\"\\n\").trim();\n\n // 2) Build visible text = hook + blank line + body\n // (always show hook at top once)\n const visiblePrefix = hook ? hook + \"\\n\\n\" : \"\";\n // enforce max by trimming ONLY the body portion\n const allowedBodyLimit = Math.max(0, MAX_CHARS - visiblePrefix.length);\n const bodyTrimmed = smartTrim(body, allowedBodyLimit);\n\n const visible = visiblePrefix + bodyTrimmed;\n\n // 3) Hashtag cap (10), normalize # and dedupe\n hashtags = [...new Set(\n hashtags\n .map(h => \"#\" + String(h || \"\").replace(/^#/, \"\").replace(/\\s+/g, \"\"))\n )].slice(0, 10);\n\n // 4) Final char count of visible text\n const char_count = visible.length;\n\n return {\n json: {\n hook, // unchanged\n body: bodyTrimmed, // cleaned & possibly trimmed\n notes,\n cta,\n hashtags,\n first_comment,\n char_count,\n brief\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "401c8de0-761f-49d0-b3a0-0004f54f5651",
"name": "Générer une image",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
128,
1248
],
"parameters": {
"model": "gpt-image-1",
"prompt": "={\n \"prompt\": \"Create a LinkedIn-style social graphic.\\n\\nUse this headline EXACTLY: \\\"{{$json.hook}}\\\".\\n\\nFrom the BODY below, infer 2–3 core concepts (nouns/themes) and represent them with simple, universal flat icons/illustrations (no brand logos). Prefer tech/product metaphors (e.g., phone, graph, gears, database, API plug, search, document, bolt, shield) ONLY if they match the body themes.\\n\\nBODY:\\n{{$json.body}}\\n\\nLayout:\\n- Large bold headline at top-left.\\n- Under headline, one short tagline derived from the body (≤120 chars). Do NOT paste full paragraphs.\\n- Beside/below the text, place the 2–3 icons you inferred. Arrange them in a clear left→right story flow.\\n\\nStyle:\\n- Clean, modern, minimalist, LinkedIn-friendly.\\n- Background: dark (#0B0F15) with subtle gradient; typography in white/light grey.\\n- Accent palette (use sparingly): blue #4A90E2, green #7ED321.\\n- Mix text + visuals (NOT plain text poster).\\n\\nFooter:\\n- Add a small, subtle footer strip with hashtags: {{ Array.isArray($json.hashtags) ? $json.hashtags.slice(0,3).join(' ') : '' }}\\n\\nConstraints:\\n- No faces/people. No brand marks or watermarks. High contrast, legible at mobile feed size.\",\n \"size\": \"1024x1024\",\n \"n\": 1\n}\n",
"options": {},
"resource": "image"
},
"credentials": {
"openAiApi": {
"id": "X9ubpsApQNgfKwnt",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "2f764832-1f2d-494c-ae7e-016f3da41618",
"name": "Note adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
16
],
"parameters": {
"color": 3,
"width": 2544,
"height": 288,
"content": "## Idea Generation and Dedupe with previous published posts"
},
"typeVersion": 1
},
{
"id": "e10e205e-e5fc-4c1f-9df3-8a8605f977af",
"name": "Note adhésive1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
400
],
"parameters": {
"color": 4,
"width": 2544,
"height": 288,
"content": "## Post generation basis the idea"
},
"typeVersion": 1
},
{
"id": "a664f3a1-65ed-412c-a94e-ba9556f6395c",
"name": "Note adhésive2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
816
],
"parameters": {
"color": 6,
"width": 2544,
"height": 288,
"content": "## Idea polishing, adding CTA and hashtags"
},
"typeVersion": 1
},
{
"id": "3cc14f12-fd29-46b2-878a-e653b7616510",
"name": "Note adhésive3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
1168
],
"parameters": {
"width": 2528,
"height": 288,
"content": "## Image Generation, final post ready and updating the google sheet and google drive\n"
},
"typeVersion": 1
},
{
"id": "12dc9885-c076-4cb3-b178-b718ef116840",
"name": "Fusion5",
"type": "n8n-nodes-base.merge",
"position": [
320,
1264
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "d4420fe7-8b84-456f-bc3c-7da1b0f6974e",
"name": "18_EmballagePublication",
"type": "n8n-nodes-base.code",
"position": [
480,
1264
],
"parameters": {
"jsCode": "// Expecting merged item with text JSON + binary.image\nconst j = $json || {};\nconst b = $binary?.image || $binary?.data || null;\n\nif (!j.hook && !j.body) {\n throw new Error('No post fields found. Ensure Merge node combines 16_FormatCompliance (JSON) with 17_GenerateImage (binary).');\n}\nif (!b) {\n throw new Error('No image binary found. In Image node set Binary Property = \"image\" (or \"data\") and wire it into the Merge.');\n}\n\n// Normalize\nconst hashtags = Array.isArray(j.hashtags) ? j.hashtags : (j.hashtags ? String(j.hashtags).split(/\\s+/) : []);\nconst finalPost = `\n${j.hook || ''}\n\n${j.body || ''}\n\n${hashtags.length ? hashtags.join(' ') : ''}${j.cta ? `\\n\\n${j.cta}` : ''}\n`.trim();\n\nreturn [{\n json: {\n ...j,\n final_post: finalPost,\n image_provider: 'image_gen_node',\n image_filename: b.fileName || 'post.png',\n image_mime: b.mimeType || 'image/png',\n image_size: b.fileSize || '',\n image_binary_id: b.id || ''\n },\n binary: { image: b }\n}];\n"
},
"typeVersion": 2
},
{
"id": "6635de34-cf6c-4bd2-ac54-3aa932f510f1",
"name": "Téléverser fichier",
"type": "n8n-nodes-base.googleDrive",
"position": [
672,
1264
],
"parameters": {
"name": "={{ $now.toFormat(\"yyyyLLdd_HHmmss\") + \"_\" + $json[\"hook\"].replace(/[^a-zA-Z0-9]/g,\"_\").slice(0,30) + \".png\" }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "1M8-qn3kL5P0Fb7MZllIL3KL2jVxROFkm",
"cachedResultUrl": "https://drive.google.com/drive/folders/1M8-qn3kL5P0Fb7MZllIL3KL2jVxROFkm",
"cachedResultName": "Linkedin Post Generator"
},
"inputDataFieldName": "=image"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "4wtxqZRczqngQF8G",
"name": "Google Drive account"
}
},
"typeVersion": 3
},
{
"id": "c3afa08f-4402-4455-a99d-a8447a7483ce",
"name": "18b_ConstruireLigneFeuille",
"type": "n8n-nodes-base.code",
"position": [
1072,
1264
],
"parameters": {
"jsCode": "// 18b_BuildSheetRow\n\nconst rows = [];\n\nfor (const item of items) {\n const x = item.json;\n\n // === IDEA (dedupe safety) ===\n const pickSentence = (txt) => {\n if (!txt) return '';\n const s = txt.split(/[.?!]/)[0];\n return s.length > 100 ? s.slice(0, 100) : s;\n };\n\n const ideaTextRaw =\n x.locked_idea ||\n x.chosenIdea ||\n x.idea ||\n pickSentence(x.hook) ||\n pickSentence(x.body) ||\n pickSentence(x.final_post);\n\n const idea = (ideaTextRaw || '').trim();\n const ideaSlug = idea.toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n // === Hash for exact dedupe ===\n const crypto = require('crypto');\n const ideaHash = crypto.createHash('md5').update(idea).digest('hex');\n\n // === Timestamps ===\n const tsISO = new Date().toISOString();\n const tsIST = new Date().toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });\n\n // === Sheet Row Object ===\n rows.push({\n timestamp_iso: tsISO,\n timestamp_ist: tsIST,\n\n post_id: x.id || '',\n\n idea,\n idea_slug: ideaSlug,\n idea_hash: ideaHash,\n\n hook: x.hook || '',\n body: x.body || '',\n cta: x.cta || '',\n hashtags: Array.isArray(x.hashtags) ? x.hashtags.join(' ') : (x.hashtags || ''),\n first_comment: x.first_comment || '',\n final_post: x.final_post || '',\n\n notes: Array.isArray(x.notes) ? x.notes.join(' | ') : (x.notes || ''),\n\n image_url: x.webViewLink || x.webContentLink || '',\n image_filename: x.image_filename || x.name || '',\n image_mime: x.image_mime || x.mimeType || '',\n image_size: x.image_size || x.fileSize || '',\n\n // Extra debug/meta\n image_binary_id: x.image_binary_id || '',\n provider: x.image_provider || '',\n });\n}\n\nreturn rows.map(r => ({ json: r }));\n"
},
"typeVersion": 2
},
{
"id": "855dfa96-f231-4f3c-8272-c1ce195eab59",
"name": "Fusion6",
"type": "n8n-nodes-base.merge",
"position": [
864,
1264
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "a34b9b18-bbff-4ace-a89f-c7a057f7c3a6",
"name": "19_AjoutFeuilles",
"type": "n8n-nodes-base.googleSheets",
"position": [
1280,
1264
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "timestamp_ist",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp_ist",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "post_id",
"type": "string",
"display": true,
"required": false,
"displayName": "post_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "hook",
"type": "string",
"display": true,
"required": false,
"displayName": "hook",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "body",
"type": "string",
"display": true,
"required": false,
"displayName": "body",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cta",
"type": "string",
"display": true,
"required": false,
"displayName": "cta",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "hashtags",
"type": "string",
"display": true,
"required": false,
"displayName": "hashtags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "first_comment",
"type": "string",
"display": true,
"required": false,
"displayName": "first_comment",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_url",
"type": "string",
"display": true,
"required": false,
"displayName": "image_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_filename",
"type": "string",
"display": true,
"required": false,
"displayName": "image_filename",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "notes",
"type": "string",
"display": true,
"required": false,
"displayName": "notes",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp_iso",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "timestamp_iso",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idea",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idea",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idea_slug",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idea_slug",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idea_hash",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idea_hash",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "final_post",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "final_post",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_mime",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "image_mime",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_size",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "image_size",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_binary_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "image_binary_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "provider",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "provider",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1945kuHLUlrCDROQxRPb7vNZQ4mEXd67sLRNVIB9lFFA/edit?usp=drivesdk",
"cachedResultName": "Idea_Log"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "x2LQk3hNWfQ8t8iy",
"name": "Google Sheets account 3"
}
},
"typeVersion": 4.7
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "23358699-7458-4693-940e-06895ad60da1",
"connections": {
"2c5ad466-a960-421d-b65e-7343957d354b": {
"main": [
[
{
"node": "e2fc1a59-8082-4b57-b907-62b6f9ef6ad4",
"type": "main",
"index": 0
}
]
]
},
"fd3c747c-5164-403e-9ca3-9de40e7bfc9b": {
"main": [
[
{
"node": "2cc8e18a-4f29-4456-802d-68bb1c5a829e",
"type": "main",
"index": 0
}
]
]
},
"a1bff2e1-c584-4f05-983c-e93623947469": {
"main": [
[
{
"node": "4beb81f3-d5e0-44d9-b6b6-183314ca883c",
"type": "main",
"index": 0
}
]
]
},
"b51b8336-95f0-498c-9997-73fd6c8f2d0a": {
"main": [
[
{
"node": "ddb1f7e4-861f-4849-b228-50b695449e62",
"type": "main",
"index": 0
}
]
]
},
"afb9ea3a-1c87-4e58-be14-ae140c074748": {
"main": [
[
{
"node": "cfc7e722-2b69-44ae-a42e-6fc99fd304fc",
"type": "main",
"index": 0
}
]
]
},
"12dc9885-c076-4cb3-b178-b718ef116840": {
"main": [
[
{
"node": "d4420fe7-8b84-456f-bc3c-7da1b0f6974e",
"type": "main",
"index": 0
}
]
]
},
"855dfa96-f231-4f3c-8272-c1ce195eab59": {
"main": [
[
{
"node": "c3afa08f-4402-4455-a99d-a8447a7483ce",
"type": "main",
"index": 0
}
]
]
},
"6635de34-cf6c-4bd2-ac54-3aa932f510f1": {
"main": [
[
{
"node": "855dfa96-f231-4f3c-8272-c1ce195eab59",
"type": "main",
"index": 0
}
]
]
},
"5d8195ac-0e4d-46a2-b215-e76088726704": {
"main": [
[
{
"node": "3606e466-c0e3-47e6-aac8-000cd2960fab",
"type": "main",
"index": 0
}
]
]
},
"3606e466-c0e3-47e6-aac8-000cd2960fab": {
"main": [
[
{
"node": "d27e676c-fe72-41d0-ba06-64a31b0c2170",
"type": "main",
"index": 0
},
{
"node": "2c5ad466-a960-421d-b65e-7343957d354b",
"type": "main",
"index": 1
},
{
"node": "9aecf953-5e89-4434-b430-077ec3a598e1",
"type": "main",
"index": 1
},
{
"node": "fd3c747c-5164-403e-9ca3-9de40e7bfc9b",
"type": "main",
"index": 1
},
{
"node": "a1bff2e1-c584-4f05-983c-e93623947469",
"type": "main",
"index": 1
},
{
"node": "b51b8336-95f0-498c-9997-73fd6c8f2d0a",
"type": "main",
"index": 1
}
]
]
},
"e2fc1a59-8082-4b57-b907-62b6f9ef6ad4": {
"main": [
[
{
"node": "9aecf953-5e89-4434-b430-077ec3a598e1",
"type": "main",
"index": 0
}
]
]
},
"d27e676c-fe72-41d0-ba06-64a31b0c2170": {
"main": [
[
{
"node": "f82d70ea-08fa-49db-8c88-dca6637ab547",
"type": "main",
"index": 0
}
]
]
},
"6881cd94-a7ed-43a5-9824-9594a9631596": {
"main": [
[
{
"node": "fd3c747c-5164-403e-9ca3-9de40e7bfc9b",
"type": "main",
"index": 0
}
]
]
},
"8866dafc-c386-46ae-a75a-2402ecd35903": {
"main": [
[
{
"node": "c606437f-5680-4691-adf3-1fbb17eaf9bf",
"type": "main",
"index": 0
}
]
]
},
"c3afa08f-4402-4455-a99d-a8447a7483ce": {
"main": [
[
{
"node": "a34b9b18-bbff-4ace-a89f-c7a057f7c3a6",
"type": "main",
"index": 0
}
]
]
},
"401c8de0-761f-49d0-b3a0-0004f54f5651": {
"main": [
[
{
"node": "12dc9885-c076-4cb3-b178-b718ef116840",
"type": "main",
"index": 0
}
]
]
},
"c3536683-2e43-4920-a169-38ab9e338ce3": {
"main": [
[
{
"node": "b51b8336-95f0-498c-9997-73fd6c8f2d0a",
"type": "main",
"index": 0
}
]
]
},
"391ac3da-c92c-4a5c-b2da-944af179c253": {
"main": [
[
{
"node": "ef02a5d6-5e50-4f22-aef9-41785fe92290",
"type": "main",
"index": 0
}
]
]
},
"ef02a5d6-5e50-4f22-aef9-41785fe92290": {
"main": [
[
{
"node": "b13a9c53-e561-4b10-8062-58a4c65260ee",
"type": "main",
"index": 0
},
{
"node": "afb9ea3a-1c87-4e58-be14-ae140c074748",
"type": "main",
"index": 1
}
]
]
},
"d4420fe7-8b84-456f-bc3c-7da1b0f6974e": {
"main": [
[
{
"node": "6635de34-cf6c-4bd2-ac54-3aa932f510f1",
"type": "main",
"index": 0
},
{
"node": "855dfa96-f231-4f3c-8272-c1ce195eab59",
"type": "main",
"index": 1
}
]
]
},
"f82d70ea-08fa-49db-8c88-dca6637ab547": {
"main": [
[
{
"node": "8866dafc-c386-46ae-a75a-2402ecd35903",
"type": "main",
"index": 0
},
{
"node": "2db1b5aa-eb84-4291-a43a-60c3353affe3",
"type": "main",
"index": 1
}
]
]
},
"7a9e1242-f84c-4fc0-ba23-4fc3196479fe": {
"main": [
[
{
"node": "00f18696-842e-4261-ae0e-e24a07c9917f",
"type": "main",
"index": 0
}
]
]
},
"2038c6a7-a0a1-47b4-8f8c-07ecc9219f2c": {
"main": [
[
{
"node": "6881cd94-a7ed-43a5-9824-9594a9631596",
"type": "main",
"index": 0
}
]
]
},
"4beb81f3-d5e0-44d9-b6b6-183314ca883c": {
"main": [
[
{
"node": "c3536683-2e43-4920-a169-38ab9e338ce3",
"type": "main",
"index": 0
}
]
]
},
"cfc7e722-2b69-44ae-a42e-6fc99fd304fc": {
"main": [
[
{
"node": "62b0dd6b-e736-456e-8cbb-cd27f721cbbe",
"type": "main",
"index": 0
}
]
]
},
"53d3ea8a-56d2-469c-9410-8d858f2b0e8e": {
"main": [
[
{
"node": "401c8de0-761f-49d0-b3a0-0004f54f5651",
"type": "main",
"index": 0
},
{
"node": "12dc9885-c076-4cb3-b178-b718ef116840",
"type": "main",
"index": 1
}
]
]
},
"62b0dd6b-e736-456e-8cbb-cd27f721cbbe": {
"main": [
[
{
"node": "53d3ea8a-56d2-469c-9410-8d858f2b0e8e",
"type": "main",
"index": 0
}
]
]
},
"c606437f-5680-4691-adf3-1fbb17eaf9bf": {
"main": [
[
{
"node": "2db1b5aa-eb84-4291-a43a-60c3353affe3",
"type": "main",
"index": 0
}
]
]
},
"9aecf953-5e89-4434-b430-077ec3a598e1": {
"main": [
[
{
"node": "2038c6a7-a0a1-47b4-8f8c-07ecc9219f2c",
"type": "main",
"index": 0
}
]
]
},
"00f18696-842e-4261-ae0e-e24a07c9917f": {
"main": [
[
{
"node": "2c5ad466-a960-421d-b65e-7343957d354b",
"type": "main",
"index": 0
}
]
]
},
"2cc8e18a-4f29-4456-802d-68bb1c5a829e": {
"main": [
[
{
"node": "a1bff2e1-c584-4f05-983c-e93623947469",
"type": "main",
"index": 0
}
]
]
},
"b13a9c53-e561-4b10-8062-58a4c65260ee": {
"main": [
[
{
"node": "afb9ea3a-1c87-4e58-be14-ae140c074748",
"type": "main",
"index": 0
}
]
]
},
"2db1b5aa-eb84-4291-a43a-60c3353affe3": {
"main": [
[
{
"node": "7a9e1242-f84c-4fc0-ba23-4fc3196479fe",
"type": "main",
"index": 0
}
]
]
},
"ddb1f7e4-861f-4849-b228-50b695449e62": {
"main": [
[
{
"node": "391ac3da-c92c-4a5c-b2da-944af179c253",
"type": "main",
"index": 0
}
]
]
}
}
}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é ?
Avancé - Création de contenu, 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.
Workflows recommandés
Nishant
@panditaPartager ce workflow