Convierte texto de eventos a entradas de calendario usando IA y NextCloud/Google/Zoho

Avanzado

Este es unContent Creation, Multimodal AIflujo de automatización del dominio deautomatización que contiene 19 nodos.Utiliza principalmente nodos como If, Switch, Webhook, HttpRequest, GoogleCalendar. Convertir texto de eventos en entradas del calendario mediante IA y NextCloud/Google/Zoho

Requisitos previos
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Pueden requerirse credenciales de autenticación para la API de destino
  • Clave de API de OpenAI
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "meta": {
    "instanceId": "90f9a6ef38ec632934192a5de51518245cd649d4287258dedc9971969910cdb7"
  },
  "nodes": [
    {
      "id": "758f90ce-d94a-4c62-a793-7ddd088178f9",
      "name": "to_UTC",
      "type": "@n8n/n8n-nodes-langchain.toolCode",
      "position": [
        1120,
        560
      ],
      "parameters": {
        "name": "to_UTC",
        "jsCode": "function toICSDate(query) {\n  let d;\n\n  if (query instanceof Date) {\n    d = query;\n\n  } else if (typeof query === 'string') {\n    if (/^\\d{8}T\\d{6}Z$/.test(query)) {\n      // Already ICS UTC format\n      return query;\n    } else if (/^\\d{8}T\\d{6}$/.test(query)) {\n      // Compact local format, parse manually\n      const [datePart, timePart] = query.split('T');\n      const year   = +datePart.slice(0, 4);\n      const month  = +datePart.slice(4, 6) - 1; // 0‑based\n      const day    = +datePart.slice(6, 8);\n      const hour   = +timePart.slice(0, 2);\n      const minute = +timePart.slice(2, 4);\n      const second = +timePart.slice(4, 6);\n      d = new Date(year, month, day, hour, minute, second);\n    } else {\n      // Assume ISO‑8601 string (\"2025-09-26T11:00:00-04:00\")\n      d = new Date(query);\n    }\n  }\n\n  if (!(d instanceof Date) || isNaN(d)) {\n    throw new Error('Invalid input: must be Date, ISO, ICS UTC, or compact string');\n  }\n\n  // Always format UTC\n  return d.toISOString()\n          .replace(/[-:]/g, '')   // strip separators\n          .replace(/\\.\\d{3}Z$/, 'Z'); // remove ms\n}\n\n// Export\nreturn toICSDate(query);",
        "description": "=Call this tool and provide a datetime object in *{{ $now.zone.zoneName }}* timezone and this will give you the UTC time, in string format \"yyyyMMdd'T'HHmmss'Z'\"."
      },
      "typeVersion": 1.1
    },
    {
      "id": "6917181e-dfdc-4cec-b621-8ce68c774231",
      "name": "Brain",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1020,
        560
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "bbcd8973-12d9-4d85-b6f6-4cec224ad447",
      "name": "Nota adhesiva",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        240
      ],
      "parameters": {
        "color": 4,
        "height": 663.3731744745251,
        "content": "## START\nSend a text block of event data (like an from an email body or text extracted from an image) to property **`eventInfo`**."
      },
      "typeVersion": 1
    },
    {
      "id": "8b7d5184-0f36-4ae8-87d1-bbaf4b8133f0",
      "name": "Nota adhesiva1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        740,
        240
      ],
      "parameters": {
        "color": 7,
        "height": 663.3731744745248,
        "content": "## EXPANSION\n(Optional) If you wanted this workflow to receive an image, and send that directly to the language model to parse for event data, you can use this switch node to send the binary image down a different pathway.\n\nThat's up to you to build ;-)"
      },
      "typeVersion": 1
    },
    {
      "id": "2c338370-8748-4c8f-8bdd-29f8b25f86fb",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "disabled": true,
      "position": [
        780,
        720
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Text",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "19b65514-2493-4128-8e9c-c1dd40454ac6",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.body.eventInfo }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Image",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "object",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $binary }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "allMatchingOutputs": false
        }
      },
      "typeVersion": 3.1
    },
    {
      "id": "2f211450-6b40-4bac-8a1b-00592164d11d",
      "name": "Nota adhesiva2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        240
      ],
      "parameters": {
        "width": 358.7342715692612,
        "height": 663.3731744745251,
        "content": "## PARSE EVENT DETAILS\nThis agent takes in a block of unformatted text that contains info about an event (eg. time, place, event name...) and parses it to a structured output."
      },
      "typeVersion": 1
    },
    {
      "id": "276e4820-bbab-48a2-9d9d-dd4275924052",
      "name": "Nota adhesiva3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1380,
        240
      ],
      "parameters": {
        "color": 5,
        "height": 663.3731744745251,
        "content": "## CREATE EVENT\nSends a request to `NextCloud` CalDAV to create an event in your calendar.\n\nYou'll need to add `Basic Auth` credentials (user/pass) from your NextCloud account.\n\nCreate an app-specific password here: [your.NC.url/index.php/settings/user/security]"
      },
      "typeVersion": 1
    },
    {
      "id": "93d6676b-f337-4052-927a-d4a86e9d589d",
      "name": "Nota adhesiva4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1640,
        240
      ],
      "parameters": {
        "color": 3,
        "height": 663.3731744745251,
        "content": "## RESPOND\nSend your success response back to the source system. You can edit this to return a JSON object instead if required.\n\n**PS** - This workflow plugs in seamlessly with [this iCloud Shortcut](https://www.icloud.com/shortcuts/8a107ea08ec4471d877b019520a4802c)"
      },
      "typeVersion": 1
    },
    {
      "id": "6b37e5dd-e26a-4920-a929-9a9749ad8cc1",
      "name": "Nota adhesiva5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        920
      ],
      "parameters": {
        "color": 7,
        "width": 1400.3576539723263,
        "height": 258.08325199688073,
        "content": "## SUGGESTIONS\nIn production setting, you'll want to account for errors and bad input. What if the user just puts in random text with no event details? The Ai should be instructed to then output a specific fail response that goes back to the source system to tell it the input was no good.\n\nIf your NextCloud is self-hosted, and there's a chance it could be down, you may want to catch an error there as well, and announce that back to the source system, via webhook response.\n\nI use a version of this workflow with an iOS shortcut for my iPhone. I tell Siri \"Add this to my calendar\" and it opens the camera, I snap, and it sends the text in the photo to this workflow. Very easy to use. *If you have an iPhone*, here's the Shortcut for you to do the same:\n\n#### ⭐  https://www.icloud.com/shortcuts/8a107ea08ec4471d877b019520a4802c"
      },
      "typeVersion": 1
    },
    {
      "id": "4e383a02-ece9-4c0f-a8a6-4090885e6c40",
      "name": "Crear evento en Zoho (API)",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Documentation:\nhttps://www.zoho.com/calendar/help/api/post-create-event.html",
      "disabled": true,
      "position": [
        1420,
        720
      ],
      "parameters": {
        "url": "https://calendar.zoho.com/api/v1/calendars/INSERT_CAL_UID_HERE/events",
        "method": "POST",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "queryParameters": {
          "parameters": [
            {
              "name": "eventdata",
              "value": "={\n    \"dateandtime\": {\n        \"timezone\": {{ JSON.stringify($now.zone.zoneName) }},\n        \"start\": {{ JSON.stringify($json.output.startTime) }},\n        \"end\": {{ JSON.stringify($json.output.endTime) }}\n    },\n    \"title\": {{ JSON.stringify($json.output.eventTitle) }},\n    \"location\": {{ JSON.stringify($json.output.location != null ? $json.output.location : \"\") }},\n    \"url\": {{ JSON.stringify($json.output.url != null ? $json.output.url : \"\") }},\n    \"transparency\": 1,\n    \"attendees\": [\n        {\n            \"email\": \"INSERT_EMAIL_HERE\"\n        }\n    ],\n    \"description\": {{ JSON.stringify($json.output.description != null ? $json.output.description : \"\") }}\n}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "06883e54-7548-448d-92d8-6d7079bdbf43",
      "name": "Salida estructurada",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1220,
        560
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"eventTitle\": \"Marketing Conference\",\n  \"description\": null,\n  \"startTime\": \"20250912T160000Z\",\n  \"endTime\": \"20250912T200000Z\",\n  \"location\": \"15000 Park Ave, Suite 1234, New York, New York, United States\",\n  \"url\": null\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "1102b5a1-932b-4ab9-a2d3-17950c4b8b99",
      "name": "Respuesta exitosa",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1700,
        540
      ],
      "parameters": {
        "options": {
          "responseCode": 201
        },
        "respondWith": "text",
        "responseBody": "=Your calendar event was successfully created."
      },
      "typeVersion": 1.1
    },
    {
      "id": "c162405c-ed1a-4177-8f9f-5110ffbeb426",
      "name": "Respuesta fallida",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1700,
        740
      ],
      "parameters": {
        "options": {
          "responseCode": 400
        },
        "respondWith": "text",
        "responseBody": "=There was a problem with the event info. Try again."
      },
      "typeVersion": 1.1
    },
    {
      "id": "7f11b9f4-526e-45fd-8e89-e89c8b9e2db4",
      "name": "Creación de evento en NextCloud Cal",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1440,
        540
      ],
      "parameters": {
        "url": "https://your.nextcloudurl.com/remote.php/dav/calendars/YOUR_USER/personal/newEvent.ics",
        "body": "=BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//n8n//CalDAV Connector//EN\nBEGIN:VEVENT\nUID:123456789@example.com\nDTSTAMP:{{ $now.setZone($now.zone.zoneName).toUTC().toFormat(\"yyyyMMdd'T'HHmmss'Z'\") }}\nDTSTART:{{ $json.output.startTime }}\nDTEND:{{ $json.output.endTime }}\nSUMMARY:{{ $json.output.eventTitle }}\nDESCRIPTION:{{ $json.output.description }}\nLOCATION:{{ $json.output.location }}\nURL:{{ $json.output.url }}\nEND:VEVENT\nEND:VCALENDAR",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "text/calendar; charset=utf-8"
      },
      "typeVersion": 4.2
    },
    {
      "id": "9a789e02-203a-40b8-a834-aa6fa6881ce7",
      "name": "Análisis correcto",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        760
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3bd94ff5-bebb-43a4-ae06-7790de6df7a6",
              "operator": {
                "type": "string",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.output.error }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "c6bb115d-bf79-457d-a8db-fb4a8ef1bcf5",
      "name": "Nota adhesiva6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -260
      ],
      "parameters": {
        "color": 5,
        "width": 435.7280989463619,
        "height": 478.57603298212047,
        "content": "## Eric Knaus www.MarketingGuy.ai\nFind me on LinkedIn: https://linkedin.com/in/ericknaus\n\n![My Image](https://ericknaus.com/wp-content/uploads/2025/09/black-and-white_sm.png)\n\n## TTC - Text-to-Calendar event"
      },
      "typeVersion": 1
    },
    {
      "id": "f10d8f8d-88b0-49be-8263-14c7a343bc1d",
      "name": "Calendario Google",
      "type": "n8n-nodes-base.googleCalendar",
      "disabled": true,
      "position": [
        1480,
        740
      ],
      "parameters": {
        "end": "={{ $json.output.endTime }}",
        "start": "={{ $json.output.startTime }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "additionalFields": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "b4be10a7-0306-425e-9e24-f449dc198ae0",
      "name": "Información de evento entrante",
      "type": "n8n-nodes-base.webhook",
      "position": [
        540,
        540
      ],
      "webhookId": "2ee09e2c-6ee0-4e12-a941-a40a63442bb1",
      "parameters": {
        "path": "make-cal-event-xdt8gh4-rf3827",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "80fc0363-4991-4eb9-a019-17b8597e9bfe",
      "name": "Analizar información del evento",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1040,
        380
      ],
      "parameters": {
        "text": "=Local time context: {{ $now.toString() }}  \nServer timezone: {{ $now.zone.zoneName }}  \n\nInstructions:\n1. Extract calendar event details from the text below.  \n2. For event times, pass each local datetime through `to_UTC(Datetime)` to get UTC output values, in \"YYYYMMDDTHHmmssZ\" format.  \n4. Apply special cases:\n   - Case 1: If text has a date and at least one person/place but no clear details → infer event. If no time, use 08:00–22:00 local.  \n   - Case 2: If there is no date and no person/place/event → output exactly: {\"error\": \"BAD INPUT\"} \n\nText to parse:\n{{ JSON.stringify($json.body.eventInfo) }}",
        "options": {
          "systemMessage": "You are an assistant that extracts calendar event information from text.\n\nAlways respond ONLY in JSON.\n\nNormal Output Schema (when event is valid or inferable):\n{\n  \"eventTitle\": \"string\",\n  \"description\": \"string or null\",\n  \"startTime\": \"YYYYMMDDTHHmmssZ\",  // UTC, ISO8601\n  \"endTime\": \"YYYYMMDDTHHmmssZ\",    // UTC, ISO8601\n  \"location\": \"string or null\",\n  \"url\": \"string or null\"\n}\n\nSpecial Rules:\n1. If text includes at least one date and a name or place but lacks other details → infer a plausible event.  \n   - If no time is provided → assume 08:00 for start time and 22:00 for end time, local time. Convert using `to_UTC`.  \n2. If text has no date and no usable event/person/place detail → output:\n   {\n     \"error\": \"BAD INPUT\"\n   }\n\nFormatting Rules:\n- Output strictly valid JSON only.\n- Use null values for missing optional fields unless you are inferring details under rule (1).\n- Use the `to_UTC(Datetime)` tool to convert each local datetime to UTC."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.6
    }
  ],
  "pinData": {},
  "connections": {
    "6917181e-dfdc-4cec-b621-8ce68c774231": {
      "ai_languageModel": [
        [
          {
            "node": "80fc0363-4991-4eb9-a019-17b8597e9bfe",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "758f90ce-d94a-4c62-a793-7ddd088178f9": {
      "ai_tool": [
        [
          {
            "node": "80fc0363-4991-4eb9-a019-17b8597e9bfe",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "9a789e02-203a-40b8-a834-aa6fa6881ce7": {
      "main": [
        [
          {
            "node": "7f11b9f4-526e-45fd-8e89-e89c8b9e2db4",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "c162405c-ed1a-4177-8f9f-5110ffbeb426",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "80fc0363-4991-4eb9-a019-17b8597e9bfe": {
      "main": [
        [
          {
            "node": "9a789e02-203a-40b8-a834-aa6fa6881ce7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "06883e54-7548-448d-92d8-6d7079bdbf43": {
      "ai_outputParser": [
        [
          {
            "node": "80fc0363-4991-4eb9-a019-17b8597e9bfe",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "b4be10a7-0306-425e-9e24-f449dc198ae0": {
      "main": [
        [
          {
            "node": "80fc0363-4991-4eb9-a019-17b8597e9bfe",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7f11b9f4-526e-45fd-8e89-e89c8b9e2db4": {
      "main": [
        [
          {
            "node": "1102b5a1-932b-4ab9-a2d3-17950c4b8b99",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "c162405c-ed1a-4177-8f9f-5110ffbeb426",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Creación de contenido, IA Multimodal

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Flujos de trabajo relacionados recomendados

Guía principiante para la automatización de flujos de trabajo con OpenAI, LangChain y API integradas
Guía de iniciación a la automatización de flujos de trabajo con OpenAI, LangChain e integración de API
If
Set
Code
+
If
Set
Code
33 NodosMeelioo
Creación de contenido
Generar videos promocionales de IA para productos usando GPT-4o, Fal.ai y supervisión humana
Usar GPT-4o, Fal.ai y supervisión humana para generar videos promocionales de productos de AI
If
Set
Code
+
If
Set
Code
72 NodosgotoHuman
Creación de contenido
Creación automatizada de contenido de LinkedIn basada en la interfaz de usuario (UI) con GPT-4 y DALL-E
Generador de contenido para LinkedIn basado en AI (GPT-4 de OpenAI y DALL-E)
Webhook
Http Request
Agent
+
Webhook
Http Request
Agent
23 NodosWeWeb
Creación de contenido
Generar contenido SEO desde una hoja de cálculo de tendencias a un almacenamiento (SharePoint/Drive/Dropbox)
Usar GPT-4o, FAL AI y soporte multi-almacenamiento para generar automáticamente contenido SEO a partir de tendencias
If
Set
Code
+
If
Set
Code
47 Nodosplemeo
Creación de contenido
✅ Fábrica de Reels virales
Usar Veo, Shotstack y Postiz para automatizar la creación y publicación de videos ASMR de frutas de vidrio
If
Jwt
Set
+
If
Jwt
Set
37 NodosAyoub Boutouil
Creación de contenido
Automatización de videos cortos sin rostro usando OpenAI, RunwayML y ElevenLabs
Automatización de videos cortos sin rostro usando OpenAI, RunwayML y ElevenLabs: del guion a las redes sociales
Set
Code
Wait
+
Set
Code
Wait
56 NodosLeeWei
Creación de contenido
Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos19
Categoría2
Tipos de nodos11
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor

Automation Wizard bzzt Years of experience as a digital marketer. Honed skill in JS, web dev, email mktg. All about the value to the client. Value, baby, it's everything.

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34