Conversion de texte d'événement en entrées de calendrier en utilisant l'IA et NextCloud/Google/Zoho

Avancé

Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 19 nœuds.Utilise principalement des nœuds comme If, Switch, Webhook, HttpRequest, GoogleCalendar. Convertir du texte d'événements en entrées de calendrier via IA et NextCloud/Google/Zoho

Prérequis
  • Point de terminaison HTTP Webhook (généré automatiquement par n8n)
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
  • Clé API OpenAI
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "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": "Note adhésive",
      "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": "Note adhésive1",
      "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": "Commutateur",
      "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": "Note adhésive2",
      "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": "Note adhésive3",
      "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": "Note adhésive4",
      "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": "Note adhésive5",
      "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": "Create Zoho Event (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": "Structured Output",
      "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": "Success Response",
      "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": "Fail Response",
      "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": "NextCloud Cal Event Creation",
      "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": "Good Parse",
      "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": "Note adhésive6",
      "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": "Google Agenda",
      "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": "Inbound Event Info",
      "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": "Parse Event Info",
      "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
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Création de contenu, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Workflows recommandés

Guide de débutant pour l'automatisation des workflows avec OpenAI, LangChain et l'intégration d'API
Guide débutant pour l'automatisation des workflows avec OpenAI, LangChain et intégration d'API
If
Set
Code
+
If
Set
Code
33 NœudsMeelioo
Création de contenu
Générer des vidéos promotionnelles de produits IA avec GPT-4o, Fal.ai et une supervision humaine
Générer des vidéos promotionnelles de produits IA avec GPT-4o, Fal.ai et une supervision humaine
If
Set
Code
+
If
Set
Code
72 NœudsgotoHuman
Création de contenu
Automatisation de la création de contenu LinkedIn basée sur l'interface utilisateur avec GPT-4 et DALL-E
Générateur de contenu LinkedIn basé sur l'IA (OpenAI GPT-4 et DALL-E)
Webhook
Http Request
Agent
+
Webhook
Http Request
Agent
23 NœudsWeWeb
Création de contenu
Générer du contenu SEO à partir d'une feuille de calcul de tendances vers un stockage (SharePoint/Drive/Dropbox)
Génération automatique de contenu SEO à partir des tendances avec GPT-4o, FAL AI et prise en charge de plusieurs stockages
If
Set
Code
+
If
Set
Code
47 Nœudsplemeo
Création de contenu
✅ Usine de Reels virale
Utiliser Veo, Shotstack et Postiz pour automatiser la création et la publication de vidéos ASMR sur fruits en verre
If
Jwt
Set
+
If
Jwt
Set
37 NœudsAyoub Boutouil
Création de contenu
Automatisation de courts métrages sans visage avec OpenAI, RunwayML et ElevenLabs
Automatisation de courts métrages sans visage : du script aux réseaux sociaux avec OpenAI, RunwayML et ElevenLabs
Set
Code
Wait
+
Set
Code
Wait
56 NœudsLeeWei
Création de contenu
Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds19
Catégorie2
Types de nœuds11
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Auteur

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.

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34