Files
portfolio/docs/ai-image-generation/n8n-workflow-ai-image-generator.json
2026-01-07 14:30:00 +01:00

341 lines
13 KiB
JSON

{
"name": "AI Project Image Generator",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "ai-image-generation",
"responseMode": "responseNode",
"options": {
"authType": "headerAuth"
}
},
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [250, 300],
"webhookId": "ai-image-gen-webhook",
"credentials": {
"httpHeaderAuth": {
"id": "1",
"name": "Header Auth"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, title, description, tags, category, content, tech_stack FROM projects WHERE id = $1 LIMIT 1",
"additionalFields": {
"queryParameters": "={{ $json.body.projectId }}"
}
},
"id": "get-project-data",
"name": "Get Project Data",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [450, 300],
"credentials": {
"postgres": {
"id": "2",
"name": "PostgreSQL"
}
}
},
{
"parameters": {
"jsCode": "// Extract project data\nconst project = $input.first().json;\n\n// Style keywords by category\nconst styleKeywords = {\n 'web': 'modern web interface, clean UI dashboard, gradient backgrounds, glass morphism effect, floating panels',\n 'mobile': 'mobile app mockup, sleek smartphone design, app icons, modern UI elements, notification badges',\n 'devops': 'server infrastructure, cloud network diagram, container orchestration, CI/CD pipeline visualization',\n 'backend': 'API architecture, database systems, microservices diagram, server endpoints, data flow',\n 'game': 'game environment scene, 3D rendered world, gaming interface, player HUD elements',\n 'ai': 'neural network visualization, AI chip design, machine learning data flow, futuristic technology',\n 'automation': 'workflow automation diagram, process flows, interconnected systems, automated pipeline',\n 'security': 'cybersecurity shields, encrypted data streams, security locks, firewall visualization',\n 'iot': 'Internet of Things devices, sensor networks, smart home technology, connected devices',\n 'blockchain': 'blockchain network, crypto technology, distributed ledger, decentralized nodes'\n};\n\nconst categoryStyle = styleKeywords[project.category?.toLowerCase()] || 'modern technology concept visualization';\n\n// Extract tech-specific keywords from tags and tech_stack\nconst techKeywords = [];\nif (project.tags) {\n const tags = Array.isArray(project.tags) ? project.tags : JSON.parse(project.tags || '[]');\n techKeywords.push(...tags.slice(0, 3));\n}\nif (project.tech_stack) {\n const stack = Array.isArray(project.tech_stack) ? project.tech_stack : JSON.parse(project.tech_stack || '[]');\n techKeywords.push(...stack.slice(0, 2));\n}\n\nconst techContext = techKeywords.length > 0 ? techKeywords.join(', ') + ' technology,' : '';\n\n// Build sophisticated prompt\nconst prompt = `\nProfessional tech project cover image, ${categoryStyle},\nrepresenting the concept of \"${project.title}\",\n${techContext}\nmodern minimalist design, vibrant gradient colors,\nhigh quality digital art, isometric perspective,\nclean composition, soft lighting,\ncolor palette: cyan, purple, pink, blue accents,\n4k resolution, trending on artstation,\nno text, no watermarks, no people, no logos,\nfuturistic, professional, tech-focused\n`.trim().replace(/\\s+/g, ' ');\n\n// Comprehensive negative prompt\nconst negativePrompt = `\nlow quality, blurry, pixelated, grainy, jpeg artifacts,\ntext, letters, words, watermark, signature, logo, brand name,\npeople, faces, hands, fingers, human figures, person,\ncluttered, messy, chaotic, disorganized,\ndark, gloomy, depressing, ugly, distorted,\nrealistic photo, stock photo, photograph,\nbad anatomy, deformed, mutation, extra limbs,\nduplication, duplicate elements, repetitive patterns\n`.trim().replace(/\\s+/g, ' ');\n\nreturn {\n json: {\n projectId: project.id,\n prompt: prompt,\n negativePrompt: negativePrompt,\n title: project.title,\n category: project.category,\n timestamp: Date.now()\n }\n};"
},
"id": "build-ai-prompt",
"name": "Build AI Prompt",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.SD_API_URL || 'http://localhost:7860' }}/sdapi/v1/txt2img",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "prompt",
"value": "={{ $json.prompt }}"
},
{
"name": "negative_prompt",
"value": "={{ $json.negativePrompt }}"
},
{
"name": "steps",
"value": "30"
},
{
"name": "cfg_scale",
"value": "7"
},
{
"name": "width",
"value": "1024"
},
{
"name": "height",
"value": "768"
},
{
"name": "sampler_name",
"value": "DPM++ 2M Karras"
},
{
"name": "seed",
"value": "-1"
},
{
"name": "batch_size",
"value": "1"
},
{
"name": "n_iter",
"value": "1"
},
{
"name": "save_images",
"value": "false"
}
]
},
"options": {
"timeout": 180000
}
},
"id": "generate-image-sd",
"name": "Generate Image (Stable Diffusion)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [850, 300],
"credentials": {
"httpHeaderAuth": {
"id": "3",
"name": "SD API Auth"
}
}
},
{
"parameters": {
"jsCode": "const fs = require('fs');\nconst path = require('path');\n\n// Get the base64 image data from Stable Diffusion response\nconst response = $input.first().json;\nconst imageData = response.images[0]; // Base64 encoded PNG\n\nconst projectId = $('Build AI Prompt').first().json.projectId;\nconst timestamp = Date.now();\n\n// Define upload directory (adjust path based on your setup)\nconst uploadDir = process.env.GENERATED_IMAGES_DIR || '/app/public/generated-images';\n\n// Create directory if it doesn't exist\nif (!fs.existsSync(uploadDir)) {\n fs.mkdirSync(uploadDir, { recursive: true });\n}\n\n// Generate filename\nconst filename = `project-${projectId}-${timestamp}.png`;\nconst filepath = path.join(uploadDir, filename);\n\n// Convert base64 to buffer and save\ntry {\n const imageBuffer = Buffer.from(imageData, 'base64');\n fs.writeFileSync(filepath, imageBuffer);\n \n // Get file size for logging\n const stats = fs.statSync(filepath);\n const fileSizeKB = (stats.size / 1024).toFixed(2);\n \n return {\n json: {\n projectId: projectId,\n imageUrl: `/generated-images/${filename}`,\n filepath: filepath,\n filename: filename,\n fileSize: fileSizeKB + ' KB',\n generatedAt: new Date().toISOString(),\n success: true\n }\n };\n} catch (error) {\n return {\n json: {\n projectId: projectId,\n error: error.message,\n success: false\n }\n };\n}"
},
"id": "save-image-file",
"name": "Save Image to File",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1050, 300]
},
{
"parameters": {
"operation": "executeQuery",
"query": "UPDATE projects SET image_url = $1, updated_at = NOW() WHERE id = $2 RETURNING id, title, image_url",
"additionalFields": {
"queryParameters": "={{ $json.imageUrl }},={{ $json.projectId }}"
}
},
"id": "update-project-image",
"name": "Update Project Image URL",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [1250, 300],
"credentials": {
"postgres": {
"id": "2",
"name": "PostgreSQL"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"projectId\": {{ $json.id }},\n \"title\": \"{{ $json.title }}\",\n \"imageUrl\": \"{{ $json.image_url }}\",\n \"generatedAt\": \"{{ $('Save Image to File').first().json.generatedAt }}\",\n \"fileSize\": \"{{ $('Save Image to File').first().json.fileSize }}\",\n \"message\": \"Project image generated successfully\"\n}",
"options": {}
},
"id": "webhook-response",
"name": "Webhook Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [1450, 300]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.success }}",
"value2": true
}
]
}
},
"id": "check-save-success",
"name": "Check Save Success",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [1050, 450]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": false,\n \"error\": \"{{ $json.error || 'Failed to save image' }}\",\n \"projectId\": {{ $json.projectId }},\n \"message\": \"Image generation failed\"\n}",
"options": {
"responseCode": 500
}
},
"id": "error-response",
"name": "Error Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [1250, 500]
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO activity_logs (type, action, details, created_at) VALUES ('ai_generation', 'image_generated', $1, NOW())",
"additionalFields": {
"queryParameters": "={{ JSON.stringify({ projectId: $json.id, imageUrl: $json.image_url, timestamp: new Date().toISOString() }) }}"
}
},
"id": "log-activity",
"name": "Log Generation Activity",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [1250, 150],
"credentials": {
"postgres": {
"id": "2",
"name": "PostgreSQL"
}
}
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Get Project Data",
"type": "main",
"index": 0
}
]
]
},
"Get Project Data": {
"main": [
[
{
"node": "Build AI Prompt",
"type": "main",
"index": 0
}
]
]
},
"Build AI Prompt": {
"main": [
[
{
"node": "Generate Image (Stable Diffusion)",
"type": "main",
"index": 0
}
]
]
},
"Generate Image (Stable Diffusion)": {
"main": [
[
{
"node": "Save Image to File",
"type": "main",
"index": 0
}
]
]
},
"Save Image to File": {
"main": [
[
{
"node": "Check Save Success",
"type": "main",
"index": 0
}
]
]
},
"Check Save Success": {
"main": [
[
{
"node": "Update Project Image URL",
"type": "main",
"index": 0
}
],
[
{
"node": "Error Response",
"type": "main",
"index": 0
}
]
]
},
"Update Project Image URL": {
"main": [
[
{
"node": "Log Generation Activity",
"type": "main",
"index": 0
},
{
"node": "Webhook Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": ""
},
"staticData": null,
"tags": [
{
"name": "AI",
"id": "ai-tag"
},
{
"name": "Automation",
"id": "automation-tag"
},
{
"name": "Image Generation",
"id": "image-gen-tag"
}
],
"meta": {
"instanceId": "your-instance-id"
},
"id": "ai-image-generator-workflow",
"versionId": "1",
"triggerCount": 1,
"active": true
}