8
n8n 中文网amn8n.com

博客与LinkedIn内容创作自动化

高级

这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 28 个节点。主要使用 If, Set, Code, Cron, Gmail 等节点。 使用OpenAI和Replicate AI图像自动化博客与LinkedIn内容创作

前置要求
  • Google 账号和 Gmail API 凭证
  • Notion API Key
  • LinkedIn API 凭证
  • 可能需要目标 API 的认证凭证
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "f930580f475173640cf75bd5e1dc94fd2a589d21917d2c231c8fd90eb205f9b82",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "45e081e9-db15-4808-9c26-6f1089f23a0e",
      "name": "Cron(计划任务)",
      "type": "n8n-nodes-base.cron",
      "position": [
        -1648,
        -304
      ],
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "hour": 19
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7e72fddb-7c81-4bf3-bd96-b02c3ebb53efa",
      "name": "设置(配置)",
      "type": "n8n-nodes-base.set",
      "position": [
        -1424,
        -304
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "NOTION_DB_ID",
              "value": "25496301-7675-81fa-9d31-cedcc7f452c6a"
            },
            {
              "name": "NOTION_PAGE_PARENT",
              "value": "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
            },
            {
              "name": "LINKEDIN_PERSON_URN",
              "value": "urn:li:person:XXXXXXXX"
            },
            {
              "name": "OPENAI_MODEL",
              "value": "gpt-4.1-mini"
            },
            {
              "name": "EMAIL_TO",
              "value": "test@mail.com"
            }
          ],
          "boolean": [
            {
              "name": "LINKEDIN_PUBLISH",
              "value": true
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 2
    },
    {
      "id": "648ff7d2-a55e-4e0c-8b12-d3634d1f1b958",
      "name": "Notion → 查询想法数据库(全部)",
      "type": "n8n-nodes-base.notion",
      "position": [
        -1200,
        -304
      ],
      "parameters": {
        "simple": false,
        "options": {
          "sort": {
            "sortValue": [
              {
                "key": "created_time",
                "direction": "ascending",
                "timestamp": true
              }
            ]
          }
        },
        "resource": "databasePage",
        "operation": "getAll",
        "returnAll": true,
        "databaseId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.NOTION_DB_ID }}"
        },
        "filterJson": "={\n  \"property\": \"published\",\n  \"checkbox\": { \"equals\": false }\n}",
        "filterType": "json"
      },
      "credentials": {
        "notionApi": {
          "id": "AU61TARrYLYMxTj9",
          "name": "Notion account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "c964ef88-6dea-4ea1-ad6c-2eef99b483646",
      "name": "IF(符合条件?)",
      "type": "n8n-nodes-base.if",
      "position": [
        -1200,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d6c0245f-b296-4a04-861d-84c42736aa997",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.eligible_count > 0 }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "e3a428a0-c52e-47f6-9281-1063f84e587c3",
      "name": "分批处理(1)",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -656,
        -304
      ],
      "parameters": {
        "options": {},
        "batchSize": 1
      },
      "typeVersion": 2
    },
    {
      "id": "017d6b4c-52f8-4238-abf1-95f44d08b182b",
      "name": "错误触发器(任何节点失败)",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        -1520,
        2272
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "219ddd0a-9ad8-4555-acf1-b002406738346",
      "name": "统计符合条件数",
      "type": "n8n-nodes-base.code",
      "position": [
        -1424,
        0
      ],
      "parameters": {
        "jsCode": "// Emit a single item with the eligible count for IF routing\nreturn [{ json: { eligible_count: items.length } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "7d00232e-be9d-4cdc-b072-eedc64dd79e3c",
      "name": "筛选未发布项 + 映射",
      "type": "n8n-nodes-base.code",
      "position": [
        -976,
        -304
      ],
      "parameters": {
        "jsCode": "/* Filter unpublished + map fields safely */\nconst out = [];\nfor (const item of items) {\n  const page = item.json;\n  const id = page.id;\n  const p = page.properties || {};\n  const g = (prop) => {\n    if (!prop) return '';\n    if (prop.type === 'title' && prop.title?.length) return prop.title.map(t=>t.plain_text).join('');\n    if (prop.type === 'rich_text' && prop.rich_text?.length) return prop.rich_text.map(t=>t.plain_text).join('');\n    if (prop.type === 'url') return prop.url || '';\n    if (prop.type === 'checkbox') return !!prop.checkbox;\n    if (prop.type === 'multi_select') return prop.multi_select.map(o=>o.name);\n    if (prop.type === 'select') return prop.select?.name || '';\n    if (prop.type === 'date') return prop.date?.start || '';\n    return '';\n  };\n  const isPublished = p.published ? !!p.published.checkbox : false;\n  if (isPublished) continue;\n\n  const title = g(p.title) || page.properties?.Name?.title?.[0]?.plain_text || '';\n  const angle = g(p.angle);\n  const tags = p.tags ? (p.tags.type === 'multi_select' ? p.tags.multi_select.map(o=>o.name) : g(p.tags)) : '';\n  const primary_link = g(p.primary_link);\n  const reference_links = g(p.reference_links);\n  const images = g(p.images);\n  const notes = g(p.notes);\n  const target_audience = g(p.target_audience);\n  const canonical_url = g(p.canonical_url);\n  const language = g(p.language);\n  const slug = g(p.slug);\n\n  out.push({ json: {\n    notion_page_id: id,\n    title,\n    angle,\n    tags,\n    primary_link,\n    reference_links,\n    images,\n    notes,\n    target_audience,\n    canonical_url,\n    language,\n    slug\n  }});\n}\nreturn out;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "40b826f5-b1ef-490b-b208-f1754c1972d81",
      "name": "发送消息",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -976,
        0
      ],
      "webhookId": "60e2a23b-9c59-485b-a5d3-9c61b2f39a45",
      "parameters": {
        "sendTo": "={{ $('Set (Configs)').item.json.EMAIL_TO }}",
        "message": "=No rows found in {{ $('Set (Configs)').item.json.NOTION_DB_ID }} with published != true at {{$now}}.",
        "options": {},
        "subject": "Blog Pipeline: No Eligible Notion Rows!",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "g6m2gV1BtMtEggjm",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "87a55a66-d609-47d2-a177-eddb4a7d9d560",
      "name": "解析和验证 JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        144,
        -304
      ],
      "parameters": {
        "jsCode": "/**\n * Node 11 — Function (Parse & Validate JSON from OpenAI)\n * Soft-handles safety_flags (warnings) instead of throwing.\n */\n\n// ---------- 1) Extract message.content ----------\nconst input = items[0].json;\n\nfunction extractContent(nodeOut) {\n  // n8n OpenAI nodes vary; support a few shapes:\n\n  // A) Array of { message: { content } }\n  if (Array.isArray(nodeOut) && nodeOut[0]?.message?.content !== undefined) {\n    return nodeOut[0].message.content;\n  }\n  // B) Chat Completions\n  if (nodeOut?.data?.choices?.[0]?.message?.content !== undefined) {\n    return nodeOut.data.choices[0].message.content;\n  }\n  // C) OpenAI node returning raw string JSON at top level\n  if (typeof nodeOut === \"string\") {\n    return nodeOut;\n  }\n  // D) Flattened shape\n  if (nodeOut?.message?.content !== undefined) {\n    return nodeOut.message.content;\n  }\n  // E) Sometimes models already return parsed object\n  if (nodeOut?.content !== undefined) {\n    return nodeOut.content;\n  }\n  throw new Error(\"Node11: could not locate message.content from OpenAI output\");\n}\n\nlet content = extractContent(input);\n\n// ---------- 2) Parse to object ----------\nlet parsed;\nif (content && typeof content === \"object\") {\n  parsed = content;\n} else if (typeof content === \"string\") {\n  let txt = content.trim();\n  if (txt.startsWith(\"```\")) {\n    txt = txt.replace(/^```(?:json)?\\s*/i, \"\").replace(/\\s*```$/i, \"\");\n  }\n  txt = txt\n    .replace(/[\\u2018\\u2019]/g, \"'\")\n    .replace(/[\\u201C\\u201D]/g, '\"')\n    .replace(/[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F]/g, \" \")\n    .replace(/,\\s*([}\\]])/g, \"$1\");\n\n  // escape raw newlines inside strings\n  (function escapeNewlinesInStrings() {\n    let out = \"\", inStr = false, esc = false;\n    for (let i = 0; i < txt.length; i++) {\n      const ch = txt[i];\n      if (!inStr) { if (ch === '\"') inStr = true; out += ch; continue; }\n      if (esc) { out += ch; esc = false; continue; }\n      if (ch === \"\\\\\") { out += ch; esc = true; continue; }\n      if (ch === '\"') { inStr = false; out += ch; continue; }\n      if (ch === \"\\n\" || ch === \"\\r\") { out += \"\\\\n\"; continue; }\n      out += ch;\n    }\n    txt = out;\n  })();\n\n  try {\n    parsed = JSON.parse(txt);\n  } catch (e) {\n    throw new Error(\"Node11: JSON.parse failed after repair: \" + e.message);\n  }\n} else {\n  throw new Error(\"Node11: message.content is neither object nor string\");\n}\n\n// ---------- 3) Validate + normalize ----------\nconst errs = [];\nconst warn = [];\nconst isNonEmpty = (s) => typeof s === \"string\" && s.trim().length > 0;\nconst arrOfStr = (a) => Array.isArray(a) ? a.map(x => String(x)).filter(Boolean) : [];\n\nif (!parsed.blog) errs.push(\"blog missing\");\nelse {\n  if (!isNonEmpty(parsed.blog.title)) errs.push(\"blog.title missing\");\n  if (!isNonEmpty(parsed.blog.slug)) errs.push(\"blog.slug missing\");\n  if (!isNonEmpty(parsed.blog.markdown)) errs.push(\"blog.markdown missing\");\n  if (parsed.blog.slug && parsed.blog.slug.length > 100) errs.push(\"blog.slug > 100 chars\");\n  parsed.blog.keywords = arrOfStr(parsed.blog.keywords);\n  parsed.blog.image_alt_texts = arrOfStr(parsed.blog.image_alt_texts);\n  if (\n    parsed.blog.canonical_url !== null &&\n    parsed.blog.canonical_url !== undefined &&\n    typeof parsed.blog.canonical_url !== \"string\"\n  ) errs.push(\"blog.canonical_url must be string or null\");\n}\n\nif (!parsed.linkedin) errs.push(\"linkedin missing\");\nelse {\n  if (!isNonEmpty(parsed.linkedin.final_text)) errs.push(\"linkedin.final_text missing\");\n  // hashtags soft window\n  parsed.linkedin.hashtags = arrOfStr(parsed.linkedin.hashtags);\n  if (parsed.linkedin.hashtags.length > 8) {\n    parsed.linkedin.hashtags = parsed.linkedin.hashtags.slice(0, 8);\n  }\n  // char guard\n  let ft = String(parsed.linkedin.final_text || \"\");\n  if (ft.length > 1200) {\n    let cut = ft.slice(0, 1180);\n    const lastBreak = Math.max(cut.lastIndexOf(\"\\n\"), cut.lastIndexOf(\".\"));\n    if (lastBreak > 800) cut = cut.slice(0, lastBreak + 1);\n    parsed.linkedin.final_text = cut;\n    warn.push(\"linkedin.final_text truncated to 1200 chars\");\n  }\n}\n\n// Safety flags: treat as warnings (expose downstream)\nif (!Array.isArray(parsed.safety_flags)) parsed.safety_flags = [];\nif (parsed.safety_flags.length) {\n  warn.push(\"safety_flags present: \" + parsed.safety_flags.join(\", \"));\n}\n\n// Hard errors?\nif (errs.length) {\n  throw new Error(\"Node11 validation failed: \" + errs.join(\"; \"));\n}\n\n// ---------- 4) Merge with Normalize Arrays (Node 9), return ----------\nlet norm = {};\ntry {\n  const n = $items(\"Function (Normalize Arrays)\", 0, $runIndex);\n  if (Array.isArray(n) && n[0] && n[0].json) norm = n[0].json;\n} catch (_) {}\n\nreturn [{\n  json: {\n    ...norm,\n    openai: parsed,\n    warnings: warn\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "3ab2103a-a358-415c-a4d1-1df7c3cb14f5",
      "name": "标准化数组",
      "type": "n8n-nodes-base.code",
      "position": [
        -432,
        -304
      ],
      "parameters": {
        "jsCode": "// Normalize arrays + carry configs\nfunction toArray(v){\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string'){\n    const s = v.trim();\n    if (!s) return [];\n    try { const parsed = JSON.parse(s); if (Array.isArray(parsed)) return parsed; } catch(e) {}\n    return s.split(',').map(x=>x.trim()).filter(Boolean);\n  }\n  return [];\n}\n\n// Pull config from the Set (Configs) node\n// Simple form:\nconst cfg = $node[\"Set (Configs)\"].json;\n// Robust form (if you prefer):\n// const cfg = $items(\"Set (Configs)\", 0, $runIndex)[0].json;\n\nconst i = items[0].json;\n\nreturn [{\n  json: {\n    NOTION_DB_ID: cfg.NOTION_DB_ID,\n    NOTION_PAGE_PARENT: cfg.NOTION_PAGE_PARENT,\n    LINKEDIN_PERSON_URN: cfg.LINKEDIN_PERSON_URN,\n    OPENAI_MODEL: cfg.OPENAI_MODEL,\n    EMAIL_TO: cfg.EMAIL_TO,\n\n    notion_page_id: i.notion_page_id,\n    title: i.title || '',\n    angle: i.angle || '',\n    tags: toArray(i.tags),\n    primary_link: i.primary_link || '',\n    reference_links: toArray(i.reference_links),\n    images: toArray(i.images),\n    notes: i.notes || '',\n    target_audience: i.target_audience || '',\n    canonical_url: i.canonical_url || '',\n    language: i.language || '',\n    slug: i.slug || ''\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "52a1ad9c-cc6a-49a1-ab7f-9b3a8a2e8c2b",
      "name": "创建帖子",
      "type": "n8n-nodes-base.linkedIn",
      "position": [
        1872,
        -432
      ],
      "parameters": {
        "text": "={{ $('Content Creator').item.json.message.content.linkedin.final_text }}",
        "person": "k47kCb899q",
        "additionalFields": {
          "title": "={{ $('Content Creator').item.json.message.content.blog.title }}",
          "visibility": "PUBLIC"
        },
        "binaryPropertyName": "=data",
        "shareMediaCategory": "IMAGE"
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "id": "DzG9q9KGhJCP5FSt",
          "name": "LinkedIn account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "128ee066-dca2-4c19-830b-621e3eafbbc0",
      "name": "创建文章数据库页面",
      "type": "n8n-nodes-base.notion",
      "position": [
        432,
        -304
      ],
      "parameters": {
        "title": "={{ $json.openai.blog.title }}",
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "25496301-7675-81bc-b023-c7e012094120",
          "cachedResultUrl": "https://www.notion.so/25496301767581bcb023c7e012094120",
          "cachedResultName": "Articles"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "title|title",
              "title": "={{ $json.openai.blog.title }}"
            },
            {
              "key": "slug|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.openai.blog.slug }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            },
            {
              "key": "excerpt|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.openai.blog.excerpt }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            },
            {
              "key": "keywords|multi_select",
              "multiSelectValue": "={{ $json.openai.blog.keywords }}"
            },
            {
              "key": "canonical_url|url",
              "urlValue": "={{ $json.openai.blog.canonical_url || '' }}",
              "ignoreIfEmpty": true
            },
            {
              "key": "suggested_cover_caption|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.openai.blog.suggested_cover_caption }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            },
            {
              "key": "image_alt_texts|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.openai.blog.image_alt_texts.join(', ') }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            },
            {
              "key": "language|select",
              "selectValue": "={{ $('Split In Batches (1)').item.json.language || 'en' }}"
            },
            {
              "key": "tags|multi_select",
              "multiSelectValue": "={{ $json.openai.linkedin.hashtags }}"
            },
            {
              "key": "status|select",
              "selectValue": "Published"
            },
            {
              "key": "published_at|date",
              "date": "={{ $now }}",
              "timezone": "Asia/Kathmandu"
            },
            {
              "key": "source_idea|relation",
              "relationValue": [
                "={{ $('Split In Batches (1)').item.json.notion_page_id }}"
              ]
            },
            {
              "key": "linkedin_draft|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.openai.linkedin.final_text }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "id": "AU61TARrYLYMxTj9",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6160be76-97f5-4f4c-bfa6-5e480080d854",
      "name": "草稿邮件",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1120,
        -80
      ],
      "webhookId": "4a91eae9-a78f-4246-bdf2-faaf10f3afdd",
      "parameters": {
        "sendTo": "={{ $('Set (Configs)').item.json.EMAIL_TO }}",
        "message": "=Title: {{ $json.properties.title.title[0].text.content }}\nDraft: {{ $json.properties.linkedin_draft.rich_text[0].text.content }}",
        "options": {},
        "subject": "LinkedIn Draft Ready",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "g6m2gV1BtMtEggjm",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a1a7482f-3868-402c-a05b-2535b8443ad7",
      "name": "已发布邮件",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2096,
        -432
      ],
      "webhookId": "f2d6603d-058d-43dd-8d67-aaed9476c825",
      "parameters": {
        "sendTo": "mail@budhathokisagar.com.np",
        "message": "=Published: {{ $('Create a Article Database Page').item.json.properties.title.title[0].text.content }}\nSlug: {{ $('Create a Article Database Page').item.json.properties.slug.rich_text[0].text.content }}\nLinkedIn: posted as person.\nIdea Page: {{ $('Create a Article Database Page').item.json.id }}",
        "options": {},
        "subject": "LinkedIn Post Published!",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "g6m2gV1BtMtEggjm",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a7b80170-9832-46fb-85ba-8b87c5bd9da4",
      "name": "草稿更新数据库",
      "type": "n8n-nodes-base.notion",
      "position": [
        1344,
        -80
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create a Article Database Page').item.json.id }}"
        },
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "status|select",
              "selectValue": "Draft"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "id": "AU61TARrYLYMxTj9",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4e43c32b-407c-4a62-8a0d-2b5eea10c615",
      "name": "更新数据库页面",
      "type": "n8n-nodes-base.notion",
      "position": [
        2320,
        -432
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create a Article Database Page').item.json.id }}"
        },
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "status|select",
              "selectValue": "Published"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "id": "AU61TARrYLYMxTj9",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c3dfe348-0a68-45ee-b538-2f72fdbffaa9",
      "name": "下载图片",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1648,
        -432
      ],
      "parameters": {
        "url": "={{ $json.output[0] }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "4b21b649-4087-4ef2-aa8d-9ee53c5db581",
      "name": "复制图像预测",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1424,
        -432
      ],
      "parameters": {
        "url": "https://api.replicate.com/v1/models/black-forest-labs/flux-schnell/predictions",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "jsonBody": "={\n    \"input\": {\n      \"prompt\": \"{{ $json.message.content }}\",\n      \"aspect_ratio\": \"16:9\"\n    }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "wait"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "UMvkuuToRy2C4VYfo",
          "name": "Bearer Auth Replicate"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "2dd65c1f-d859-4809-857b-7f8b6e535306",
      "name": "内容生成器",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -208,
        -304
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "GPT-5-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=You are a senior technical writer and LinkedIn ghostwriter for a Nepal-based DevOps/CloudOps/SysOps/Python developer who also loves AI/ML. \nYour job is to take one Notion row and turn it into:\n\n1) A polished, human-readable blog article for Hashnode (Markdown only).\n2) A LinkedIn post that feels authentic, insightful, and share-worthy, and most-importantly simpler english.\n\nYour voice should feel like a real engineer sharing something useful:\n- Informative but conversational\n- Confident but humble\n- Sometimes witty, but never forced\n- Includes actionable value (tips, insights, commands, lessons)\n- Occasionally adds light Nepali flavor naturally if language=\"ne\"\n\n---\n### INPUT\n- title: {{ $json.title }}\n- angle: {{ $json.angle }}\n- tags: {{ $json.tags }}\n- primary_link: {{ $json.primary_link }}\n- reference_links: {{ $json.reference_links }}\n- images: {{ $json.images }}\n- notes: {{ $json.notes }}\n- target_audience: {{ $json.target_audience }}\n- canonical_url: {{ $json.canonical_url }}\n- language: {{ $json.language }}\n- slug: {{ $json.slug }}\n\n---\n### PREFERENCES\n- LinkedIn posts ≤ 1200 characters\n- Blog word count:\n  - Rich notes/tags: 900–1400 words\n  - Sparse notes/tags: 600–900 words\n- Include at least one specific example, command, or actionable tip\n- Only one link allowed in LinkedIn text (if primary_link exists)\n\n---\n### STYLE TARGETS\nFor LinkedIn, pick the most natural style automatically:\n- **Story:** Small anecdote or lesson\n- **Industry Take:** Commentary with reflection\n- **Tech Breakdown:** Clear step-by-step with code/tips\n- **Basics:** Foundational guidance in checklist format\n- **Humor List:** Funny but relatable \"few techs\" overwhelm joke\n- **Optimization/Win:** Real-world result or improvement shared\n\n---\n### BLOG REQUIREMENTS\n- Markdown only, no frontmatter\n- Structure:\n  - Hook intro (2–4 lines)\n  - Clear sections with H2/H3\n  - Include steps, code snippets, or bullet lists\n  - Add “Sharp edges & gotchas” with realistic pitfalls\n  - Include a mini case/example\n  - End with actionable “Key Takeaways” (3–6 bullets)\n- Include:\n  - SEO: slug, excerpt, keywords (5–10)\n  - Suggested cover caption\n  - Alt text suggestions for images\n  - Canonical URL if provided\n\n---\n### LINKEDIN REQUIREMENTS\n- Start with a strong HOOK (1–2 lines), do not mention word itself like 'hook' or similar\n- Use short, human paragraphs\n- Include at least one actionable tip or fact\n- Invite engagement with a closing question or CTA\n- Add 5–10 hashtags, a mix of broad (#DevOps #Cloud) and niche (#AWS #Kubernetes #Observability)\n\n---\n### RULES\n- Never invent unknown facts\n- Prioritize clear, human language\n- Favor real-world examples over generic advice\n- Use emojis sparingly and purposefully (max 3)\n\n---\n### OUTPUT SCHEMA\n{\n  \"blog\": {\n    \"title\": \"string\",\n    \"slug\": \"string\",\n    \"excerpt\": \"string\",\n    \"keywords\": [\"string\", \"...\"],\n    \"canonical_url\": \"string|null\",\n    \"suggested_cover_caption\": \"string\",\n    \"image_alt_texts\": [\"string\", \"...\"],\n    \"markdown\": \"string\"\n  },\n  \"linkedin\": {\n    \"style_used\": \"story|industry_take|tech_breakdown|basics|humor_list|optimization\",\n    \"final_text\": \"string\",\n    \"alt_titles\": [\"string\",\"string\",\"string\"]\n  },\n  \"safety_flags\": []\n}"
            }
          ]
        },
        "simplify": "={{ true }}",
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "id": "1JMlq9LFlvNZ4n7z",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "17809fd9-84d8-458b-a904-b497549c10dd",
      "name": "图像提示生成器",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1072,
        -432
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "={\n  \"title\": \"{{$json.properties?.title?.title?.[0]?.plain_text || ''}}\",\n  \"excerpt\": \"{{$json.properties?.excerpt?.rich_text?.[0]?.plain_text || ''}}\",\n  \"linkedin_draft\": \"{{$json.properties?.linkedin_draft?.rich_text?.[0]?.plain_text || ''}}\",\n  \"alt\": \"{{$json.properties?.image_alt_texts?.rich_text?.[0]?.plain_text || ''}}\",\n  \"keywords\": \"{{$json.properties?.keywords?.multi_select?.map(k => k.name).join(', ') || ''}}\"\n}\n"
            },
            {
              "role": "system",
              "content": "You generate a single, realistic text-to-image prompt for the Replicate model black-forest-labs/flux-schnell, based on details from a LinkedIn post.\n\nRULES:\n- Output only the prompt as plain text, no JSON, no commentary.\n- Make the scene look photorealistic but clean and professional — perfect for LinkedIn.\n- Focus on key objects, actions, and environment described in the post (title, excerpt, alt, keywords).\n- Include subtle realistic elements (lighting, depth, perspective, color) but keep the layout minimal and balanced.\n- Never include any legible text, logos, watermarks, brand names, or faces.\n- Use soft professional lighting, shallow depth of field, and natural tones.\n- Keep it under ~900 characters.\n- Default to a 16:9 aspect ratio.\n"
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "1JMlq9LFlvNZ4n7z",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "20246ca2-9171-4ba8-8009-f43a43296c59",
      "name": "失败消息",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1232,
        2272
      ],
      "webhookId": "3fd774cb-ed1a-4d99-9680-46fed3bdeb82",
      "parameters": {
        "sendTo": "={{$json.execution?.error?.workflow?.data?.startData?.runData?.['Set (Configs)']?.[0]?.json?.EMAIL_TO || 'test@mail.com'}}",
        "message": "=Node: {{$json.execution?.error?.node?.name}}\\nMessage: {{$json.execution?.error?.message}}\\nStack: {{$json.execution?.error?.stack}}\\nLast Payload: {{JSON.stringify($json.execution?.error?.node?.data, null, 2).slice(0,5000)}}",
        "options": {},
        "subject": "=Blog Pipeline ERROR: {{$json.execution?.error?.message || 'Unknown error'}}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "g6m2gV1BtMtEggjm",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "efd5db98-aa5e-46e4-9d6c-4708b8db08a4",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1712,
        -624
      ],
      "parameters": {
        "color": 4,
        "width": 960,
        "height": 832,
        "content": "# 初始化与数据收集"
      },
      "typeVersion": 1
    },
    {
      "id": "0c0f92c8-d1b4-4e11-86cf-dc32022e984b",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -624
      ],
      "parameters": {
        "color": 4,
        "width": 1024,
        "height": 832,
        "content": "# 内容处理与AI生成"
      },
      "typeVersion": 1
    },
    {
      "id": "69e0c3a8-1239-4283-8c64-7c8aa8c3ec4e",
      "name": "如果LinkedIn发布检查",
      "type": "n8n-nodes-base.if",
      "position": [
        640,
        -304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "58a827f7-5153-4641-afbd-9bdf3d62ee2c",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $('Set (Configs)').item.json.LINKEDIN_PUBLISH || false }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "alwaysOutputData": false
    },
    {
      "id": "b3f96e1b-73d8-4153-84ef-952fd9785888",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        336,
        -624
      ],
      "parameters": {
        "color": 5,
        "width": 608,
        "height": 832,
        "content": "# 内容存储与发布决策"
      },
      "typeVersion": 1
    },
    {
      "id": "c663ee05-545d-4c1e-995d-26ed92ecba6d",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        976,
        -624
      ],
      "parameters": {
        "color": 5,
        "width": 1536,
        "height": 832,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "995fee04-6be5-4b7b-ad46-6a0965696e5c",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1920,
        -144
      ],
      "parameters": {
        "color": 5,
        "width": 592,
        "height": 352,
        "content": "# 发布与完成"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "Draft Email": {
      "main": [
        [
          {
            "node": "Draft Update Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a post": {
      "main": [
        [
          {
            "node": "Published Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set (Configs)": {
      "main": [
        [
          {
            "node": "Notion → Query Ideas DB (all)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Count Eligible": {
      "main": [
        [
          {
            "node": "IF (Has Eligible?)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Image": {
      "main": [
        [
          {
            "node": "Create a post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send a message": {
      "main": [
        []
      ]
    },
    "Content Creator": {
      "main": [
        [
          {
            "node": "Parse & Validate JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cron (Schedule)": {
      "main": [
        [
          {
            "node": "Set (Configs)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Published Email": {
      "main": [
        [
          {
            "node": "Update a database page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Arrays": {
      "main": [
        [
          {
            "node": "Content Creator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF (Has Eligible?)": {
      "main": [
        [],
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split In Batches (1)": {
      "main": [
        [
          {
            "node": "Normalize Arrays",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Validate JSON": {
      "main": [
        [
          {
            "node": "Create a Article Database Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Image prompt generator": {
      "main": [
        [
          {
            "node": "Replicate Image Prediction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update a database page": {
      "main": [
        []
      ]
    },
    "Filter Unpublished + Map": {
      "main": [
        [
          {
            "node": "Split In Batches (1)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Count Eligible",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Replicate Image Prediction": {
      "main": [
        [
          {
            "node": "Download Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If LinkedIn Published Check": {
      "main": [
        [
          {
            "node": "Image prompt generator",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Draft Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a Article Database Page": {
      "main": [
        [
          {
            "node": "If LinkedIn Published Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger (Any Node Fails)": {
      "main": [
        [
          {
            "node": "Failure Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion → Query Ideas DB (all)": {
      "main": [
        [
          {
            "node": "Filter Unpublished + Map",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

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

需要付费吗?

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

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

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

作者
Sagar Budhathoki

Sagar Budhathoki

@sbmagar13

A DevOps and AI Engineer with a passion for automation, infrastructure as code, building resilient systems, and exploring AI agents & MCP technologies.

外部链接
在 n8n.io 查看

分享此工作流