{ "name": "AI Social Media Content Generator (Ollama)", "nodes": [ { "parameters": {}, "id": "trigger", "name": "Manual Trigger", "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 240, 300 ] }, { "parameters": { "assignments": { "assignments": [ { "id": "topic", "name": "topic", "value": "Benefits of self-hosting AI models", "type": "string" }, { "id": "brand_voice", "name": "brand_voice", "value": "Tech-savvy, slightly irreverent, helpful. We love open source and privacy.", "type": "string" }, { "id": "target_audience", "name": "target_audience", "value": "developers, sysadmins, tech enthusiasts", "type": "string" } ] } }, "id": "config", "name": "Content Parameters", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 460, 300 ] }, { "parameters": { "promptType": "define", "text": "=Generate social media content for the topic: \"{{ $json.topic }}\"\n\nBrand voice: {{ $json.brand_voice }}\nTarget audience: {{ $json.target_audience }}\n\nReturn ONLY valid JSON with this structure:\n{\n \"twitter\": \"Tweet (max 280 chars, include 2-3 relevant hashtags)\",\n \"linkedin\": \"LinkedIn post (3-4 paragraphs, professional tone, include hashtags)\",\n \"reddit_title\": \"Reddit post title (engaging, not clickbait)\",\n \"reddit_body\": \"Reddit post body (informative, genuine value, no hard sell)\",\n \"instagram_caption\": \"Instagram caption (engaging, with emoji, 5-10 hashtags at end)\"\n}", "batching": { "batchSize": 1 } }, "id": "generate", "name": "Generate All Platform Content (Ollama)", "type": "@n8n/n8n-nodes-langchain.chainLlm", "typeVersion": 1.7, "position": [ 680, 300 ] }, { "parameters": { "mode": "runOnceForAllItems", "jsCode": "const parse = function parseSocial({ text, topic, original = null }) {\n const fields = ['twitter', 'linkedin', 'reddit_title', 'reddit_body', 'instagram_caption'];\n let parsed;\n try {\n if (typeof text !== 'string') throw new Error('Model output must be text.');\n const match = text.match(/\\{[\\s\\S]*\\}/);\n if (!match) throw new Error('No JSON object found.');\n parsed = JSON.parse(match[0]);\n if (!parsed || Array.isArray(parsed) || fields.some((field) => typeof parsed[field] !== 'string' || !parsed[field].trim())) throw new Error('Model output must contain all five nonempty social content fields.');\n } catch (error) {\n if (original) return { result: { ...original, reviewed: false } };\n throw new Error('Failed to parse AI response as complete content JSON: ' + error.message);\n }\n const content = Object.fromEntries(fields.map((field) => [field, parsed[field]]));\n return { result: original ? { ...original, ...content, reviewed: true } : { ...content, topic, generated_at: new Date().toISOString() } };\n}\n\nreturn [{json: parse({text: $input.first().json.text, topic: $('Content Parameters').first().json.topic}).result}];\n" }, "id": "parse", "name": "Parse Content JSON", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 900, 300 ] }, { "parameters": { "promptType": "define", "text": "=Review this social media content for quality. Check for:\n1. Grammar and spelling errors\n2. Tone consistency with brand voice\n3. Platform-appropriate formatting\n4. Hashtag relevance\n\nBrand voice: {{ $('Content Parameters').first().json.brand_voice }}\nContent:\nTwitter: {{ $json.twitter }}\nLinkedIn: {{ $json.linkedin }}\nReddit: {{ $json.reddit_title }} — {{ $json.reddit_body }}\nInstagram: {{ $json.instagram_caption }}\n\nIf any issues found, return corrected versions as JSON (same structure). If all good, return the same content. Return ONLY JSON.", "batching": { "batchSize": 1 } }, "id": "review", "name": "Review & Polish (Ollama)", "type": "@n8n/n8n-nodes-langchain.chainLlm", "typeVersion": 1.7, "position": [ 1120, 300 ] }, { "parameters": { "mode": "runOnceForAllItems", "jsCode": "const parse = function parseSocial({ text, topic, original = null }) {\n const fields = ['twitter', 'linkedin', 'reddit_title', 'reddit_body', 'instagram_caption'];\n let parsed;\n try {\n if (typeof text !== 'string') throw new Error('Model output must be text.');\n const match = text.match(/\\{[\\s\\S]*\\}/);\n if (!match) throw new Error('No JSON object found.');\n parsed = JSON.parse(match[0]);\n if (!parsed || Array.isArray(parsed) || fields.some((field) => typeof parsed[field] !== 'string' || !parsed[field].trim())) throw new Error('Model output must contain all five nonempty social content fields.');\n } catch (error) {\n if (original) return { result: { ...original, reviewed: false } };\n throw new Error('Failed to parse AI response as complete content JSON: ' + error.message);\n }\n const content = Object.fromEntries(fields.map((field) => [field, parsed[field]]));\n return { result: original ? { ...original, ...content, reviewed: true } : { ...content, topic, generated_at: new Date().toISOString() } };\n}\n\nreturn [{json: parse({text: $input.first().json.text, topic: $('Content Parameters').first().json.topic, original: $('Parse Content JSON').first().json}).result}];\n" }, "id": "final-parse", "name": "Final Content Output", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1340, 300 ] }, { "id": "generate-ollama-model", "name": "Generate All Platform Content (Ollama) model", "type": "@n8n/n8n-nodes-langchain.lmOllama", "typeVersion": 1, "position": [ 680, 500 ], "parameters": { "model": "llama3:8b", "options": { "temperature": 0.7, "numPredict": 2000 } } }, { "id": "review-ollama-model", "name": "Review & Polish (Ollama) model", "type": "@n8n/n8n-nodes-langchain.lmOllama", "typeVersion": 1, "position": [ 1120, 500 ], "parameters": { "model": "llama3:8b", "options": { "temperature": 0.2, "numPredict": 2000 } } } ], "connections": { "Manual Trigger": { "main": [ [ { "node": "Content Parameters", "type": "main", "index": 0 } ] ] }, "Content Parameters": { "main": [ [ { "node": "Generate All Platform Content (Ollama)", "type": "main", "index": 0 } ] ] }, "Generate All Platform Content (Ollama)": { "main": [ [ { "node": "Parse Content JSON", "type": "main", "index": 0 } ] ] }, "Parse Content JSON": { "main": [ [ { "node": "Review & Polish (Ollama)", "type": "main", "index": 0 } ] ] }, "Review & Polish (Ollama)": { "main": [ [ { "node": "Final Content Output", "type": "main", "index": 0 } ] ] }, "Generate All Platform Content (Ollama) model": { "ai_languageModel": [ [ { "node": "Generate All Platform Content (Ollama)", "type": "ai_languageModel", "index": 0 } ] ] }, "Review & Polish (Ollama) model": { "ai_languageModel": [ [ { "node": "Review & Polish (Ollama)", "type": "ai_languageModel", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" }, "tags": [ { "name": "AI" }, { "name": "Ollama" }, { "name": "Social Media" }, { "name": "Content" } ], "active": false, "pinData": {} }