NextCloud/Google/Zoho を使用した AI とイベントテキストからカレンダー項目への変換
上級
これはContent Creation, Multimodal AI分野の自動化ワークフローで、19個のノードを含みます。主にIf, Switch, Webhook, HttpRequest, GoogleCalendarなどのノードを使用。 AIとNextCloud/Google/Zohoを使ってイベントテキストをカレンダー項目に変換
前提条件
- •HTTP Webhookエンドポイント(n8nが自動生成)
- •ターゲットAPIの認証情報が必要な場合あり
- •OpenAI API Key
使用ノード (19)
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"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": "付箋",
"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": "付箋1",
"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": "スイッチ",
"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": "付箋2",
"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": "付箋3",
"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": "付箋4",
"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": "付箋5",
"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": "付箋6",
"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\n\n## TTC - Text-to-Calendar event"
},
"typeVersion": 1
},
{
"id": "f10d8f8d-88b0-49be-8263-14c7a343bc1d",
"name": "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": "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
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
上級 - コンテンツ作成, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
OpenAI・LangChain・アピ業間連携によるワークフレーム自動化入門ガイド
OpenAI、LangChain、API を使用したワークフロー自動化の初心者ガイド
If
Set
Code
+
If
Set
Code
33 ノードMeelioo
コンテンツ作成
GPT-4o、Fal.ai、および人間のサポートを用いて製品AI宣伝動画を生成
GPT-4o、Fal.ai、人工が監督するプロダクト用AIビデオ制作
If
Set
Code
+
If
Set
Code
72 ノードgotoHuman
コンテンツ作成
UIをベースにGPT-4とDALL-Eを用いてLinkedInコンテンツ生成を自動化
AIベースのLinkedInコンテンツジェネレーター(OpenAI GPT-4およびDALL-E)
Webhook
Http Request
Agent
+
Webhook
Http Request
Agent
23 ノードWeWeb
コンテンツ作成
Instagramの趨勢電卓ブックからSEOコンテンツを生成して保存(SharePoint/Drive/Dropbox)
GPT-4o、FAL AI、複数ストレージによるトレンドの自動SEOコンテンツ生成
If
Set
Code
+
If
Set
Code
47 ノードplemeo
コンテンツ作成
✅ ウイルスのReelsファクトリー
Veo、Shotstack、Postizを使用したASMRガラス fruit動画制作と公開の自動化
If
Jwt
Set
+
If
Jwt
Set
37 ノードAyoub Boutouil
コンテンツ作成
OpenAI、RunwayML、ElevenLabsを使って無顔の短い動画を自動化
OpenAI、RunwayML、ElevenLabs を使ってアニメ顔の短い動画を自動化:スクリプトからソーシャルメディアへ
Set
Code
Wait
+
Set
Code
Wait
56 ノードLeeWei
コンテンツ作成
ワークフロー情報
難易度
上級
ノード数19
カテゴリー2
ノードタイプ11
作成者
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.
外部リンク
n8n.ioで表示 →
このワークフローを共有