8
n8n 中文网amn8n.com

Shopify博客内部链接

高级

这是一个Content Creation, AI Summarization领域的自动化工作流,包含 26 个节点。主要使用 If, Set, Code, DataTable, HttpRequest 等节点。 使用OpenAI text-embedding-3-small自动生成Shopify博客相关文章

前置要求
  • 可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "01ZGpwv1rdsk5Ng8",
  "meta": {
    "instanceId": "8e9162e70be518ca153a70a16d8785f5bfc6523821e135712fb7ef93fe97a5dd",
    "templateCredsSetupCompleted": true
  },
  "name": "Shopify博客内部链接",
  "tags": [],
  "nodes": [
    {
      "id": "8848b159-986e-4b67-8bde-a38da0a25f36",
      "name": "计划触发器",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1808,
        496
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtHour": 20
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "057f8499-694c-4391-80a1-e2f7ca093d25",
      "name": "工作流程配置",
      "type": "n8n-nodes-base.set",
      "position": [
        -1584,
        496
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "566ed7c6-84cf-4fcf-ae6e-5607fa4c3909",
              "name": "shopifyBlogId",
              "type": "string",
              "value": ""
            },
            {
              "id": "bdcbb25a-eba1-4a26-bc4e-e4dd8eb268db",
              "name": "shopifyBlogDomain",
              "type": "string",
              "value": "<https://example.com/blogs/>"
            },
            {
              "id": "6f1aaf1c-eb2f-42ac-b16e-6e4cd8cabd9f",
              "name": "shopifyStoreName",
              "type": "string",
              "value": "<domain_before_myshopify.com>"
            },
            {
              "id": "d704d6dd-d887-40d3-9f3b-1a61010095d2",
              "name": "shopApiVersion",
              "type": "string",
              "value": "2025-07"
            },
            {
              "id": "027f4123-2194-4f6d-8411-1305e7602692",
              "name": "percent_minimum_similarity",
              "type": "number",
              "value": 70
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ce7cbd23-b0ec-4420-a262-cc16ddd9f5bd",
      "name": "从Shopify获取文章",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1360,
        496
      ],
      "parameters": {
        "url": "=https://{{ $('Workflow Configuration').first().json.shopifyStoreName }}.myshopify.com/admin/api/{{ $('Workflow Configuration').first().json.shopApiVersion }}/blogs/{{ $('Workflow Configuration').first().json.shopifyBlogId }}/articles.json",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "published_status",
              "value": "published"
            }
          ]
        },
        "nodeCredentialType": "shopifyAccessTokenApi"
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "id": "oDrAi4lTTxnawLSv",
          "name": "Shopify Access Token account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "3623adca-6827-467c-81f7-6f138377aefd",
      "name": "清理和准备文本",
      "type": "n8n-nodes-base.code",
      "position": [
        -1136,
        496
      ],
      "parameters": {
        "jsCode": "// Function to clean HTML and remove the related section\nfunction stripHtml(html) {\n  if (!html) return '';\n  return html\n    .replace(/<style[^>]*>.*?<\\/style>/gi, '')\n    .replace(/<script[^>]*>.*?<\\/script>/gi, '')\n    .replace(/<div class=\"related-articles\"[^>]*>[\\s\\S]*?<\\/div>/gi, '') // remove related articles \n    .replace(/<[^>]+>/g, ' ')\n    .replace(/\\s+/g, ' ')\n    .replace(/&nbsp;/g, ' ')\n    .replace(/&amp;/g, '&')\n    .replace(/&lt;/g, '<')\n    .replace(/&gt;/g, '>')\n    .trim();\n}\n\n// Detect what we receive from previous node\nlet allItems = $input.all();\nlet articles = [];\n\n//  1: if multiple items\nif (allItems.length > 0) {\n  allItems.forEach(item => {\n    // Verificar si el item contiene un array \"articles\"\n    if (item.json && Array.isArray(item.json.articles)) {\n      articles = articles.concat(item.json.articles);\n    } \n    // if only one item\n    else if (item.json && item.json.id && item.json.title) {\n      articles.push(item.json);\n    }\n  });\n}\n\n// Fallback if no articles found\nif (articles.length === 0 && $input.item.json) {\n  if (Array.isArray($input.item.json.articles)) {\n    articles = $input.item.json.articles;\n  } else if ($input.item.json.id && $input.item.json.title) {\n    articles = [$input.item.json];\n  }\n}\n\n\n// Process each article\nconst processedArticles = articles.map(article => {\n  const cleanContent = stripHtml(article.body_html);\n  const cleanSummary = stripHtml(article.summary_html);\n  \n  // Create text for embeddings \n  const textForEmbedding = `Título: ${article.title}\n\nResumen: ${cleanSummary}\n\nContenido: ${cleanContent.substring(0, 15000)}`;\n\n  return {\n    shopify_id: article.id,\n    blog_id: article.blog_id,\n    shopify_handle: article.handle,\n    title: article.title,\n    content: cleanContent,\n    summary: cleanSummary,\n    url: $('Workflow Configuration').first().json.shopifyBlogDomain + article.handle,\n    published_at: article.published_at,\n    text_for_embedding: textForEmbedding,\n    word_count: cleanContent.split(/\\s+/).filter(w => w.length > 0).length\n  };\n});\n\nreturn processedArticles.map(article => ({ json: article }));"
      },
      "typeVersion": 2
    },
    {
      "id": "a91f14ad-f42c-4ad9-9ddd-4a218e8b8514",
      "name": "遍历项目",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -912,
        496
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "8a1ffb69-65c0-4cf5-a4cb-e9209a9dc0ea",
      "name": "OpenAI获取嵌入",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -464,
        512
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/embeddings",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "text-embedding-3-small"
            },
            {
              "name": "input",
              "value": "={{ $json.embedding }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "id": "F6XMlOYUADkfTF7M",
          "name": "OpenAi key"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7d83e353-0272-4857-ad4e-f3baab2e62b6",
      "name": "设置文章字段",
      "type": "n8n-nodes-base.set",
      "position": [
        -688,
        512
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e443624a-de8d-485f-a3a1-b567c3145c2c",
              "name": "shopify_id",
              "type": "number",
              "value": "={{ $json.shopify_id }}"
            },
            {
              "id": "139eedb1-6aa3-434a-9425-fac9234c5148",
              "name": "blog_id",
              "type": "number",
              "value": "={{ $json.blog_id }}"
            },
            {
              "id": "9950f411-833a-488f-9f6a-b17f338114bf",
              "name": "shopify_handle",
              "type": "string",
              "value": "={{ $json.shopify_handle }}"
            },
            {
              "id": "1d83dc8d-c93d-41bb-ba5e-0a01f055c0fe",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "4a2a7109-b8d1-43f7-9d69-6d1f0cbef95a",
              "name": "content",
              "type": "string",
              "value": "={{ $json.content }}"
            },
            {
              "id": "0db25418-7777-4fc2-b774-4abf85819790",
              "name": "summary",
              "type": "string",
              "value": "={{ $json.summary }}"
            },
            {
              "id": "960a20c6-77ae-434a-9646-7b562da78a2e",
              "name": "url",
              "type": "string",
              "value": "={{ $json.url }}"
            },
            {
              "id": "4080709d-46e3-4d5c-b4b8-4cc599fae16c",
              "name": "published_at",
              "type": "string",
              "value": "={{ $json.published_at }}"
            },
            {
              "id": "83f98c7d-6ce7-4b58-9034-72f7b78a59e8",
              "name": "embedding",
              "type": "string",
              "value": "={{ $json.text_for_embedding }})"
            },
            {
              "id": "9a2a581c-2c3b-4a27-bde8-a3a62590a9df",
              "name": "analyzed_at",
              "type": "string",
              "value": "={{new Date().toISOString()}}"
            },
            {
              "id": "3a53791e-f7c6-4cef-ad55-8a37c9239073",
              "name": "word_count",
              "type": "number",
              "value": "={{ $json.word_count }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "55ce71bc-afc1-4178-87a3-6fda9829bd68",
      "name": "计算相似度",
      "type": "n8n-nodes-base.code",
      "position": [
        -688,
        48
      ],
      "parameters": {
        "jsCode": "const doneItems = $(\"Loop Over Items\").all();\n\nconsole.log(`📦 Total items recibidos: ${doneItems.length}`);\n\n// Extract and prepare articles\nconst allArticles = doneItems.map(item => {\n  const data = item.json;\n  \n  // Parsing embedding\n  const embedding = typeof data.embedding === 'string' \n    ? JSON.parse(data.embedding) \n    : data.embedding;\n  \n  return {\n    shopify_id: data.shopify_id,\n    blog_id: data.blog_id,\n    title: data.title,\n    url: data.url,\n    embedding: embedding\n  };\n});\n\nconst uniqueIds = new Set(allArticles.map(a => a.shopify_id));\n\nif (allArticles.length < 2) {\n  throw new Error(`❌ Se necesitan al menos 2 artículos. Solo hay ${allArticles.length}`);\n}\n\nif (uniqueIds.size < 2) {\n  throw new Error(`❌ Todos los artículos tienen el mismo ID (${Array.from(uniqueIds)[0]})`);\n}\n\n// Function to calculate similarities\nfunction cosineSimilarity(vecA, vecB) {\n  if (!vecA || !vecB || vecA.length !== vecB.length) {\n    throw new Error('❌ Embeddings inválidos o de diferente longitud');\n  }\n  \n  let dotProduct = 0;\n  let normA = 0;\n  let normB = 0;\n  \n  for (let i = 0; i < vecA.length; i++) {\n    dotProduct += vecA[i] * vecB[i];\n    normA += vecA[i] * vecA[i];\n    normB += vecB[i] * vecB[i];\n  }\n  \n  const similarity = dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));\n  return Math.round(similarity * 100 * 100) / 100;\n}\n\nconst relations = [];\nlet comparacionesRealizadas = 0;\n\nfor (let i = 0; i < allArticles.length; i++) {\n  for (let j = 0; j < allArticles.length; j++) {\n    \n    // ⚠️ Rule to avoid comparing one article to itself\n    if (allArticles[i].shopify_id === allArticles[j].shopify_id) {\n      continue; // Saltar esta iteración\n    }\n    \n    comparacionesRealizadas++;\n    \n    try {\n      const similarity = cosineSimilarity(\n        allArticles[i].embedding,\n        allArticles[j].embedding\n      );\n      \n      // Only keep similarity above the setting\n      if (similarity >= $('Workflow Configuration').first().json.percent_minimum_similarity) {\n        relations.push({\n          source_shopify_id: allArticles[i].shopify_id,\n          source_blog_id: allArticles[i].blog_id,\n          source_title: allArticles[i].title,\n          related_shopify_id: allArticles[j].shopify_id,\n          related_title: allArticles[j].title,\n          related_url: allArticles[j].url,\n          relation_type: \"semantic_similarity\",\n          similarity_score: similarity\n        });\n      }\n    } catch (error) {\n      console.error(`Error comparando ${allArticles[i].shopify_id} con ${allArticles[j].shopify_id}:`, error.message);\n    }\n  }\n}\n\n// In case, not enough similarity\nif (relations.length === 0) {\n  return [{ \n    json: { \n      mensaje: \"No se encontraron relaciones con similitud >= 60%\",\n      articulos_procesados: allArticles.length,\n      articulos_unicos: uniqueIds.size,\n      comparaciones_realizadas: comparacionesRealizadas,\n      sugerencia: \"Intenta bajar el umbral de similitud o verifica que los embeddings sean correctos\",\n      muestra_articulos: allArticles.slice(0, 3).map(a => ({\n        shopify_id: a.shopify_id,\n        title: a.title,\n        longitud_embedding: a.embedding.length\n      }))\n    } \n  }];\n}\n\nreturn relations.map(rel => ({ json: rel }));"
      },
      "typeVersion": 2,
      "alwaysOutputData": false
    },
    {
      "id": "762e212e-1907-4610-9bcd-cc7b79258172",
      "name": "更新插入文章",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -240,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "url": "={{ $('Set article fields').item.json.url }}",
            "title": "={{ $('Set article fields').item.json.title }}",
            "blog_id": "={{ $('Set article fields').item.json.blog_id }}",
            "content": "={{ $('Set article fields').item.json.content }}",
            "summary": "={{ $('Set article fields').item.json.summary }}",
            "embedding": "={{ JSON.stringify($json.data[0].embedding) }}",
            "shopify_id": "={{ $('Set article fields').item.json.shopify_id }}",
            "word_count": "={{ $('Set article fields').item.json.word_count }}",
            "published_at": "={{ $('Set article fields').item.json.published_at }}",
            "shopify_handle": "={{ $('Set article fields').item.json.shopify_handle }}",
            "last_analyzed_at": "={{ $('Set article fields').item.json.analyzed_at }}"
          },
          "schema": [
            {
              "id": "shopify_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "shopify_id",
              "defaultMatch": false
            },
            {
              "id": "shopify_handle",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "shopify_handle",
              "defaultMatch": false
            },
            {
              "id": "title",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "title",
              "defaultMatch": false
            },
            {
              "id": "content",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "content",
              "defaultMatch": false
            },
            {
              "id": "summary",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "summary",
              "defaultMatch": false
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "url",
              "defaultMatch": false
            },
            {
              "id": "published_at",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "published_at",
              "defaultMatch": false
            },
            {
              "id": "embedding",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "embedding",
              "defaultMatch": false
            },
            {
              "id": "last_analyzed_at",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "last_analyzed_at",
              "defaultMatch": false
            },
            {
              "id": "word_count",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "word_count",
              "defaultMatch": false
            },
            {
              "id": "blog_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "blog_id",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "filters": {
          "conditions": [
            {
              "keyName": "shopify_id",
              "keyValue": "={{ $('Set article fields').item.json.shopify_id }}"
            }
          ]
        },
        "options": {},
        "matchType": "allConditions",
        "operation": "upsert",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "kjtDGPfteUD1V64N",
          "cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/kjtDGPfteUD1V64N",
          "cachedResultName": "articles"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6607766a-147e-49b6-b127-6655d3221c8c",
      "name": "更新插入文章关系",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -464,
        48
      ],
      "parameters": {
        "columns": {
          "value": {
            "related_url": "={{ $json.related_url }}",
            "source_title": "={{ $json.source_title }}",
            "related_title": "={{ $json.related_title }}",
            "source_blog_id": "={{ $json.source_blog_id }}",
            "similarity_score": "={{ $json.similarity_score }}",
            "source_shopify_id": "={{ $json.source_shopify_id }}",
            "related_shopify_id": "={{ $json.related_shopify_id }}"
          },
          "schema": [
            {
              "id": "source_shopify_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "source_shopify_id",
              "defaultMatch": false
            },
            {
              "id": "source_blog_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "source_blog_id",
              "defaultMatch": false
            },
            {
              "id": "source_title",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "source_title",
              "defaultMatch": false
            },
            {
              "id": "related_shopify_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "related_shopify_id",
              "defaultMatch": false
            },
            {
              "id": "related_title",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "related_title",
              "defaultMatch": false
            },
            {
              "id": "related_url",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "related_url",
              "defaultMatch": false
            },
            {
              "id": "relation_type",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "relation_type",
              "defaultMatch": false
            },
            {
              "id": "similarity_score",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "similarity_score",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "filters": {
          "conditions": [
            {
              "keyName": "source_shopify_id",
              "keyValue": "={{ $json.source_shopify_id }}"
            },
            {
              "keyName": "related_shopify_id",
              "keyValue": "={{ $json.related_shopify_id }}"
            }
          ]
        },
        "options": {},
        "matchType": "allConditions",
        "operation": "upsert",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "KXwn5vzq2gEz09tM",
          "cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/KXwn5vzq2gEz09tM",
          "cachedResultName": "article_relations"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ff514a42-ee01-448a-8951-4b6d82ecff01",
      "name": "前3篇相关文章",
      "type": "n8n-nodes-base.code",
      "position": [
        -240,
        48
      ],
      "parameters": {
        "jsCode": "// ============================================\n// GROUP AND GET TOP 3 RELATED ARTICLES\n// ============================================\n\nconst relations = $(\"Calculate similarities\").all().map(item => item.json);\n\n// Group by source_shopify_id\nconst groupedBySource = relations.reduce((acc, relation) => {\n  const sourceId = relation.source_shopify_id;\n  \n  if (!acc[sourceId]) {\n    acc[sourceId] = {\n      source_shopify_id: sourceId,\n      source_blog_id: relation.source_blog_id,\n      source_title: relation.source_title,\n      source_url: relation.source_url,\n      related_articles: []\n    };\n  }\n  \n  // Add related article with its similarity score\n  acc[sourceId].related_articles.push({\n    related_shopify_id: relation.related_shopify_id,\n    related_title: relation.related_title,\n    related_url: relation.related_url,\n    similarity_score: relation.similarity_score\n  });\n  \n  return acc;\n}, {});\n\n// Convert to array and get top 3 for each source\nconst result = Object.values(groupedBySource).map(group => {\n  // Sort by similarity_score (highest first) and take top 3\n  const top3Related = group.related_articles\n    .sort((a, b) => b.similarity_score - a.similarity_score)\n    .slice(0, 3)\n    .map(article => article.related_shopify_id);\n  \n  return {\n    source_shopify_id: group.source_shopify_id,\n    related_shopify_ids: top3Related\n  };\n});\n\n// Return as separate items for next node\nreturn result.map(item => ({ json: item }));"
      },
      "typeVersion": 2
    },
    {
      "id": "088f6ac5-4c84-4c63-ba89-ab778c3ce547",
      "name": "源文章循环",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -16,
        48
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "28f1bf7c-db78-4f1f-8db3-b00474dd7284",
      "name": "获取先前相关文章",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        208,
        64
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "source_shopify_id",
              "keyValue": "={{ $json.source_shopify_id }}"
            }
          ]
        },
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "7RrUjeEF2Zfcxpsn",
          "cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/7RrUjeEF2Zfcxpsn",
          "cachedResultName": "article_related_links_snapshot"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "268e6a49-f852-4056-b9cf-8b912f5b19e1",
      "name": "检查文章是否已有相关文章",
      "type": "n8n-nodes-base.if",
      "position": [
        432,
        64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6a466a42-552d-4be0-a443-e2907f660ba4",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.source_shopify_id }}",
              "rightValue": "={{ $('Loop for source articles').item.json.related_shopify_ids }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b41317b7-4a8c-4043-94e8-89b6add1c772",
      "name": "更新插入关系",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        688,
        80
      ],
      "parameters": {
        "columns": {
          "value": {
            "source_shopify_id": "={{ $('Loop for source articles').item.json.source_shopify_id }}",
            "related_shopify_ids": "={{ $('Loop for source articles').item.json.related_shopify_ids.join() }}"
          },
          "schema": [
            {
              "id": "source_shopify_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "source_shopify_id",
              "defaultMatch": false
            },
            {
              "id": "related_shopify_ids",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "related_shopify_ids",
              "defaultMatch": false
            },
            {
              "id": "related_urls",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "related_urls",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "filters": {
          "conditions": [
            {
              "keyName": "source_shopify_id",
              "keyValue": "={{ $('Loop for source articles').item.json.source_shopify_id }}"
            }
          ]
        },
        "options": {},
        "operation": "upsert",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "7RrUjeEF2Zfcxpsn",
          "cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/7RrUjeEF2Zfcxpsn",
          "cachedResultName": "article_related_links_snapshot"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2d051e8b-9f67-4ed3-8a2a-85d19281452f",
      "name": "为相关文章准备HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        1344,
        80
      ],
      "parameters": {
        "jsCode": "// ============================================\n// PREPARE HTML FOR RELATED ARTICLES\n// ============================================\n\n// Get source article ID from \"Upsert relations\" node\nconst sourceArticle = $('Upsert relations').first().json;\nconst sourceShopifyId = sourceArticle.source_shopify_id;\n\n// Get related articles details from \"Get related article details\" node\nconst relatedArticles = $('Get related article details').all().map(i => i.json);\n\n// Build the HTML for related articles section\nlet relatedHTML = `\n<div class=\"related-articles\" style=\"margin: 40px 0;\">\n  <h3>📚 Artículos relacionados que te pueden interesar</h3>\n  <ul style=\"list-style: none; padding: 0;\">\n`;\n\n// Add each related article as a link\nrelatedArticles.forEach(article => {\n  relatedHTML += `\n    <li style=\"margin-bottom: 10px;\">\n      <a href=\"${article.url}\">→ ${article.title}</a>\n    </li>\n  `;\n});\n\nrelatedHTML += `\n  </ul>\n</div>\n`;\n\nreturn {\n  json: {\n    source_shopify_id: sourceShopifyId,\n    related_articles_html: relatedHTML,\n    related_count: relatedArticles.length\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0e6e4ad1-cf86-4e35-a862-bc8219c99838",
      "name": "检查相关文章是否相同",
      "type": "n8n-nodes-base.if",
      "position": [
        608,
        -288
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "320c269c-572b-4888-b6c0-7ceec4db0e30",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Loop for source articles').item.json.related_shopify_ids.join() }}",
              "rightValue": "={{ $('Get previous related_articles').item.json.related_shopify_ids }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "73604394-344d-469e-b845-0f3660abccaf",
      "name": "无需更改相关部分",
      "type": "n8n-nodes-base.noOp",
      "position": [
        816,
        -304
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "2bc885ba-cbc4-4623-82ac-e85759170a6d",
      "name": "获取相关文章详情",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1120,
        80
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "shopify_id",
              "keyValue": "={{ $json.related_shopify_id }}"
            }
          ]
        },
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "kjtDGPfteUD1V64N",
          "cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/kjtDGPfteUD1V64N",
          "cachedResultName": "articles"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "85357d92-5b8b-4e36-acba-a1f3473237ae",
      "name": "拆分相关ID",
      "type": "n8n-nodes-base.code",
      "position": [
        896,
        80
      ],
      "parameters": {
        "jsCode": "return $input.all().flatMap(item => {\n  const ids = item.json.related_shopify_ids.split(',').map(id => id.trim());\n  return ids.map(relatedId => ({\n    json: {\n      source_shopify_id: item.json.source_shopify_id,\n      related_shopify_id: relatedId\n    }\n  }));\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "36042f8c-f7b5-48bc-949f-44f8521d407e",
      "name": "在文章中插入相关文章",
      "type": "n8n-nodes-base.code",
      "position": [
        1568,
        80
      ],
      "parameters": {
        "jsCode": "// ============================================\n// UPDATE SHOPIFY ARTICLE WITH RELATED LINKS\n// ============================================\n\nconst item = $input.item.json;\n\n// Get current article content from Shopify\nconst currentArticle = $('Get articles from shopify').first().json.articles.find(a => a.id === $input.first().json.source_shopify_id);\nlet currentContent = currentArticle.body_html || '';\n\n// Remove old related articles section if exists\ncurrentContent = currentContent.replace(\n  /<div class=\"related-articles\"[^>]*>[\\s\\S]*?<\\/div>/gi, \n  ''\n);\n\n// Add new related articles at the end\nconst updatedContent = currentContent.trim() + '\\n\\n' + item.related_articles_html;\n\nconst article = {\n  id: item.source_shopify_id,\n  body_html: updatedContent\n}\n\nreturn [{ json: { article } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1524f17c-e0b2-41dc-a948-4e085885b0a2",
      "name": "使用相关文章更新文章",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1792,
        80
      ],
      "parameters": {
        "url": "=https://{{ $('Workflow Configuration').first().json.shopifyStoreName }}.myshopify.com/admin/api/{{ $('Workflow Configuration').first().json.shopApiVersion }}/blogs/{{ $('Workflow Configuration').first().json.shopifyBlogId }}/articles/{{ $json.article.id }}.json",
        "method": "PUT",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "shopifyAccessTokenApi"
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "id": "oDrAi4lTTxnawLSv",
          "name": "Shopify Access Token account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e9d3c731-ff01-4bbc-9c8c-a6eed48abb20",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -976,
        304
      ],
      "parameters": {
        "width": 896,
        "height": 480,
        "content": "## 使用\"text-embedding-3-small\"模型分析每篇文章并保存到数据表"
      },
      "typeVersion": 1
    },
    {
      "id": "d61c23f1-2de2-4b63-9e3b-a38cbb37688d",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        -448
      ],
      "parameters": {
        "color": 5,
        "width": 2736,
        "height": 736,
        "content": "## 核心流程"
      },
      "typeVersion": 1
    },
    {
      "id": "4d66e34f-f02c-4b30-8a7e-182b828330fd",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1856,
        304
      ],
      "parameters": {
        "color": 4,
        "width": 864,
        "height": 480,
        "content": "## 设置"
      },
      "typeVersion": 1
    },
    {
      "id": "03a381af-5bf9-4fa1-a633-3e2a154b1ceb",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1856,
        -448
      ],
      "parameters": {
        "color": 7,
        "width": 1072,
        "height": 736,
        "content": "## 重要提示 启动工作流程前请阅读"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "ib0LqomNsNIqEoi6",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "f2d0a7cc-1be7-4878-bd20-e82dae800398",
  "connections": {
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Calculate similarities",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set article fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert articles": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert relations": {
      "main": [
        [
          {
            "node": "Split Related IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Related IDs": {
      "main": [
        [
          {
            "node": "Get related article details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set article fields": {
      "main": [
        [
          {
            "node": "OpenAI Get Embeddings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean & Prepare Text": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Get Embeddings": {
      "main": [
        [
          {
            "node": "Upsert articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate similarities": {
      "main": [
        [
          {
            "node": "Upsert article_relations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top 3 related articles": {
      "main": [
        [
          {
            "node": "Loop for source articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Get articles from shopify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop for source articles": {
      "main": [
        [],
        [
          {
            "node": "Get previous related_articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert article_relations": {
      "main": [
        [
          {
            "node": "Top 3 related articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get articles from shopify": {
      "main": [
        [
          {
            "node": "Clean & Prepare Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert Related in Article": {
      "main": [
        [
          {
            "node": "Update article with related",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get related article details": {
      "main": [
        [
          {
            "node": "Prepare HTML for related articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update article with related": {
      "main": [
        [
          {
            "node": "Loop for source articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get previous related_articles": {
      "main": [
        [
          {
            "node": "Check if article already has related",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare HTML for related articles": {
      "main": [
        [
          {
            "node": "Insert Related in Article",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if article already has related": {
      "main": [
        [
          {
            "node": "Check if related articles are the same",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Upsert relations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No need to change the related section": {
      "main": [
        [
          {
            "node": "Loop for source articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if related articles are the same": {
      "main": [
        [
          {
            "node": "No need to change the related section",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Upsert relations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

高级 - 内容创作, AI 摘要总结

需要付费吗?

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

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

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

作者
Geoffroy

Geoffroy

@jojoq42

Just a simple guy discovering the power of AI

外部链接
在 n8n.io 查看

分享此工作流