{
  "id": "Automated_Content_Creator_Publisher",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automated Content Creator & Publisher",
  "tags": [
    "AI",
    "Content Generation",
    "Marketing",
    "SEO",
    "Publishing",
    "Telegram",
    "Google Sheets"
  ],
  "nodes": [
    {
      "id": "",
      "name": "Ollama: Article Writer Model",
      "type": "@n8n/n8n-nodes-langchain.lmOllama",
      "position": [
        -2660,
        -220
      ],
      "parameters": {
        "model": "llama3:latest",
        "options": {}
      },
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "12a28d97-2679-4bc5-a8a0-65ec7ef76398",
      "name": "HTTP Request: Post to Website",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -960,
        -220
      ],
      "httpMethod": "POST",
      "parameters": {
        "url": "={{ $connections.websiteApi.url }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "user_id",
              "value": "={{ $('Function: Prepare Post Data').item.json.user_id }}"
            },
            {
              "name": "username",
              "value": "={{ $('Function: Prepare Post Data').item.json.username }}"
            },
            {
              "name": "postTitle",
              "value": "={{ $('Function: Prepare Post Data').item.json.postTitle }}"
            },
            {
              "name": "postContent",
              "value": "={{ $('LLM: Article Writer').item.json.text }}\n\n{{ $('Function: Parse LLM Output').item.json.tags2[0] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[1] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[2] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[3] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[4] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[5] }}\n{{ $('Function: Parse LLM Output').item.json.tags2[6] }}\n\n{{ $('Function: Parse LLM Output').item.json.username }}\n"
            },
            {
              "name": "bgColor",
              "value": "={{ $('Function: Prepare Post Data').item.json.bg_color }}"
            },
            {
              "name": "LinkAff",
              "value": "={{ $('Function: Prepare Post Data').item.LinkAff }}"
            },
            {
              "name": "postType",
              "value": "={{ $('Function: Prepare Post Data').item.postType }}"
            },
            {
              "name": "embeddedContent",
              "value": "={{ $('Function: Prepare Post Data').item.embeddedContent }}"
            },
            {
              "name": "tags",
              "value": "={{ $('Function: Parse LLM Output').item.json.tags1.join(',') }}"
            },
            {
              "name": "post-thumbnail",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "generated-image.png"
            },
            {
              "name": "aff_image",
              "value": "="
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Api-Key",
              "value": "={{ $connections.websiteApi.apiKey }}"
            }
          ]
        }
      },
      "typeVersion": 3,
      "bodyContentType": "multipart-form-data"
    },
    {
      "id": "3c460292-1341-48e8-83cb-784a7a5f2d54",
      "name": "Telegram: Send Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -800,
        -220
      ],
      "parameters": {
        "text": "New Article Posted: {{ $('Function: Parse LLM Output').item.json.postTitle }}\n\nSummary:\n{{ $('Function: Parse LLM Output').item.json.postContent }}\n\nTags: {{ $('Function: Parse LLM Output').item.json.tags2.join(', ') }}",
        "chatId": "={{ $connections.telegramApi.chatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b21535d9-db05-4d51-b0d5-344ca70ea2b5",
      "name": "Google Gemini: Generate Photo",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1480,
        -220
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-preview-image-generation:generateContent?key=YOUR_TOKEN_HERE $connections.googleGeminiApi.apiKey }}",
        "options": {},
        "requestMethod": "POST",
        "jsonParameters": true,
        "bodyParametersJson": "={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"text\": \"masterpiece, 8k, ultra-detailed, photorealistic cinematic shot of: {{ $('Function: Parse LLM Output').item.json.imagePrompt }} thai-face. professional photography, sharp focus, high dynamic range (HDR), intricate details, dramatic natural lighting, aspect ratio 16:9\"\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"responseModalities\": [\n      \"TEXT\",\n      \"IMAGE\"\n    ]\n  }\n}",
        "headerParametersJson": "{\"Content-Type\":\"application/json\"}"
      },
      "typeVersion": 1
    },
    {
      "id": "12be1078-6a82-46e3-a35f-c497dc7789c7",
      "name": "Convert AI Image to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        -1120,
        -220
      ],
      "parameters": {
        "options": {},
        "operation": "toBinary",
        "sourceProperty": "candidates.0.content.parts.1.inlineData.data",
        "binaryPropertyName": "generated-image.png"
      },
      "typeVersion": 1.1
    },
    {
      "id": "",
      "name": "Ollama: SEO & Marketing Model",
      "type": "@n8n/n8n-nodes-langchain.lmOllama",
      "position": [
        -2360,
        80
      ],
      "parameters": {
        "model": "llama3:latest",
        "options": {}
      },
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "47c8db8e-d6fb-4caa-8332-43ac033c9fef",
      "name": "LLM: Article Writer",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -2680,
        -120
      ],
      "parameters": {
        "text": "=### INSTRUCTION ###\nYou are a professional Thai editor and adaptive long-form article writer. Your primary task is to analyze the user's input and decide on the best format for the article (either a list-based article or a standard analytical article), then write a high-quality, flawless article in Thai.\n\n### STRICT RULES ###\n1. Your ENTIRE response MUST BE ONLY the article content.\n2. NO titles, NO labels, NO conversation, NO explanations.\n3. FLAWLESS THAI: Pay meticulous attention to spelling and grammar. NO typos or malformed words.\n4. PURE LANGUAGE: Use only natural Thai. DO NOT mix in words from other languages unless they are common loanwords.\n\n### USER INPUT ###\nSUMMARY: {{ $('Google Sheets: Read News').item.json.description }}\n\n\n\n### TASK ###\n1.  **Analyze the TOPIC**: First, determine if the TOPIC suggests a list of items, steps, or methods (e.g., contains numbers like \"5 \u0e27\u0e34\u0e18\u0e35...\", \"7 \u0e40\u0e17\u0e04\u0e19\u0e34\u0e04...\", \"10 \u0e2a\u0e34\u0e48\u0e07\u0e17\u0e35\u0e48...\").\n\n2.  **Choose the Format and Write**:\n    * **IF the TOPIC is a list**: Write the article in a \"listicle\" format. Start with an introduction, then present each numbered item (e.g., \"1. [\u0e0a\u0e37\u0e48\u0e2d\u0e27\u0e34\u0e18\u0e35\u0e41\u0e23\u0e01]\", \"2. [\u0e0a\u0e37\u0e48\u0e2d\u0e27\u0e34\u0e18\u0e35\u0e17\u0e35\u0e48\u0e2a\u0e2d\u0e07]\", etc.) with a detailed explanation for each point. Ensure the total word count is at least 800 words. Conclude with a summary.\n    * **IF the TOPIC is NOT a list**: Write a standard detailed, long-form analytical article. The article MUST BE AT LEAST 800 WORDS and structured with an introduction, at least 5-7 main body paragraphs, and a concluding paragraph.\n\n3.  **Final Touches**: The concluding paragraph for either format should provide a powerful and memorable final thought. After writing, proofread the entire article to ensure it adheres to all rules and is free of errors.",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "b2acb79c-ce1f-4a78-b6ec-b9ec644ca362",
      "name": "LLM: SEO & Marketing",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -2320,
        -120
      ],
      "parameters": {
        "text": "=INSTRUCTION\nYou are a structured data generation AI. Your task is to follow a sequence of steps to create content components based on the user's input.\n\nSTRICT RULES\n\nYour ENTIRE response MUST be ONLY the text between the ---START_DATA--- and ---END_DATA--- markers.\n\nYou MUST generate ALL fields listed in the output structure. DO NOT omit any field.\n\nThe IMAGE_PROMPT field is MANDATORY.\n\nFor TAGS2, you MUST generate exactly 3 pairs of corresponding Thai and English tags. Each pair must represent the same concept and be DIRECTLY RELEVANT to the USER INPUT.\n\nDO NOT use placeholders such as \u2018\u0e44\u0e17\u0e22\u0e04\u0e33\u2019, \u2018ThaiWord\u2019 or any generic filler. Each Thai-English pair must be meaningful, unique, and reflect a core concept from the USER INPUT. If unable to do this exactly, leave TAGS2 blank.\n\nNO conversation, NO explanations, NO apologies.\n\nAll LABELS must be uppercase and end with a colon (e.g., TITLE:).\n\nThe TITLE must be strictly no longer than  words. If you cannot create a TITLE within this limit, leave it blank.\n\nUSER INPUT\nINPUT_DESCRIPTION: {{ $json.text }}\n\nTHINKING_PROCESS (Internal thought process for you, do not output this section):\nStep 1: Deeply analyze the core theme of the USER INPUT.\nStep 2: Generate the Thai TITLE. The TITLE must be attractive, concise, and strictly no more than 8 words. If unable, leave TITLE blank.\nStep 3: Write the Thai EXCERPT.\nStep 4: Create 8 relevant TAGS in Thai, based on the input.\nStep 5: Identify 8 core concepts from the USER INPUT. Create 8 Thai-English tag pairs (TAGS2) strictly relevant to the main topics. Do not use placeholders or repeat.\nStep 6: Generate a detailed English IMAGE_PROMPT reflecting the main theme.\n\nREQUIRED OUTPUT STRUCTURE\n---START_DATA---\nTITLE: [\u0e2b\u0e31\u0e27\u0e02\u0e49\u0e2d\u0e02\u0e48\u0e32\u0e27\u0e2b\u0e25\u0e31\u0e01 (H1) \u0e40\u0e1b\u0e47\u0e19\u0e20\u0e32\u0e29\u0e32\u0e44\u0e17\u0e22 \u0e14\u0e36\u0e07\u0e14\u0e39\u0e14\u0e43\u0e08 \u0e01\u0e23\u0e30\u0e0a\u0e31\u0e1a \u0e44\u0e21\u0e48\u0e40\u0e01\u0e34\u0e19 8 \u0e04\u0e33]\n\nEXCERPT: [\u0e22\u0e48\u0e2d\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e01\u0e23\u0e34\u0e48\u0e19\u0e19\u0e33\u0e1b\u0e23\u0e30\u0e21\u0e32\u0e13 150 \u0e04\u0e33]\n\nTAGS: [8 \u0e41\u0e17\u0e47\u0e01\u0e20\u0e32\u0e29\u0e32\u0e44\u0e17\u0e22 \u0e04\u0e31\u0e48\u0e19\u0e14\u0e49\u0e27\u0e22\u0e08\u0e38\u0e25\u0e20\u0e32\u0e04]\n\nTAGS2: [3 \u0e04\u0e39\u0e48\u0e41\u0e17\u0e47\u0e01 \u0e44\u0e17\u0e22-\u0e2d\u0e31\u0e07\u0e01\u0e24\u0e29 \u0e41\u0e1a\u0e1a #\u0e04\u0e33\u0e44\u0e17\u0e22, #EnglishWord \u0e41\u0e15\u0e48\u0e25\u0e30\u0e04\u0e39\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e2a\u0e37\u0e48\u0e2d\u0e2a\u0e32\u0e23\u0e40\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e40\u0e14\u0e35\u0e22\u0e27\u0e01\u0e31\u0e19\u0e42\u0e14\u0e22\u0e15\u0e23\u0e07]\n\nIMAGE_PROMPT: [\u0e20\u0e32\u0e29\u0e32\u0e2d\u0e31\u0e07\u0e01\u0e24\u0e29 1 \u0e22\u0e48\u0e2d\u0e2b\u0e19\u0e49\u0e32 \u0e41\u0e2a\u0e14\u0e07\u0e41\u0e19\u0e27\u0e04\u0e34\u0e14\u0e2b\u0e25\u0e31\u0e01]\n\n---END_DATA---",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "912fd524-acdd-47cf-92f2-cdc7a00bc77d",
      "name": "Function: Prepare Post Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -1860,
        -120
      ],
      "parameters": {
        "jsCode": "// This node prepares the final JSON payload for the website POST request.\n// It combines data from various upstream nodes.\n\nconst parsedLLMOutput = $('Function: Parse LLM Output').item.json;\nconst imageBinaryData = $('Merge Image Data').item.json.imageBinaryData;\nconst postContentFromWriter = $('LLM: Article Writer').item.json.text;\n\n// Default values for website post, can be configured via workflow parameters or credentials\nconst defaultUserId = '{{ $connections.websiteApi.userId }}'; \nconst defaultUsername = '{{ $connections.websiteApi.username }}';\nconst defaultBgColor = '#FFFFFF';\nconst defaultLinkAff = '';\nconst defaultPostType = 'General';\nconst defaultEmbeddedContent = '';\n\nconst outputItem = {\n    json: {\n        user_id: parsedLLMOutput.user_id || defaultUserId,\n        username: parsedLLMOutput.username || defaultUsername,\n        postTitle: parsedLLMOutput.postTitle,\n        postContent: postContentFromWriter,\n        bgColor: parsedLLMOutput.bg_color || defaultBgColor,\n        LinkAff: parsedLLMOutput.LinkAff || defaultLinkAff,\n        postType: parsedLLMOutput.postType || defaultPostType,\n        embeddedContent: parsedLLMOutput.embeddedContent || defaultEmbeddedContent,\n        tags1: parsedLLMOutput.tags1,\n        tags2: parsedLLMOutput.tags2,\n        imageBinaryData: imageBinaryData, // Pass binary data reference\n        description: postContentFromWriter // Use full article as description for Telegram\n    },\n    // Ensure binary data is also passed through for the HTTP Request node\n    binary: {\n        'generated-image.png': imageBinaryData\n    }\n};\n\nreturn [outputItem];"
      },
      "typeVersion": 2
    },
    {
      "id": "760df977-da46-4d10-9f19-d2cb2099e5b8",
      "name": "If: Is Real Image?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1700,
        -120
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "16513b65-0fae-4aa6-a30d-5c2bc5b2a0ba",
              "operator": {
                "type": "string",
                "operation": "equal"
              },
              "leftValue": "={{ $('LLM: Image Type Analyzer').item.json.type }}",
              "rightValue": "\u0e20\u0e32\u0e1e\u0e08\u0e23\u0e34\u0e07"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3c916018-d0ad-4111-814a-be6c1cb84537",
      "name": "Convert AI Risoprint Image to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        -1120,
        -40
      ],
      "parameters": {
        "options": {},
        "operation": "toBinary",
        "sourceProperty": "candidates[0].content.parts[1].inlineData.data",
        "binaryPropertyName": "generated-image.png"
      },
      "typeVersion": 1.1
    },
    {
      "id": "a021bbfd-870d-41c6-b481-729643acb196",
      "name": "Function: Parse LLM Output",
      "type": "n8n-nodes-base.code",
      "position": [
        -2020,
        -120
      ],
      "parameters": {
        "jsCode": "// This node parses the structured text output from the LLM.\n// It extracts TITLE, EXCERPT, TAGS, TAGS2, and IMAGE_PROMPT.\n\nconst rawLLMText = $json.text || \"\";\n\n// --- 1. Extract desired data using Markers ---\nconst startMarker = \"---START_DATA---\";\nconst endMarker = \"---END_DATA---\";\nlet articleDataText = rawLLMText;\n\nconst startIndex = rawLLMText.indexOf(startMarker);\nconst endIndex = rawLLMText.indexOf(endMarker, startIndex);\n\nif (startIndex !== -1 && endIndex !== -1) {\n    articleDataText = rawLLMText.substring(startIndex + startMarker.length, endIndex);\n}\n\nfunction sanitizeValue(value) {\n    if (typeof value !== 'string') return \"\";\n    return value.trim().replace(/^\"|\"$|^|$/g, '').trim();\n}\n\n// --- 2. Extract each Field ---\nconst fields = {\n    TITLE: \"\",\n    EXCERPT: \"\",\n    TAGS: \"\",\n    TAGS2: \"\",\n    IMAGE_PROMPT: \"\"\n};\nconst regex = /(?:^|\\n)\\**\\s*(TITLE|EXCERPT|TAGS|TAGS2|IMAGE_PROMPT)\\s*\\**:\\s*([\\s\\S]*?)(?=(?:\\n)\\**\\s*[A-Z_]+:|$)/gi;\n\nlet match;\nwhile ((match = regex.exec(articleDataText)) !== null) {\n    const fieldName = match[1].trim().toUpperCase();\n    const fieldValue = sanitizeValue(match[2]);\n    if (fields.hasOwnProperty(fieldName)) {\n        fields[fieldName] = fieldValue;\n    }\n}\n\n// --- 3. Post-processing data correction (preventing data bleed) ---\nconst tagsMarker = 'TAGS:';\nif (fields.EXCERPT && fields.EXCERPT.includes(tagsMarker)) {\n    const parts = fields.EXCERPT.split(new RegExp(`\\\\s*${tagsMarker}`));\n    fields.EXCERPT = parts[0];\n    if (!fields.TAGS && parts.length > 1) {\n        fields.TAGS = parts[1];\n    }\n}\n\nconst tags2Marker = 'TAGS2:';\nif (fields.TAGS && fields.TAGS.includes(tags2Marker)) {\n    const parts = fields.TAGS.split(new RegExp(`\\\\s*${tags2Marker}`));\n    fields.TAGS = parts[0];\n    if (!fields.TAGS2 && parts.length > 1) {\n        fields.TAGS2 = parts[1];\n    }\n}\n\n// --- 4. Cleanse TAGS and TAGS2 separately ---\nconst cleanedTags1 = fields.TAGS.split(',')\n    .map(tag => tag.trim())\n    .filter(tag => tag.length > 0)\n    .map(tag => tag.replace(/^#/, '')); // Removes leading '#' for tags1\n\nconst cleanedTags2 = fields.TAGS2.split(',')\n    .map(tag => tag.trim())\n    .filter(tag => tag.length > 0)\n    .map(tag => tag.startsWith('#') ? tag : `#${tag}`); // Ensures each tag in tags2 starts with '#'\n\n// --- 5. Create JSON Object for export ---\nconst jsonOutput = {\n    \"postTitle\": fields.TITLE,\n    \"postContent\": fields.EXCERPT,\n    \"tags1\": cleanedTags1,\n    \"tags2\": cleanedTags2,\n    \"imagePrompt\": fields.IMAGE_PROMPT\n};\n\nreturn [jsonOutput];"
      },
      "typeVersion": 2
    },
    {
      "id": "f6ff9656-7342-492a-87d0-d290c76047a4",
      "name": "If: Is AI Image?",
      "type": "n8n-nodes-base.if",
      "position": [
        -3260,
        -320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "d206cefb-3142-4bc0-b3d7-0669c94b06c9",
              "operator": {
                "type": "string",
                "operation": "equal"
              },
              "leftValue": "={{ $('LLM: Image Type Analyzer').item.json.type }}",
              "rightValue": "\u0e20\u0e32\u0e1e AI"
            }
          ]
        },
        "looseTypeValidation": "="
      },
      "typeVersion": 2.2
    },
    {
      "id": "308fc7dc-97fc-4a79-8340-f5ced91c015b",
      "name": "Function: Image Type Analyzer",
      "type": "n8n-nodes-base.code",
      "position": [
        -3220,
        -160
      ],
      "parameters": {
        "jsCode": "// This node analyzes the news content to determine the appropriate image type (Real or AI) and extracts relevant keywords for real images.\n\nconst responseText = $json.text || \"\";\n\nconst outputItem = {\n    json: {\n        type: \"\",\n        keywords: []\n    }\n};\n\nif (!responseText) {\n    console.warn(\"Input text is undefined or null. Returning default empty values.\");\n    return [outputItem];\n}\n\nconst lines = responseText.split('\\n').map(line => line.trim()).filter(Boolean);\n\nlet foundType = \"\";\nlet foundKeywords = [];\n\nfor (let i = 0; i < lines.length; i++) {\n    const currentLine = lines[i];\n\n    if (currentLine.startsWith(\"\u0e20\u0e32\u0e1e\u0e08\u0e23\u0e34\u0e07\")) {\n        foundType = \"\u0e20\u0e32\u0e1e\u0e08\u0e23\u0e34\u0e07\";\n        if (i + 1 < lines.length) {\n            const nextLine = lines[i + 1];\n            if (!nextLine.startsWith(\"\u0e20\u0e32\u0e1e AI\") && !nextLine.toLowerCase().startsWith(\"keywords:\")) {\n                foundKeywords = nextLine.split(',')\n                                       .map(kw => kw.trim())\n                                       .filter(Boolean);\n                break;\n            }\n        }\n    } else if (currentLine.startsWith(\"\u0e20\u0e32\u0e1e AI\")) {\n        foundType = \"\u0e20\u0e32\u0e1e AI\";\n        break;\n    }\n\n    if (currentLine.toLowerCase().startsWith(\"keywords:\")) {\n        const keywordString = currentLine.substring(\"keywords:\".length);\n        foundKeywords = keywordString.split(',')\n                                    .map(kw => kw.trim())\n                                    .filter(Boolean);\n        if (foundType) {\n            break;\n        }\n    }\n}\n\noutputItem.json.type = foundType;\noutputItem.json.keywords = foundKeywords;\n\nreturn [outputItem];"
      },
      "typeVersion": 2
    },
    {
      "id": "9965d31f-85fc-450f-8918-de20504495bb",
      "name": "HTTP Request: Fetch Real Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -3220,
        -20
      ],
      "parameters": {
        "url": "={{ $connections.localImageServer.url }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"keyword\": \"{{ $('Function: Image Type Analyzer').item.json.keywords }}\",\n  \"status\": \"started\"\n}\n",
        "sendBody": true,
        "sendQuery": true,
        "specifyBody": "json",
        "queryParameters": {
          "parameters": [
            {
              "name": "Key",
              "value": "Content-Type"
            },
            {
              "name": "Value",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "29ce8614-edd0-4496-9deb-493e2ad9d430",
      "name": "Read/Write Files from Disk (Local)",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        -3220,
        140
      ],
      "parameters": {
        "options": {},
        "fileSelector": "/pic/**/*.{png,jpg,jpeg,gif,bmp,tiff,webp}"
      },
      "typeVersion": 1
    },
    {
      "id": "d85f8b4c-8170-41d9-8d7b-329e41c249b4",
      "name": "Extract Image Binary Data",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -3220,
        300
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery"
      },
      "typeVersion": 1
    },
    {
      "id": "bb69c31c-837b-4714-b0cb-10d47a86796f",
      "name": "Merge Image Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        -2940,
        -120
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "1c358faf-7240-4b85-b9c1-e047668aae7a",
      "name": "Convert Extracted Image to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        -3220,
        420
      ],
      "parameters": {
        "options": {},
        "operation": "toBinary",
        "sourceProperty": "data",
        "binaryPropertyName": "generated-image.png"
      },
      "typeVersion": 1.1
    },
    {
      "id": "fefba463-aa01-48e3-aeb7-40423b1e9ed1",
      "name": "Function: Attach Image Binary",
      "type": "n8n-nodes-base.code",
      "position": [
        -2920,
        320
      ],
      "parameters": {
        "jsCode": "for (const item of items) {\n  if (item.binary && item.binary['generated-image.png']) {\n    item.json.imageBinaryData = item.binary['generated-image.png'];\n  }\n}\nreturn items;"
      },
      "typeVersion": 2
    },
    {
      "id": "",
      "name": "Google Sheets: Read News",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        -2300,
        -500
      ],
      "parameters": {
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/ENTER_YOUR_GOOGLE_SHEET_ID_HERE/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "ENTER_YOUR_GOOGLE_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/ENTER_YOUR_GOOGLE_SHEET_ID_HERE/edit",
          "cachedResultName": "Your News Data Sheet"
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9773638f-ae9b-4693-b606-226e16af3f40",
      "name": "LLM: Image Type Analyzer",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -2140,
        -500
      ],
      "parameters": {
        "text": "=# Please respond ONLY in the specified format. NO additional text, NO explanations, NO conversations, NO introductions or conclusions, or any other extraneous text are strictly allowed. **The output must be clean and unadulterated.**\n\n# Decision Criteria:\n- Before making a decision and generating the output, absolutely filter out and ignore any text that is not core news content or metadata (e.g., \"View icon\", \"Share\", \"Date\", \"Main Guide:\") that may be mixed in the Input by ignoring these irrelevant texts from the output.\n- If the news refers to identifiable individuals (whether famous or not), specific place names (e.g., provinces, districts, important buildings), product names, products, airplanes, cars, or anything else with a specific name that can be photographed or found as a real image: The output must be 2 lines as follows:\n  Line 1: \u0e20\u0e32\u0e1e\u0e08\u0e23\u0e34\u0e07\n  Line 2: [1 Main Keyword for image search] (This keyword must be the most important, concise, and effective word for searching images. It must be only 1 Keyword. NO other text should be mixed on this line.)\n- If the news is about concepts, economics, finance, technology in general, abstract topics, or general matters for which a specific image cannot be clearly identified, including cases where there are words that mean \u201csmall\u201d, \u201cmodel\u201d, \u201cmockup\u201d, \u201cconcept\u201d: The output must be 1 line as follows:\n  Line 1: \u0e20\u0e32\u0e1e AI\n- If the information is insufficient for a decision: The output must be 1 line as follows:\n  Line 1: \u0e20\u0e32\u0e1e AI\n\n# Evaluate this news content:\nNews Content:\n{{ $json.description }}\n\n# Result:",
        "batching": {},
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "",
      "name": "Ollama: Image Type Model",
      "type": "@n8n/n8n-nodes-langchain.lmOllama",
      "position": [
        -2140,
        -620
      ],
      "parameters": {
        "model": "llama3:latest",
        "options": {}
      },
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "366744f5-7868-43da-9196-9930992734d8",
      "name": "Google Gemini: Generate Risoprint Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1480,
        -40
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-preview-image-generation:generateContent?key=YOUR_TOKEN_HERE $connections.googleGeminiApi.apiKey }}",
        "options": {},
        "requestMethod": "POST",
        "jsonParameters": true,
        "bodyParametersJson": "={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"inlineData\": {\n            \"mimeType\": \"image/png\",\n            \"data\": \"{{ $('Function: Attach Image Binary').item.json.imageBinaryData.data }}\"\n          }\n        },\n        {\n          \"text\": \"100% cutout risoprint photo effect mockup, masterpiece, risograph print style, retro risograph texture, stencil cutout look, vibrant duotone color (red and blue tones), high contrast, grainy paper texture, sharp vector edges, artistic ink bleed, photorealistic base: {{ $('Function: Parse LLM Output').item.json.imagePrompt }} thai-face. aspect ratio 16:9\"\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"responseModalities\": [\n      \"TEXT\",\n      \"IMAGE\"\n    ]\n  }\n}\n",
        "headerParametersJson": "{\"Content-Type\":\"application/json\"}"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5e3ceac4-5c15-4027-9c8b-80626975a216",
  "connections": {
    "If: Is AI Image?": {
      "main": [
        [
          {
            "node": "Merge Image Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Function: Image Type Analyzer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Image Data": {
      "main": [
        [
          {
            "node": "LLM: Article Writer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If: Is Real Image?": {
      "main": [
        [
          {
            "node": "Google Gemini: Generate Photo",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Gemini: Generate Risoprint Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Article Writer": {
      "main": [
        [
          {
            "node": "LLM: SEO & Marketing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM: SEO & Marketing": {
      "main": [
        [
          {
            "node": "Function: Parse LLM Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert AI Image to File": {
      "main": [
        [
          {
            "node": "HTTP Request: Post to Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets: Read News": {
      "main": [
        [
          {
            "node": "LLM: Image Type Analyzer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Image Type Analyzer": {
      "main": [
        [
          {
            "node": "If: Is AI Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama: Image Type Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: Image Type Analyzer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Image Binary Data": {
      "main": [
        [
          {
            "node": "Convert Extracted Image to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Parse LLM Output": {
      "main": [
        [
          {
            "node": "Function: Prepare Post Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Prepare Post Data": {
      "main": [
        [
          {
            "node": "If: Is Real Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama: Article Writer Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: Article Writer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Function: Attach Image Binary": {
      "main": [
        [
          {
            "node": "Merge Image Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Function: Image Type Analyzer": {
      "main": [
        [
          {
            "node": "HTTP Request: Fetch Real Image",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Image Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini: Generate Photo": {
      "main": [
        [
          {
            "node": "Convert AI Image to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request: Post to Website": {
      "main": [
        [
          {
            "node": "Telegram: Send Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama: SEO & Marketing Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: SEO & Marketing",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request: Fetch Real Image": {
      "main": [
        [
          {
            "node": "Read/Write Files from Disk (Local)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert Extracted Image to File": {
      "main": [
        [
          {
            "node": "Function: Attach Image Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert AI Risoprint Image to File": {
      "main": [
        [
          {
            "node": "HTTP Request: Post to Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read/Write Files from Disk (Local)": {
      "main": [
        [
          {
            "node": "Extract Image Binary Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}