{ "kind": "open-flow-workflow", "version": 1, "name": "Social Content Review", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_574014589c8c879e": { "name": "Social content brief", "kind": "start", "inputDefs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "topic" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "brand_voice" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "target_audience" } ] }, "n_a4303192dba4cd31": { "inputs": { "topic": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "topic" } ] }, "brand_voice": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "brand_voice" } ] }, "target_audience": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "target_audience" } ] } }, "name": "Generate platform drafts", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "items": { "type": "object" }, "type": "array" }, "nullable": true, "handle": "messages", "value": null }, { "jsonSchema": { "items": { "type": "object" }, "minItems": 1, "type": "array" }, "nullable": false, "handle": "template", "value": [ { "role": "user", "content": "Generate social media content for the topic: \"{{topic}}\"\n\nBrand voice: {{brand_voice}}\nTarget audience: {{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}" } ] }, { "jsonSchema": { "type": "object" }, "nullable": false, "handle": "model", "value": { "model": "llama3:8b", "temperature": 0.7, "max_tokens": 2000 } }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "topic" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "brand_voice" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "target_audience" } ], "outputs": [ { "description": "Generated response.", "jsonSchema": { "type": "string" }, "nullable": false, "handle": "output" } ], "name": "Generate platform drafts", "executor": { "kind": "llm", "mode": "chat" } } }, "n_dd0c954c871e5bc2": { "inputs": { "text": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_a4303192dba4cd31", "output": "output" } ] }, "topic": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "topic" } ] }, "original": { "kind": "value", "value": null } }, "name": "Parse platform drafts", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "text" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "topic" }, { "jsonSchema": { "type": "object" }, "nullable": true, "handle": "original" } ], "outputs": [ { "jsonSchema": { "type": "object", "properties": { "twitter": { "type": "string" }, "linkedin": { "type": "string" }, "reddit_title": { "type": "string" }, "reddit_body": { "type": "string" }, "instagram_caption": { "type": "string" }, "topic": { "type": "string" }, "generated_at": { "type": "string" }, "reviewed": { "type": "boolean" } }, "additionalProperties": false, "required": [ "twitter", "linkedin", "reddit_title", "reddit_body", "instagram_caption", "topic", "generated_at" ] }, "nullable": false, "handle": "result" } ], "name": "Parse platform drafts", "moduleId": "n_2b8b04cfca4dc3bc", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_02b72b37a09e43e2": { "inputs": { "brand_voice": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "brand_voice" } ] }, "twitter": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result", "field": "twitter" } ] }, "linkedin": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result", "field": "linkedin" } ] }, "reddit_title": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result", "field": "reddit_title" } ] }, "reddit_body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result", "field": "reddit_body" } ] }, "instagram_caption": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result", "field": "instagram_caption" } ] } }, "name": "Review platform drafts", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "items": { "type": "object" }, "type": "array" }, "nullable": true, "handle": "messages", "value": null }, { "jsonSchema": { "items": { "type": "object" }, "minItems": 1, "type": "array" }, "nullable": false, "handle": "template", "value": [ { "role": "user", "content": "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: {{brand_voice}}\nContent:\nTwitter: {{twitter}}\nLinkedIn: {{linkedin}}\nReddit: {{reddit_title}} — {{reddit_body}}\nInstagram: {{instagram_caption}}\n\nIf any issues found, return corrected versions as JSON (same structure). If all good, return the same content. Return ONLY JSON." } ] }, { "jsonSchema": { "type": "object" }, "nullable": false, "handle": "model", "value": { "model": "llama3:8b", "temperature": 0.2, "max_tokens": 2000 } }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "brand_voice" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "twitter" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "linkedin" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "reddit_title" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "reddit_body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "instagram_caption" } ], "outputs": [ { "description": "Generated response.", "jsonSchema": { "type": "string" }, "nullable": false, "handle": "output" } ], "name": "Review platform drafts", "executor": { "kind": "llm", "mode": "chat" } } }, "n_bc0bb8878cb314d1": { "inputs": { "text": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_02b72b37a09e43e2", "output": "output" } ] }, "topic": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_574014589c8c879e", "output": "topic" } ] }, "original": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd0c954c871e5bc2", "output": "result" } ] } }, "name": "Choose reviewed content", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "text" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "topic" }, { "jsonSchema": { "type": "object", "properties": { "twitter": { "type": "string" }, "linkedin": { "type": "string" }, "reddit_title": { "type": "string" }, "reddit_body": { "type": "string" }, "instagram_caption": { "type": "string" }, "topic": { "type": "string" }, "generated_at": { "type": "string" }, "reviewed": { "type": "boolean" } }, "additionalProperties": false, "required": [ "twitter", "linkedin", "reddit_title", "reddit_body", "instagram_caption", "topic", "generated_at" ] }, "nullable": false, "handle": "original" } ], "outputs": [ { "jsonSchema": { "type": "object", "properties": { "twitter": { "type": "string" }, "linkedin": { "type": "string" }, "reddit_title": { "type": "string" }, "reddit_body": { "type": "string" }, "instagram_caption": { "type": "string" }, "topic": { "type": "string" }, "generated_at": { "type": "string" }, "reviewed": { "type": "boolean" } }, "additionalProperties": false, "required": [ "twitter", "linkedin", "reddit_title", "reddit_body", "instagram_caption", "topic", "generated_at" ] }, "nullable": false, "handle": "result" } ], "name": "Choose reviewed content", "moduleId": "n_62a71ee62580e027", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_2d27b15acc8f582c": { "name": "Social content set", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "object", "properties": { "twitter": { "type": "string" }, "linkedin": { "type": "string" }, "reddit_title": { "type": "string" }, "reddit_body": { "type": "string" }, "instagram_caption": { "type": "string" }, "topic": { "type": "string" }, "generated_at": { "type": "string" }, "reviewed": { "type": "boolean" } }, "additionalProperties": false, "required": [ "twitter", "linkedin", "reddit_title", "reddit_body", "instagram_caption", "topic", "generated_at" ] }, "nullable": false, "handle": "content" } ], "outputMappings": { "content": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_bc0bb8878cb314d1", "output": "result" } ] } } } }, "edges": [ { "source": "n_574014589c8c879e", "target": "n_a4303192dba4cd31" }, { "source": "n_a4303192dba4cd31", "target": "n_dd0c954c871e5bc2" }, { "source": "n_dd0c954c871e5bc2", "target": "n_02b72b37a09e43e2" }, { "source": "n_02b72b37a09e43e2", "target": "n_bc0bb8878cb314d1" }, { "source": "n_bc0bb8878cb314d1", "target": "n_2d27b15acc8f582c" } ] } }, "modules": { "n_2b8b04cfca4dc3bc": { "name": "Parse platform drafts", "imports": [], "source": "export default 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" }, "n_62a71ee62580e027": { "name": "Choose reviewed content", "imports": [], "source": "export default 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" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }