Files
glm-hub/n8n/GLM-Hub-Generar-Icono-Gemini-Nodo-Nativo.json

465 lines
14 KiB
JSON

{
"name": "GLM Hub - Generar ícono con Gemini (Nodo nativo)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "glm-hub-generar-icono",
"responseMode": "responseNode",
"options": {
"allowedOrigins": "*"
}
},
"id": "47ec047e-250d-4056-a2af-2bb6c5f072b0",
"name": "Webhook - Generar ícono",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-1120,
0
],
"webhookId": "bc20a398-5ecf-42a2-9d17-9396aa278708"
},
{
"parameters": {
"jsCode": "const request = $input.first().json ?? {};\nconst rawBody = request.body ?? request;\nlet body = rawBody;\n\nif (typeof rawBody === 'string') {\n try {\n body = JSON.parse(rawBody);\n } catch {\n body = {};\n }\n}\n\nconst headers = request.headers ?? {};\nconst headerAuthorization = String(headers.authorization ?? headers.Authorization ?? '').trim();\nconst accessToken = String(body.accessToken ?? '').trim();\nconst authorization = headerAuthorization.toLowerCase().startsWith('bearer ')\n ? headerAuthorization\n : accessToken\n ? `Bearer ${accessToken}`\n : '';\nconst name = String(body.name ?? '').trim();\nconst description = String(body.description ?? '').trim();\n\nlet error = '';\nif (!authorization.toLowerCase().startsWith('bearer ')) {\n error = 'La sesión de Supabase no fue enviada o no es válida.';\n} else if (name.length < 2 || name.length > 60) {\n error = 'El nombre debe contener entre 2 y 60 caracteres.';\n} else if (!description || description.length > 180) {\n error = 'La descripción debe contener entre 1 y 180 caracteres.';\n}\n\nreturn [{ json: { valid: !error, error, authorization, name, description } }];"
},
"id": "934fb8be-c5bc-43bd-b44a-53f9db105b32",
"name": "Validar solicitud",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-860,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "308c498d-7c3f-4414-a21f-571276aee28b",
"leftValue": "={{ $json.valid }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "3344b885-db2b-473d-a444-a51ca00d063d",
"name": "¿Solicitud válida?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
-640,
0
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { ok: false, error: $json.error } }}",
"options": {
"responseCode": 400,
"responseHeaders": {
"entries": [
{
"name": "Cache-Control",
"value": "no-store"
}
]
}
}
},
"id": "af555c88-6ec6-4e0f-9d01-64b6cb16a5c5",
"name": "Responder 400",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
-400,
180
]
},
{
"parameters": {
"method": "POST",
"url": "={{ ($env.SUPABASE_URL || '').replace(/\\/$/, '') + '/rest/v1/rpc/glm_hub_icon_generation_access' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "={{ $env.SUPABASE_ANON_KEY }}"
},
{
"name": "Authorization",
"value": "={{ $('Validar solicitud').item.json.authorization }}"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "{}",
"options": {
"response": {
"response": {
"neverError": true,
"responseFormat": "json"
}
},
"timeout": 30000
}
},
"id": "42ba23d6-9f3a-4b67-ae48-8253adfb7110",
"name": "Validar administrador en Supabase",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-400,
-80
]
},
{
"parameters": {
"jsCode": "const permission = $input.first().json ?? {};\nconst request = $('Validar solicitud').first().json;\nconst authorized = permission.authorized === true;\nreturn [{\n json: {\n authorized,\n error: authorized ? '' : 'Tu sesión no tiene permisos de administrador para generar íconos.',\n name: request.name,\n description: request.description,\n email: String(permission.email ?? '')\n }\n}];"
},
"id": "489c0999-9ca3-4361-8262-18404f5aad35",
"name": "Confirmar autorización",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-180,
-80
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "c9275da4-0bca-4ce9-bd75-cc7d06e4cf56",
"leftValue": "={{ $json.authorized }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "7c199474-f2b6-4c1c-873d-e578d1f7d500",
"name": "¿Es administrador?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
40,
-80
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { ok: false, error: $json.error } }}",
"options": {
"responseCode": 403,
"responseHeaders": {
"entries": [
{
"name": "Cache-Control",
"value": "no-store"
}
]
}
}
},
"id": "1b105633-29f8-4e75-bead-d3022420dfed",
"name": "Responder 403",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
280,
100
]
},
{
"parameters": {
"jsCode": "const { name, description } = $input.first().json;\nconst prompt = `Crea un ícono cuadrado 1:1, profesional, minimalista y fácil de reconocer para una aplicación interna de GomezLee Marketing.\n\nNombre de la aplicación: ${name}\nDescripción funcional: ${description}\n\nRequisitos visuales obligatorios:\n- Representa la función principal con un único símbolo simple, claro y reconocible.\n- Estética corporativa moderna, limpia y tecnológica.\n- Paleta inspirada en GLM: azul grisáceo, verde claro y verde azulado.\n- Fondo blanco o transparente.\n- Composición centrada, con buen espacio de respiración.\n- Sin texto, sin letras, sin siglas, sin números, sin marcas comerciales y sin logotipos existentes.\n- Sin mockups, sin fotografías, sin personas, sin sombras exageradas y sin fondos complejos.\n- Debe seguir siendo legible al reducirse a 32 x 32 píxeles.\n- Entrega solamente el ícono final.`;\nreturn [{ json: { prompt } }];"
},
"id": "1ae24908-c67d-4742-917e-573b69f4ca19",
"name": "Construir prompt del ícono",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
280,
-180
]
},
{
"parameters": {
"resource": "image",
"operation": "generate",
"modelId": {
"__rl": true,
"value": "models/gemini-3-pro-image",
"mode": "list",
"cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)"
},
"prompt": "={{ $json.prompt }}",
"options": {
"binaryPropertyOutput": "data"
}
},
"id": "bdeed7c1-71ba-4af4-9424-b248c06c9e75",
"name": "Generate an image",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"typeVersion": 1.2,
"position": [
520,
-180
],
"onError": "continueErrorOutput"
},
{
"parameters": {
"respondWith": "binary",
"responseDataSource": "set",
"inputFieldName": "data",
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Cache-Control",
"value": "no-store"
},
{
"name": "Content-Disposition",
"value": "inline; filename=\"glm-hub-icon.png\""
}
]
}
}
},
"id": "7349fabd-6d25-48b1-94be-64e36eef5f7e",
"name": "Responder con ícono",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
800,
-260
]
},
{
"parameters": {
"jsCode": "const input = $input.first().json ?? {};\nconst rawError = input.error ?? input.message ?? input.description ?? input;\nlet message = 'Gemini no pudo generar el ícono. Revisa la credencial, el modelo y la cuota disponible.';\n\nif (typeof rawError === 'string' && rawError.trim()) {\n message = rawError.trim();\n} else if (rawError && typeof rawError === 'object') {\n message = String(rawError.message ?? rawError.description ?? rawError.status ?? message);\n}\n\nreturn [{ json: { ok: false, error: message } }];"
},
"id": "fc7b61a0-fb00-42a4-bc4a-2e530da36a12",
"name": "Preparar error de Gemini",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
800,
-80
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { ok: false, error: $json.error } }}",
"options": {
"responseCode": 502,
"responseHeaders": {
"entries": [
{
"name": "Cache-Control",
"value": "no-store"
}
]
}
}
},
"id": "c0bc7fee-a55e-4f40-90b5-f875c41b131c",
"name": "Responder error de Gemini",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
1040,
-80
]
},
{
"parameters": {
"content": "## CONFIGURACIÓN ÚNICA\n\nEn el nodo **Generate an image**, confirma la credencial existente **Isaac - Gemini Api Pago** después de importar.\n\nEl webhook devuelve la imagen directamente como archivo binario al GLM Hub.",
"height": 220,
"width": 380,
"color": 5
},
"id": "fd8a87b4-3924-412b-8d3d-b7707bf6388b",
"name": "Nota de configuración",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
420,
100
]
}
],
"pinData": {},
"connections": {
"Webhook - Generar ícono": {
"main": [
[
{
"node": "Validar solicitud",
"type": "main",
"index": 0
}
]
]
},
"Validar solicitud": {
"main": [
[
{
"node": "¿Solicitud válida?",
"type": "main",
"index": 0
}
]
]
},
"¿Solicitud válida?": {
"main": [
[
{
"node": "Validar administrador en Supabase",
"type": "main",
"index": 0
}
],
[
{
"node": "Responder 400",
"type": "main",
"index": 0
}
]
]
},
"Validar administrador en Supabase": {
"main": [
[
{
"node": "Confirmar autorización",
"type": "main",
"index": 0
}
]
]
},
"Confirmar autorización": {
"main": [
[
{
"node": "¿Es administrador?",
"type": "main",
"index": 0
}
]
]
},
"¿Es administrador?": {
"main": [
[
{
"node": "Construir prompt del ícono",
"type": "main",
"index": 0
}
],
[
{
"node": "Responder 403",
"type": "main",
"index": 0
}
]
]
},
"Construir prompt del ícono": {
"main": [
[
{
"node": "Generate an image",
"type": "main",
"index": 0
}
]
]
},
"Generate an image": {
"main": [
[
{
"node": "Responder con ícono",
"type": "main",
"index": 0
}
],
[
{
"node": "Preparar error de Gemini",
"type": "main",
"index": 0
}
]
]
},
"Preparar error de Gemini": {
"main": [
[
{
"node": "Responder error de Gemini",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner"
},
"versionId": "ae79a50a-79d1-43f8-b856-b4106bae3e60",
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}