feat: add folder support for workflows (fixes #70)

This commit is contained in:
Praveen Mudalgeri
2025-08-05 09:40:47 +05:30
parent 307d530f9b
commit c4885eee92
2057 changed files with 985290 additions and 974268 deletions

View File

@@ -0,0 +1,737 @@
{
"meta": {
"instanceId": "408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9"
},
"nodes": [
{
"id": "76589d1c-45f3-4a89-906f-8ef300d34964",
"name": "n8n Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
-2520,
-280
],
"webhookId": "5e7637dd-d222-4786-8cdc-7b66cebc1481",
"parameters": {
"path": "schedule_appointment",
"options": {
"ignoreBots": true,
"appendAttribution": true,
"useWorkflowTimezone": true
},
"formTitle": "Schedule an Appointment",
"formFields": {
"values": [
{
"fieldLabel": "Your Name",
"placeholder": "eg. Sam Smith",
"requiredField": true
},
{
"fieldType": "email",
"fieldLabel": "Email",
"placeholder": "eg. sam@example.com",
"requiredField": true
},
{
"fieldType": "textarea",
"fieldLabel": "Enquiry",
"placeholder": "eg. I'm looking for...",
"requiredField": true
}
]
},
"formDescription": "Welcome to Jim's Appointment Form.\nBefore we set a date, please tell me a little about yourself and how I can help."
},
"typeVersion": 2.1
},
{
"id": "194b7073-fa33-4e75-85ed-c02724c8075c",
"name": "Form End",
"type": "n8n-nodes-base.form",
"position": [
-420,
-260
],
"webhookId": "8fcc907b-bc2e-4fdf-a829-82c83e677724",
"parameters": {
"options": {
"formTitle": "Appointment Request Sent!"
},
"operation": "completion",
"completionTitle": "Appointment Request Sent!",
"completionMessage": "=Thank you for submitting an appointment request. A confirmation of this request will be sent to your inbox. I'll get back to you shortly with a confirmation of the appointment.\n\nHere is the summary of the appointment request.\n\nName: {{ $('Get Form Values').item.json.name }}\nDate & Time: {{ DateTime.fromISO($('Get Form Values').item.json.dateTime).format('EEE, dd MMM @ t') }}\nEnquiry: {{ $('Get Form Values').item.json.enquiry.trim() }}\n"
},
"typeVersion": 1
},
{
"id": "688ea2cc-b595-4b6f-9214-d5dfd3893172",
"name": "Enter Date & Time",
"type": "n8n-nodes-base.form",
"position": [
-1260,
-320
],
"webhookId": "0cd03415-66f8-4c82-8069-5bfd8ea310bd",
"parameters": {
"options": {
"formTitle": "Enter a Date & Time",
"formDescription": "=Please select a date and time"
},
"defineForm": "json",
"jsonOutput": "={{\n[\n {\n \"fieldLabel\":\"Date\",\n \"requiredField\":true,\n \"fieldType\": \"dropdown\",\n \"fieldOptions\":\n Array(5).fill(0)\n .map((_,idx) => $now.plus(idx+1, 'day'))\n .filter(d => !d.isWeekend)\n .map(d => ({ option: d.format('EEE, d MMM') }))\n },\n {\n \"fieldLabel\": \"Time\",\n \"requiredField\": true,\n \"fieldType\": \"dropdown\",\n \"fieldOptions\": [\n { \"option\": \"9:00 am\" },\n { \"option\": \"10:00 am\" },\n { \"option\": \"11:00 am\" },\n { \"option\": \"12:00 pm\" },\n { \"option\": \"1:00 pm\" },\n { \"option\": \"2:00 pm\" },\n { \"option\": \"3:00 pm\" },\n { \"option\": \"4:00 pm\" },\n { \"option\": \"5:00 pm\" },\n { \"option\": \"6:00 pm\" }\n ]\n }\n]\n}}"
},
"typeVersion": 1
},
{
"id": "602c40f9-ab11-4908-aab3-1a199126e097",
"name": "Get Form Values",
"type": "n8n-nodes-base.set",
"position": [
-900,
-260
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{\n{\n name: $('n8n Form Trigger').first().json['Your Name'],\n email: $('n8n Form Trigger').first().json.Email,\n enquiry: $('n8n Form Trigger').first().json.Enquiry,\n dateTime: DateTime.fromFormat(`${$json.Date} ${$json.Time}`, \"EEE, dd MMM t\"),\n submittedAt: $('n8n Form Trigger').first().json.submittedAt,\n}\n}}"
},
"typeVersion": 3.4
},
{
"id": "21f93645-5e27-4e9f-a72c-47a39e42a79c",
"name": "Terms & Conditions",
"type": "n8n-nodes-base.form",
"position": [
-1680,
-240
],
"webhookId": "dcf32f99-8fb7-457a-8a58-ac1a018b1873",
"parameters": {
"options": {
"formTitle": "Before we continue...",
"formDescription": "=Terms and Conditions for Booking an Appointment\n\nNon-Binding Nature of Discussions:\nAny information shared, discussed, or agreed upon during the call is non-binding and provisional. No agreement, service, or commitment shall be considered confirmed unless explicitly documented and agreed to in writing.\n\nProhibition of Recording and Note-Taking Tools:\nBy proceeding with the appointment, the user agrees not to use AI assistants, note-taking applications, recording devices, or any other technology to record or transcribe the conversation, whether manually or automatically. This is to ensure confidentiality and respect for the integrity of the discussion.\n\nConfirmation of Understanding:\nBy booking this appointment, you acknowledge and accept these terms and conditions in full."
},
"formFields": {
"values": [
{
"fieldType": "dropdown",
"fieldLabel": "Please select",
"multiselect": true,
"fieldOptions": {
"values": [
{
"option": "I accept the terms and conditions"
}
]
},
"requiredField": true
}
]
}
},
"typeVersion": 1
},
{
"id": "22e03fec-bd56-4fc3-864a-f1e81a864cb5",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-2340,
-140
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "8b4e9bba-cd57-46af-8042-4b47e5ebcd82",
"name": "Has Accepted?",
"type": "n8n-nodes-base.if",
"position": [
-1500,
-240
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "bc7c3e99-e610-4997-82a7-4851f2c04c19",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json[\"Please select\"] }}",
"rightValue": "I accept"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "627a4c00-e831-4a77-8aad-f417f0f8e6dd",
"name": "Send Receipt",
"type": "n8n-nodes-base.gmail",
"position": [
-580,
-260
],
"webhookId": "5f590407-4ab9-4ae6-bb85-38dbe41d6dce",
"parameters": {
"sendTo": "={{ $('Get Form Values').first().json.email }}",
"message": "=<p>Dear {{ $('Get Form Values').first().json.name }},</p>\n<p>Thanks for requesting an appointment. We will review and get back to you shortly.</p>\n<p>Here is the summary of the request that was sent:</p>\n<p>\nName: {{ $('Get Form Values').first().json.name }}<br/>\nEmail: {{ $('Get Form Values').first().json.email }}<br/>\nEnquiry: {{ $('Get Form Values').first().json.enquiry }}<br/>\nSubmitted at: {{ $('Get Form Values').first().json.submittedAt }}\n</p>\n",
"options": {},
"subject": "=Appointment Request Received for {{ DateTime.fromISO($('Get Form Values').first().json.dateTime).format('EEE, dd MMM @ t') }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "91d3dd7d-53f8-4f8e-9af2-ec54cf7f42ad",
"name": "Wait for Approval",
"type": "n8n-nodes-base.gmail",
"position": [
340,
-260
],
"webhookId": "ab9c6c5e-334d-44bb-a8fd-a58140bc680d",
"parameters": {
"sendTo": "=admin@example.com",
"message": "=<h2>A new appointment request was submitted!</h2>\n<p>\nRequesting appointment date is <strong>{{ DateTime.fromISO($('Execute Workflow Trigger').item.json.dateTime).format('EEE, dd MMM @ t') }}</strong>.\n</p>\n<p>\nName: {{ $('Execute Workflow Trigger').first().json.name }}<br/>\nEmail: {{ $('Execute Workflow Trigger').first().json.email }}<br/>\nEnquiry Summary: {{ $json.text }}<br/>\nSubmitted at: {{ $('Execute Workflow Trigger').first().json.submittedAt }}\n</p>",
"subject": "New Appointment Request!",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"approveLabel": "Confirm"
}
}
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "7a02b57b-b9b1-45b1-9b3d-aebb84259875",
"name": "Has Approval?",
"type": "n8n-nodes-base.if",
"position": [
520,
-260
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e5e37acb-9e9d-4a9e-bf59-a35dfc035886",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "96aab8be-4c5e-4e14-a6ea-6d2b743551be",
"name": "OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
0,
-120
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "6f2b5454-70a3-4391-b785-bb871c3e2081",
"name": "Create Appointment",
"type": "n8n-nodes-base.googleCalendar",
"position": [
720,
-340
],
"parameters": {
"end": "={{ DateTime.fromISO($('Execute Workflow Trigger').first().json.dateTime).plus(30, 'minute').toISO() }}",
"start": "={{ $('Execute Workflow Trigger').first().json.dateTime }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "c_5792bdf04bc395cbcbc6f7b754268245a33779d36640cc80a357711aa2f09a0a@group.calendar.google.com",
"cachedResultName": "n8n-events"
},
"additionalFields": {
"summary": "=Appointment Scheduled - {{ $('Execute Workflow Trigger').item.json.name }} & Jim",
"attendees": [
"={{ $('Execute Workflow Trigger').item.json.email }}"
],
"description": "={{ $('Summarise Enquiry').first().json.text }}\n\nOriginal message:\n> {{ $('Execute Workflow Trigger').item.json.enquiry }}",
"conferenceDataUi": {
"conferenceDataValues": {
"conferenceSolution": "hangoutsMeet"
}
}
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "kWMxmDbMDDJoYFVK",
"name": "Google Calendar account"
}
},
"typeVersion": 1.2
},
{
"id": "e6881867-5b3c-4b85-b06a-a0a3c01be227",
"name": "Send Rejection",
"type": "n8n-nodes-base.gmail",
"position": [
720,
-180
],
"webhookId": "5f590407-4ab9-4ae6-bb85-38dbe41d6dce",
"parameters": {
"sendTo": "={{ $('Execute Workflow Trigger').first().json.email }}",
"message": "=<p>Dear {{ $('Execute Workflow Trigger').first().json.name }},</p>\n<p>Unfortunately, we cannot schedule the requested appointment at the requested time.</p>\n<p>Kind regards</p>\n",
"options": {},
"subject": "=Appointment Request Rejected for {{ DateTime.fromISO($('Execute Workflow Trigger').first().json.dateTime).format('EEE, dd MMM @ t') }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "40785eca-943c-45f6-b4a9-0c95538621ed",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2580,
-555.2889298043726
],
"parameters": {
"color": 7,
"width": 763.0427617951669,
"height": 611.898918296892,
"content": "## 1. Qualify Enquiries Using AI\n[Learn more about the text classifier](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/)\n\nWith n8n's multi-forms, youre no longer stuck creating long, overwhelming forms. Instead, you have more flexibility and control to design smarter, more engaging form experiences.\n\nIn this demo, well explore an appointment request scenario where a user wants to schedule a call to discuss their inquiry. However, not all inquiries require a meeting, making it a perfect use case for AI to pre-qualify the request. We can handle this validation using the text classifier node."
},
"typeVersion": 1
},
{
"id": "985be8d1-e77a-475b-9ac2-dba163dbd950",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1800,
-549.8684464902185
],
"parameters": {
"color": 7,
"width": 781.472405063291,
"height": 606.0718987341766,
"content": "## 2. Split Form For Better User Experience\n[Learn more about the forms](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.form)\n\nOnboarding is a great reason to split your big form into smaller ones. Taking the user through a step by step process ensures a smooth experience and keeps them engaged throughout.\n\nHere, we take the opportunity of the extra context space to display a terms and conditions which the user must agree to making their request. The next form then asks for desired date and time of the event."
},
"typeVersion": 1
},
{
"id": "9b0a3f0e-e15d-4d0e-b620-1acc78bf812c",
"name": "Decline",
"type": "n8n-nodes-base.form",
"position": [
-2020,
-160
],
"webhookId": "4353eadb-b7a0-45f2-8dd8-5f6cd882d8d8",
"parameters": {
"options": {},
"operation": "completion",
"completionTitle": "Send me a DM Instead!",
"completionMessage": "Thanks for your enquiry but it may not necessarily need an appointment. Please feel free to email me instead at jim@example.com."
},
"typeVersion": 1
},
{
"id": "fcd3eb7d-6389-4c07-97cc-275ae387c963",
"name": "Decline1",
"type": "n8n-nodes-base.form",
"position": [
-1260,
-160
],
"webhookId": "4353eadb-b7a0-45f2-8dd8-5f6cd882d8d8",
"parameters": {
"options": {},
"operation": "completion",
"completionTitle": "Send me a DM Instead!",
"completionMessage": "Thanks for your enquiry but it may not necessarily need an appointment. Please feel free to email me instead at jim@example.com."
},
"typeVersion": 1
},
{
"id": "d89427cb-fffb-4aa4-b55c-b315fa0e92be",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1000,
-498.80432681242814
],
"parameters": {
"color": 7,
"width": 792.9401150747982,
"height": 497.4250863060987,
"content": "## 3. Send Acknowledgement to User and Start Approval Process\n[Learn more about the Gmail node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.gmail/)\n\nOnce all form steps are concluded, we can send a notification to the requester via email and in the background, trigger another email to the admin to initiate the approval process. The approval process works in a separate execution so doesn't interrupt the user's form experience."
},
"typeVersion": 1
},
{
"id": "041081e1-ee98-4b40-aa14-1980b23f4031",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
-620
],
"parameters": {
"color": 7,
"width": 609.4228768699652,
"height": 287.178089758343,
"content": "## 4. Approve or Decline Appointment\n[Learn more about the Waiting for Approval](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.gmail/message-operations/#send-a-message-and-wait-for-approval)\n\nThe Wait for Approval feature for Gmail is a special operation which allows for human-in-the-loop interaction in n8n workflows. In this example, the human interaction is the approval of the appointment request. The feature will put the workflow in a waiting state where a message is sent to the admin with 2 buttons: confirm and decline.\n\nWhen the admin clicks on the confirm button, the workflow resumes from the Gmail node and a meeting event is created for the requesting user in Google Calendar.\n\nWhen declined, a rejection email is sent to the requester instead."
},
"typeVersion": 1
},
{
"id": "d6af0f50-234f-46ca-aa41-7f3891aff8a3",
"name": "Trigger Approval Process",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
-740,
-260
],
"parameters": {
"mode": "each",
"options": {
"waitForSubWorkflow": false
},
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $workflow.id }}"
}
},
"typeVersion": 1.1
},
{
"id": "e524d6df-9b6d-4d61-8e71-08a0d3a751d7",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
-160,
-260
],
"parameters": {},
"typeVersion": 1
},
{
"id": "74dccbc1-7728-4336-a18a-2541007fd369",
"name": "Summarise Enquiry",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
0,
-260
],
"parameters": {
"text": "=The enquiry is as follows:\n{{ $('Execute Workflow Trigger').first().json.enquiry.substring(0, 500) }}",
"messages": {
"messageValues": [
{
"message": "Summarise the given enquiry"
}
]
},
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "b74f0f5a-39f0-4db3-beba-03caf981c5d2",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3080,
-640
],
"parameters": {
"width": 468.6766398158801,
"height": 690.6653164556957,
"content": "## Try it out!\n\n### This n8n template is a simple appointment scheduling workflow using n8n forms with AI thrown in the mix for good measure. It also uses n8n's wait for approval feature which allows the ability to confirm appointment requests and create events in Google Calendar.\n\n### How it works\n* We start with a form trigger which asks for the purpose of the appointment.\n* Instantly, we can qualify this by using a text classifier node which uses AI's contextual understanding to ensure the appointment is worthwhile. If not, an alternative is suggested instead.\n* Multi-page forms are then used to set the terms of the appointment and ask the user for a desired date and time.\n* An acknowledgement is sent to the user while an approval by email process is triggered in the background.\n* In a subworkflow, we use Gmail with the wait for approval operation to send an approval form to the admin user who can either confirm or decline the appointment request.\n* When approved, a Google Calendar event is created. When declined, the user is notified via email that the appointment request was declined.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!\n"
},
"typeVersion": 1
},
{
"id": "d3c87dfa-d6e5-402a-89e5-6d8f93b824a6",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
299,
-280
],
"parameters": {
"width": 177.66444188722656,
"height": 257.56869965477557,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### 🚨 Set your admin email here!"
},
"typeVersion": 1
},
{
"id": "6351121d-6ebe-432d-b370-13296fd58e1a",
"name": "Enquiry Classifier",
"type": "@n8n/n8n-nodes-langchain.textClassifier",
"position": [
-2340,
-280
],
"parameters": {
"options": {
"fallback": "other"
},
"inputText": "={{ $json.Enquiry }}",
"categories": {
"categories": [
{
"category": "relevant enquiry",
"description": "Enquire about AI, automation, digital products and product engineering."
}
]
}
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Send Receipt": {
"main": [
[
{
"node": "Form End",
"type": "main",
"index": 0
}
]
]
},
"Has Accepted?": {
"main": [
[
{
"node": "Enter Date & Time",
"type": "main",
"index": 0
}
],
[
{
"node": "Decline1",
"type": "main",
"index": 0
}
]
]
},
"Has Approval?": {
"main": [
[
{
"node": "Create Appointment",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Rejection",
"type": "main",
"index": 0
}
]
]
},
"Get Form Values": {
"main": [
[
{
"node": "Trigger Approval Process",
"type": "main",
"index": 0
}
]
]
},
"n8n Form Trigger": {
"main": [
[
{
"node": "Enquiry Classifier",
"type": "main",
"index": 0
}
]
]
},
"Enter Date & Time": {
"main": [
[
{
"node": "Get Form Values",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Enquiry Classifier",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Summarise Enquiry": {
"main": [
[
{
"node": "Wait for Approval",
"type": "main",
"index": 0
}
]
]
},
"Wait for Approval": {
"main": [
[
{
"node": "Has Approval?",
"type": "main",
"index": 0
}
]
]
},
"Enquiry Classifier": {
"main": [
[
{
"node": "Terms & Conditions",
"type": "main",
"index": 0
}
],
[
{
"node": "Decline",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "Summarise Enquiry",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Terms & Conditions": {
"main": [
[
{
"node": "Has Accepted?",
"type": "main",
"index": 0
}
]
]
},
"Execute Workflow Trigger": {
"main": [
[
{
"node": "Summarise Enquiry",
"type": "main",
"index": 0
}
]
]
},
"Trigger Approval Process": {
"main": [
[
{
"node": "Send Receipt",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,636 @@
{
"meta": {
"instanceId": "408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "cbc2ee05-3bb9-4064-ac26-fed7241e673f",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-460,
0
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 6
}
]
}
},
"typeVersion": 1.2
},
{
"id": "4a18dea4-9eda-4b8e-9d0c-fff9793802c5",
"name": "Get Past Events",
"type": "n8n-nodes-base.googleCalendar",
"position": [
-280,
0
],
"parameters": {
"options": {},
"timeMax": "={{ $now.minus({ day: 2 }) }}",
"timeMin": "={{ $now.minus({ day: 4 }) }}",
"calendar": {
"__rl": true,
"mode": "id",
"value": "<your-calendar>"
},
"operation": "getAll"
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "kWMxmDbMDDJoYFVK",
"name": "Google Calendar account"
}
},
"typeVersion": 1.3
},
{
"id": "df2ef6d0-5fcb-43c5-8ba9-2d094dffb4e1",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
200,
40
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "bedc77ad-f0c9-47ae-9609-48ceda47a224",
"name": "Flag to Follow Up",
"type": "n8n-nodes-base.set",
"position": [
580,
200
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{\n{\n ...$('Loop Over Items').first().json,\n followUp: $json.isEmpty()\n}\n}}",
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "b332ca5d-45d5-4a79-a028-baa1728aea78",
"name": "Only Follow Ups",
"type": "n8n-nodes-base.filter",
"position": [
400,
40
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "73f38d1b-75c6-4372-8e81-a2db61b045a8",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1b8a6510-f1c5-4969-a68d-143874b5737d",
"name": "Get Emails Since",
"type": "n8n-nodes-base.gmail",
"position": [
400,
200
],
"webhookId": "08fbccff-cce6-461a-b040-f5a74920c803",
"parameters": {
"limit": 1,
"filters": {
"q": "=(from:{{ $json.attendees.find(attendee => !attendee.self)?.email }} OR to:{{ $json.attendees.find(attendee => !attendee.self)?.email }})",
"receivedAfter": "={{ $json.end.dateTime }}"
},
"resource": "thread"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1,
"alwaysOutputData": true
},
{
"id": "4ce7ac3f-bad8-4822-b166-fd164d733734",
"name": "Output",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1140,
220
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"slots\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"start\": { \"type\": \"string\" },\n \"end\": { \"type\": \"string\" }\n }\n }\n }\n }\n}"
},
"typeVersion": 1.2
},
{
"id": "a22c5b78-d213-4e37-b2c6-f3d1dac96858",
"name": "Availability",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
1020,
220
],
"parameters": {
"options": {
"timezone": {
"__rl": true,
"mode": "id",
"value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Timezone', ``, 'string') }}",
"__regex": "([-+/_a-zA-Z0-9]*)"
}
},
"timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End_Time', ``, 'string') }}",
"timeMin": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start_Time', ``, 'string') }}",
"calendar": {
"__rl": true,
"mode": "id",
"value": "<your-calendar>"
},
"resource": "calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "kWMxmDbMDDJoYFVK",
"name": "Google Calendar account"
}
},
"typeVersion": 1.3
},
{
"id": "690c79d3-cf0e-4d15-9419-dafb7d86025b",
"name": "Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
900,
220
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "4e9d23c0-f9a0-4e71-b1b8-1011313942ba",
"name": "Meeting Availability Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
920,
40
],
"parameters": {
"text": "=### Details of the previous call as following\ntitle: {{ $json.summary }}\ndate: {{ $json.start.dateTime }} {{ $json.start.timeZone }}\nduration: {{ DateTime.fromISO($json.end.dateTime).diffTo(DateTime.fromISO($json.start.dateTime), 'minutes') }} minutes",
"options": {
"systemMessage": "=You are a calendar availability assistant. Analyse the previous meeting and help me find a similar available slot for the next meeting.\n* take into consideration the day, time of day and duration of the previous meeting and try to set the same or similar for the next\n* next meeting should be in the future.\n* return a list of available slots so that I can forward them to the user.\n\nToday's date is {{ $now }}."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "851728bf-7f94-4434-9dc6-23569544cdb7",
"name": "Generate Message",
"type": "n8n-nodes-base.set",
"position": [
1260,
40
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cf09c95c-f25e-4fd7-bade-a0feaeaffb3b",
"name": "message",
"type": "string",
"value": "=Hey, just noticed there wasn't a follow-up email to {{ $('Only Follow Ups').item.json.attendees.find(x => !x.self).email }} after your last call a few days ago.\n\nHere's are a few available slots to book the next call.\n{{\n$json.output.slots\n .filter(slot => !DateTime.fromISO(slot.start).isWeekend())\n .map(slot => `* ${DateTime.fromISO(slot.start).format('cccc, DDD @ hh:mm')} - ${DateTime.fromISO(slot.end).format('hh:mm')}`)\n.join('\\n')\n}}\n\nLet me know which I should book or let me know if it's okay to dismiss."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "7e45eddc-8c34-402a-86a2-ed89ff463095",
"name": "Meetings",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
2360,
240
],
"parameters": {
"end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', ``, 'string') }}",
"start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', ``, 'string') }}",
"calendar": {
"__rl": true,
"mode": "id",
"value": "<your-calendar>"
},
"additionalFields": {
"summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', ``, 'string') }}",
"description": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Description', ``, 'string') }}"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "kWMxmDbMDDJoYFVK",
"name": "Google Calendar account"
}
},
"typeVersion": 1.3
},
{
"id": "74618cf0-1fe5-4abb-ba38-6818162ce826",
"name": "Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
2180,
240
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "790cc7ee-fe1b-434f-8736-38952bffbb85",
"name": "Meeting Booking Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2180,
60
],
"parameters": {
"text": "={{ $json.data.text }}",
"options": {
"systemMessage": "=You are a meeting booking agent. Your task is to book the meeting requested if confirmed by the user or otherwise do nothing if the user wants to disregard. No need to ask for further approval.\n\nAI: {{ $('Generate Message').first().json.message }}"
},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "7ed171b2-08ee-49b0-9f9b-b4943549b2f6",
"name": "Mark as Seen",
"type": "n8n-nodes-base.removeDuplicates",
"position": [
-100,
0
],
"parameters": {
"options": {},
"operation": "removeItemsSeenInPreviousExecutions",
"dedupeValue": "={{ $json.id }}"
},
"typeVersion": 2
},
{
"id": "c8198538-4e02-429d-9fef-4cc2cb0bb7d0",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-540,
-200
],
"parameters": {
"color": 7,
"width": 620,
"height": 420,
"content": "## 1. Get Recent Meetings\n[Learn more about the GCalendar node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlecalendar)\n\nFor this template, a scheduled trigger is set to fire every morning to pull in past meetings from 2-3 days ago. A \"Remove Duplicates\" node ensures we don't double process events more than once between runs."
},
"typeVersion": 1
},
{
"id": "ef4888e2-249f-4501-a731-4dc8886dfa1a",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
100,
-160
],
"parameters": {
"color": 7,
"width": 680,
"height": 600,
"content": "## 2. Check If Any Messages Since\n[Read more about the Gmail node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.gmail)\n\nNext, we want to check if there has been any messages/contact between the lead and the user since the meeting ended. Where there is not, it could be a good opportunity to remind the user to reengage the lead as to not lose them."
},
"typeVersion": 1
},
{
"id": "d9ccc4d5-2ccb-4f85-ada1-6a6fc5374ff2",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
-160
],
"parameters": {
"color": 7,
"width": 620,
"height": 580,
"content": "## 3. Suggest Availability For Next Call\n[Read more about AI Agents](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/)\n\nOnce filtered for applicable leads, we can use an AI Agent to suggest another meeting slot for them. An AI Agent can analyse the previous meeting details and use that information to suggest a similar date and time."
},
"typeVersion": 1
},
{
"id": "851b15f6-ea6a-4d30-a45b-f9ed087a37fa",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1440,
-200
],
"parameters": {
"color": 7,
"width": 540,
"height": 520,
"content": "## 4. Get Human Approval\n[Learn more about n8n's Human-in-the-loop features](https://docs.n8n.io/advanced-ai/examples/human-fallback/)\n\nOf course, we don't want the AI to actually book the meeting unless the user confirms it is something he/she wants to do and the best way to confirm is just to ask the user directly! Thanks for n8n's Human-in-the-loop feature, we can achieve this with a number of messaging protocols.\n\nHere, we're using the Gmail node's **Send-and-wait-for-approval** mode. This will send an email to the user and give them a textbox to tell our agent what they want to do next."
},
"typeVersion": 1
},
{
"id": "725b187f-d59b-4a7d-bf11-6265a4c995ed",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2000,
-160
],
"parameters": {
"color": 7,
"width": 640,
"height": 560,
"content": "## 5. Book the meeting If Accepted\n[Learn more about the AI Agent node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/)\n\nFinally, the response from the user combined with the suggested availability slots are given to another AI agent which can book meetings. If the user accepted and confirmed a date, this agent will book the meeting on behalf of the user. If the user declined, then the agent takes no action."
},
"typeVersion": 1
},
{
"id": "ae59a45a-01e9-42be-99da-f75ed90f881b",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1000,
-700
],
"parameters": {
"width": 420,
"height": 980,
"content": "## Try it out!\n### This n8n template extends the idea of sales leads follow-up reminders by having an AI agent suggest and book the next call or message to reengage the prospect.\n\nWhat makes this template practical for use is that it uses the Human-in-the-loop approach to wait for a user's approval before actually making the booking. Without, this could be annoying for both the user and the recipient!\n\n### How it works\n* A scheduled trigger checks your google calendar for sales meetings which happened a few days ago.\n* For each event, gmail search is used to figure out if a follow-up message has been sent or received from the other party since the meeting. If none, we want to remind ourselves to reengage the lead.\n* For leads applicable for follow-up, we first get an AI Agent to find available meeting slots in the calendar.\n* These slots and reminder are sent to the user via send-and-approval mode of the gmail node. The user replies in natural language either picking a slot, suggesting an entirely new slot or declines the request.\n* When accepted, another AI Agent books the meeting in the calendar with the proposed dates and lead.\n\n### How to use\n* Update all calendar nodes (+subnodes) to point to the right calendar. If this is a shared-purpose calendar, you may need to either filter or create a new calendar.\n* Update the gmail nodes to point to the right accounts.\n\n### Customising the template\n* Not using Google? Swap out for Microsoft or otherwise.\n* Try swapping out or adding in additional send-for-approval methods such as telegram or whatsapp.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!"
},
"typeVersion": 1
},
{
"id": "46ef7220-49ea-4dfc-8e4c-ce7da5119daf",
"name": "Send for Human Approval",
"type": "n8n-nodes-base.gmail",
"position": [
1660,
80
],
"webhookId": "76b88312-1c54-482e-abdd-e699159577f0",
"parameters": {
"sendTo": "=<your-email-here>",
"message": "={{ $json.message }}",
"options": {},
"subject": "=Book a follow-up meeting with {{ $('Only Follow Ups').item.json.attendees.find(x => !x.self).email }}?",
"operation": "sendAndWait",
"responseType": "freeText"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
}
],
"pinData": {},
"connections": {
"Model": {
"ai_languageModel": [
[
{
"node": "Meeting Availability Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Model1": {
"ai_languageModel": [
[
{
"node": "Meeting Booking Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Output": {
"ai_outputParser": [
[
{
"node": "Meeting Availability Agent",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Meetings": {
"ai_tool": [
[
{
"node": "Meeting Booking Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Availability": {
"ai_tool": [
[
{
"node": "Meeting Availability Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Mark as Seen": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Get Past Events": {
"main": [
[
{
"node": "Mark as Seen",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Only Follow Ups",
"type": "main",
"index": 0
}
],
[
{
"node": "Get Emails Since",
"type": "main",
"index": 0
}
]
]
},
"Only Follow Ups": {
"main": [
[
{
"node": "Meeting Availability Agent",
"type": "main",
"index": 0
}
]
]
},
"Generate Message": {
"main": [
[
{
"node": "Send for Human Approval",
"type": "main",
"index": 0
}
]
]
},
"Get Emails Since": {
"main": [
[
{
"node": "Flag to Follow Up",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get Past Events",
"type": "main",
"index": 0
}
]
]
},
"Flag to Follow Up": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Send for Human Approval": {
"main": [
[
{
"node": "Meeting Booking Agent",
"type": "main",
"index": 0
}
]
]
},
"Meeting Availability Agent": {
"main": [
[
{
"node": "Generate Message",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,286 @@
{
"nodes": [
{
"name": "Attendee Registrations",
"type": "n8n-nodes-base.typeformTrigger",
"position": [
400,
300
],
"webhookId": "6314f4db-12ca-4c5e-a6c5-062bb0437734",
"parameters": {
"formId": "RknoIFsl"
},
"credentials": {
"typeformApi": "Typeform Burner Account"
},
"typeVersion": 1
},
{
"name": "Add to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
600,
300
],
"parameters": {
"range": "Attendees!A:F",
"options": {},
"sheetId": "1nlnsTQKGgQZN-Rtd07K9bn0ROm0aFBC2O4kzM2YaTBI",
"operation": "append",
"authentication": "oAuth2"
},
"credentials": {
"googleSheetsOAuth2Api": "google-sheets"
},
"typeVersion": 1
},
{
"name": "Create Account",
"type": "n8n-nodes-base.mattermost",
"position": [
800,
300
],
"parameters": {
"email": "={{$json[\"And what's your email address?\"]}}",
"password": "=P!_{{$json[\"And what's your email address?\"].split(\" \").join(\"\")}}-{{new Date().getHours()}}{{new Date().getDate()}}",
"resource": "user",
"username": "={{$json[\"Great, can we get your full name?\"].split(\" \").join(\"\")}}-{{new Date().getHours()}}",
"operation": "create",
"authService": "email",
"additionalFields": {
"first_name": "={{$json[\"Great, can we get your full name?\"]}}"
}
},
"credentials": {
"mattermostApi": "Mattermost Credentials"
},
"typeVersion": 1
},
{
"name": "Add to team",
"type": "n8n-nodes-base.mattermost",
"position": [
1000,
300
],
"parameters": {
"emails": "={{$node[\"Attendee Registrations\"].json[\"And what's your email address?\"]}}",
"teamId": "ee3ddsn98i8d3xizkcttras5nw",
"resource": "user",
"operation": "invite"
},
"credentials": {
"mattermostApi": "Mattermost Credentials"
},
"typeVersion": 1
},
{
"name": "Array to Rows",
"type": "n8n-nodes-base.function",
"position": [
1200,
300
],
"parameters": {
"functionCode": "const newItems = [];\nfor (let i=0;i<$node[\"Attendee Registrations\"].json[\"Which sessions would you like to attend?\"].length;i++) {\n\tnewItems.push({\n \tjson: {\n \tSession: $node[\"Attendee Registrations\"].json[\"Which sessions would you like to attend?\"][i]\n }\n });\n}\n\nreturn newItems;"
},
"typeVersion": 1
},
{
"name": "Get Session Details",
"type": "n8n-nodes-base.googleSheets",
"position": [
1200,
500
],
"parameters": {
"range": "Sessions!A:F",
"options": {},
"sheetId": "1nlnsTQKGgQZN-Rtd07K9bn0ROm0aFBC2O4kzM2YaTBI",
"authentication": "oAuth2"
},
"credentials": {
"googleSheetsOAuth2Api": "google-sheets"
},
"typeVersion": 1
},
{
"name": "Merge Data",
"type": "n8n-nodes-base.merge",
"position": [
1376,
422
],
"parameters": {
"mode": "mergeByKey",
"propertyName1": "Session",
"propertyName2": "Session"
},
"typeVersion": 1
},
{
"name": "Add to channels",
"type": "n8n-nodes-base.mattermost",
"position": [
1576,
422
],
"parameters": {
"userId": "={{$node[\"Create Account\"].json[\"id\"]}}",
"resource": "channel",
"channelId": "={{$json[\"Mattermost Channel ID\"]}}",
"operation": "addUser"
},
"credentials": {
"mattermostApi": "Mattermost Credentials"
},
"typeVersion": 1
},
{
"name": "Add to Event",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1776,
422
],
"parameters": {
"eventId": "={{$node[\"Merge Data\"].json[\"Google Calendar Event ID\"]}}",
"calendar": "3ne32v2nlrrd2l3624v5qpg6qk@group.calendar.google.com",
"operation": "update",
"updateFields": {
"attendees": [
"={{$node[\"Attendee Registrations\"].json[\"And what's your email address?\"]}}"
]
}
},
"credentials": {
"googleCalendarOAuth2Api": "Google Calendar Credentials"
},
"typeVersion": 1
},
{
"name": "Welcome Email",
"type": "n8n-nodes-base.gmail",
"position": [
1976,
422
],
"parameters": {
"toList": [
"={{$node[\"Attendee Registrations\"].json[\"And what's your email address?\"]}}"
],
"message": "=Dear {{$node[\"Attendee Registrations\"].json[\"Great, can we get your full name?\"]}},\n\nWelcome to n8nConf, the world's largest no-code automation conference!\n\nThis email is to confirm your registration to the following sessions:\n- {{$node[\"Attendee Registrations\"].json[\"Which sessions would you like to attend?\"].join('\\n- ')}}\n\nYou should receive Google Calendar invites to these events on your email. Please consult those for the Google Meet joining information.\n\nYou can also interact with the rest of the community via our Mattermost chat. We created an account just for you!\nLook for the channel corresponding to your session to join the discussion!\n\nLogin URL: https://mm.failedmachine.com/\nUsername: {{$node[\"Create Account\"].json[\"username\"]}}\nPassword: {{$node[\"Create Account\"].parameter[\"password\"]}}\n\nRemember to change your password immediately after your first login!\n\nIf you have any troubles with joining the event, or using the chat rooms; please feel free to let us know on support@n8nconf.com\n\nWe look forward to your participation!\n\nBest,\nTeam n8n",
"subject": "Welcome to n8nConf",
"resource": "message",
"additionalFields": {}
},
"credentials": {
"gmailOAuth2": "gmail"
},
"typeVersion": 1
}
],
"connections": {
"Merge Data": {
"main": [
[
{
"node": "Add to channels",
"type": "main",
"index": 0
}
]
]
},
"Add to team": {
"main": [
[
{
"node": "Array to Rows",
"type": "main",
"index": 0
}
]
]
},
"Add to Event": {
"main": [
[
{
"node": "Welcome Email",
"type": "main",
"index": 0
}
]
]
},
"Add to Sheets": {
"main": [
[
{
"node": "Create Account",
"type": "main",
"index": 0
}
]
]
},
"Array to Rows": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 0
}
]
]
},
"Create Account": {
"main": [
[
{
"node": "Add to team",
"type": "main",
"index": 0
}
]
]
},
"Add to channels": {
"main": [
[
{
"node": "Add to Event",
"type": "main",
"index": 0
}
]
]
},
"Get Session Details": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 1
}
]
]
},
"Attendee Registrations": {
"main": [
[
{
"node": "Add to Sheets",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,152 @@
{
"id": "AvCMhDoSUAYXsrQX",
"meta": {
"instanceId": "14e4c77104722ab186539dfea5182e419aecc83d85963fe13f6de862c875ebfa"
},
"name": "Automate Event Creation in Google Calendar from Google Sheets",
"tags": [],
"nodes": [
{
"id": "b973046b-ff52-464e-8d34-fe57c5b1df7d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-240,
0
],
"parameters": {
"color": 6,
"width": 1200,
"height": 280,
"content": "# Automate Event Creation in Google Calendar from Google Sheets\n"
},
"typeVersion": 1
},
{
"id": "e845b624-6c0a-4d31-aace-cc050f8613dc",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-240,
300
],
"parameters": {
"color": 6,
"width": 1200,
"height": 280,
"content": "## Description \nIn this workflow, we streamline the process of creating events in Google Calendar using event data stored in a Google Sheet through n8n automation. The workflow begins by retrieving the latest event entry from Google Sheets, ensuring that only the most recent event details are processed. Once the event data is fetched, a Function node is used to format the event date so that it aligns with Google Calendar's required format. This step ensures consistency and prevents any date-related errors.\n\nAfter formatting, the workflow sends the structured event details to Google Calendar, where the event is created with essential information such as the event title (summary), description, event date, and location. Additionally, the workflow allows customization by setting the event's status as either \"Busy\" or \"Available,\" helping attendees manage their schedules effectively. Furthermore, a background color can be assigned to the event to enhance visibility and categorization in the calendar.\n\nBy automating this process, the workflow eliminates the need for manual event creation, ensuring seamless synchronization between Google Sheets and Google Calendar. This approach improves efficiency, accuracy, and productivity, making event management effortless."
},
"typeVersion": 1
},
{
"id": "60f2c8b8-a953-4fc1-8751-01d8b7924cb2",
"name": "Event Date Formatter",
"type": "n8n-nodes-base.code",
"position": [
320,
100
],
"parameters": {
"jsCode": "// Get the last item from the input data\nconst lastEvent = items[items.length - 1].json;\n\n// Extract relevant fields\nconst eventName = lastEvent[\"Event Name\"];\nconst eventDescription = lastEvent[\"Event Description\"];\nconst currentYear = new Date().getFullYear(); \n// Get the current year\nconst location = lastEvent[\"Location\"];\n\n// Ensure the date includes the year\nconst formatDateWithYear = (dateStr) => {\n return dateStr.includes(currentYear) ? dateStr : `${dateStr} ${currentYear}`;\n};\n\n// Format the start date\nconst startDateString = formatDateWithYear(lastEvent[\"Event Start Date\"]); // Example: \"11 March 2024\"\n\n// Convert to JavaScript Date object\nconst startDate = new Date(startDateString);\n\n// Convert to ISO format (YYYY-MM-DD)\nconst formattedStartDate = startDate.toISOString().split(\"T\")[0]; // Extract only the date\n\n// Return the last event's formatted data\nreturn [{\n json: {\n eventName,\n eventDescription,\n startDate: formattedStartDate,\n location: location,\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "e27e0d10-71bb-4d01-ba92-5fb8c3195422",
"name": "New Event Entry Listener",
"type": "n8n-nodes-base.googleSheetsTrigger",
"position": [
-120,
100
],
"parameters": {
"event": "rowAdded",
"options": {
"valueRender": "FORMULA"
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
},
{}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1dKjIGmcnQgSEMVuWAAFVDaj_MCBFKBX8hCOk5OH2dK4/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1dKjIGmcnQgSEMVuWAAFVDaj_MCBFKBX8hCOk5OH2dK4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1dKjIGmcnQgSEMVuWAAFVDaj_MCBFKBX8hCOk5OH2dK4/edit?usp=drivesdk",
"cachedResultName": "N8n Event List"
}
},
"typeVersion": 1
},
{
"id": "04864602-bf6a-4def-9bc3-c5ab4b5c8336",
"name": "Google Calendar Event Creator",
"type": "n8n-nodes-base.googleCalendar",
"position": [
700,
100
],
"parameters": {
"end": "={{ $json.startDate }}",
"start": "={{ $json.startDate }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"additionalFields": {
"color": "3",
"allday": "yes",
"summary": "={{ $json.eventName }}",
"location": "={{ $json.location }}",
"showMeAs": "transparent",
"description": "={{ $json.eventDescription }}",
"guestsCanInviteOthers": true
}
},
"typeVersion": 1.3
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "98bd043e-8dce-4eca-a22f-95ff61f07a1f",
"connections": {
"Event Date Formatter": {
"main": [
[
{
"node": "Google Calendar Event Creator",
"type": "main",
"index": 0
}
]
]
},
"New Event Entry Listener": {
"main": [
[
{
"node": "Event Date Formatter",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,954 @@
{
"id": "MMDt8lGtac2oU8nI",
"meta": {
"instanceId": "a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462",
"templateCredsSetupCompleted": true
},
"name": "Build a Chatbot, Voice Agent and Phone Agent with Voiceflow, Google Calendar and RAG",
"tags": [],
"nodes": [
{
"id": "20605948-5277-4fd7-9ba0-63f645bf2dcc",
"name": "n8n_order",
"type": "n8n-nodes-base.webhook",
"position": [
-340,
-140
],
"webhookId": "9ff7a394-5b4b-4790-a96b-c41c4ba27fa5",
"parameters": {
"path": "9ff7a394-5b4b-4790-a96b-c41c4ba27fa5",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "9ef7971e-f679-4d5e-b347-3238d51a06d6",
"name": "Google Calendar",
"type": "n8n-nodes-base.googleCalendar",
"position": [
300,
280
],
"parameters": {
"end": "={{ $json.output.end }}",
"start": "={{ $json.output.start }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "info@n3w.it",
"cachedResultName": "info@n3w.it"
},
"additionalFields": {
"summary": "=Event title with {{ $('n8n_appointment').item.json.query.Email }}",
"description": "Event description"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "8RFK3u13g2PJEGa9",
"name": "Google Calendar account"
}
},
"typeVersion": 1.3
},
{
"id": "17b9f162-c4a3-43ec-b640-a68ebc67b0c9",
"name": "OpenAI Chat Model3",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-120,
480
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "4zwP0MSr8zkNvvV9",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "5b40db3c-6c98-4fea-9c3b-98ba7e13bc30",
"name": "Concert start date",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-80,
280
],
"parameters": {
"text": "=Convert this date to a compatible format for Google Calendar APIs for the start date, and for the end date add 1 hour to the start date.\n\nHere is the start date:\n{{ $json.query.Appointment_date }}",
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.6
},
{
"id": "8931d21a-7c30-40ae-b0b0-1f5f6868b3a3",
"name": "n8n_appointment",
"type": "n8n-nodes-base.webhook",
"position": [
-340,
280
],
"webhookId": "f5edfe92-649b-40da-ab35-f818ccb55ad4",
"parameters": {
"path": "f5edfe92-649b-40da-ab35-f818ccb55ad4",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "fa3e66ca-de09-496b-be14-483b33386e07",
"name": "Retrive Qdrant Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreQdrant",
"position": [
20,
1280
],
"parameters": {
"options": {},
"qdrantCollection": {
"__rl": true,
"mode": "list",
"value": "scarperia",
"cachedResultName": "scarperia"
}
},
"credentials": {
"qdrantApi": {
"id": "iyQ6MQiVaF3VMBmt",
"name": "QdrantApi account"
}
},
"typeVersion": 1
},
{
"id": "ea7be112-1949-47b7-b68b-ae2f3a7b1b71",
"name": "Embeddings OpenAI2",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
-20,
1460
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "4zwP0MSr8zkNvvV9",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "e61ff57f-a109-41e0-87f3-522b1fa78dd6",
"name": "RAG",
"type": "@n8n/n8n-nodes-langchain.toolVectorStore",
"position": [
180,
1080
],
"parameters": {
"name": "company_data",
"description": "Retrive data about company knowledge from vector store"
},
"typeVersion": 1
},
{
"id": "fce158b8-73a3-42c1-baf3-9f2ae979fe15",
"name": "OpenAI Chat Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-20,
1080
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "4zwP0MSr8zkNvvV9",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "e2bcfa68-3642-4e49-89cb-e08faade984c",
"name": "OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
340,
1300
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "4zwP0MSr8zkNvvV9",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "2a79c66c-040b-4ca2-ad91-a0683d0d2996",
"name": "Retrive Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
60,
860
],
"parameters": {
"text": "={{ $json.query.Question }}",
"agent": "conversationalAgent",
"options": {
"systemMessage": "You are an AI-powered assistant for an electronics store. Your primary goal is to assist customers by providing accurate and helpful information about products, troubleshooting tips, and general support. Use the provided knowledge base (retrieved documents) to answer questions with precision and professionalism.\n\n**Guidelines**:\n1. **Product Information**:\n - Provide detailed descriptions of products, including specifications, features, and compatibility.\n - Highlight key selling points and differences between similar products.\n - Mention availability, pricing, and promotions if applicable.\n\n2. **Technical Support**:\n - Offer step-by-step troubleshooting guides for common issues.\n - Suggest solutions for setup, installation, or configuration problems.\n - If the issue is complex, recommend contacting the stores support team for further assistance.\n\n3. **Customer Service**:\n - Respond politely and professionally to all inquiries.\n - If a question is unclear, ask for clarification to provide the best possible answer.\n - For order-related questions (e.g., status, returns, or cancellations), guide customers on how to proceed using the stores systems.\n\n4. **Knowledge Base Usage**:\n - Always reference the provided knowledge base (retrieved documents) to ensure accuracy.\n - If the knowledge base does not contain relevant information, inform the customer and suggest alternative resources or actions.\n\n5. **Tone and Style**:\n - Use a friendly, approachable, and professional tone.\n - Avoid technical jargon unless the customer demonstrates familiarity with the topic.\n - Keep responses concise but informative.\n\n**Example Interactions**:\n1. **Product Inquiry**:\n - Customer: \"Whats the difference between the XYZ Smartwatch and the ABC Smartwatch?\"\n - AI: \"The XYZ Smartwatch features a longer battery life (up to 7 days) and built-in GPS, while the ABC Smartwatch has a brighter AMOLED display and supports wireless charging. Both are compatible with iOS and Android devices. Would you like more details on either product?\"\n\n2. **Technical Support**:\n - Customer: \"My wireless router isnt connecting to the internet.\"\n - AI: \"Please try the following steps: 1) Restart your router and modem. 2) Ensure all cables are securely connected. 3) Check if the routers LED indicators show a stable connection. If the issue persists, you may need to reset the router to factory settings. Would you like a detailed guide for resetting your router?\"\n\n3. **Customer Service**:\n - Customer: \"How do I return a defective product?\"\n - AI: \"To return a defective product, please visit our Returns Portal on our website and enter your order number. Youll receive a return label and instructions. If you need further assistance, our support team is available at support@electronicsstore.com.\"\n\n**Limitations**:\n- If the question is outside the scope of the knowledge base or requires human intervention, inform the customer and provide contact details for the appropriate department.\n- Do not provide speculative or unverified information. Always rely on the knowledge base or direct the customer to official resources."
},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "be516c9c-d2fb-4dea-9a3b-9674be5ea689",
"name": "n8n_rag",
"type": "n8n-nodes-base.webhook",
"position": [
-360,
860
],
"webhookId": "edb1e894-1210-4902-a34f-a014bbdad8d8",
"parameters": {
"path": "edb1e894-1210-4902-a34f-a014bbdad8d8",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "2412721d-7353-4a27-8068-5c90872c7a51",
"name": "Tracking response",
"type": "n8n-nodes-base.set",
"position": [
360,
-140
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "86f332ff-7b89-4dd4-8df9-06c081625d33",
"name": "text",
"type": "string",
"value": "=Your order status is: {{ $json.status }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "4965d781-1452-42c9-8a84-baacb5abe97f",
"name": "Calendar response",
"type": "n8n-nodes-base.set",
"position": [
500,
280
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0fe6fe50-9263-479a-ab01-ca1d15ce2412",
"name": "text",
"type": "string",
"value": "L'evento è stato creato con successo"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "5311be28-2878-41ce-a70f-4e4aebcea0f9",
"name": "Webhook tracking response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
-140
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "84d8558f-e6fd-400e-ae2e-0b5fec309561",
"name": "API URL Tracking",
"type": "n8n-nodes-base.httpRequest",
"position": [
20,
-140
],
"parameters": {
"url": "URL_TRACKING",
"options": {},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "Order number",
"value": "={{ $json.Order_number }}"
},
{
"name": "Email",
"value": "={{ $json.Order_number }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "32eb8645-c56e-4db4-8870-f28161cba048",
"name": "Webhook calendar response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
280
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "72e7f085-d1e7-4967-aaa5-161ff0e83c06",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
140,
480
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"start\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n\t\t\"end\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n\t}\n}"
},
"typeVersion": 1.2
},
{
"id": "3822b875-73f0-4700-8fc4-e4d3285f593a",
"name": "Webhook RAG response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
860
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "0b43f63b-3c00-4db4-8b28-9938add9fdbe",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1100,
-1320
],
"parameters": {
"width": 1140,
"height": 2200,
"content": "# STEP 6 - VOICEFLOW\n\n- Register on [Voiceflow](https://www.voiceflow.com/) \n- Create the workflow as shown in the following image\n![image](https://i.postimg.cc/3rSPwMn2/langflow.png)\n- There are 3 \"Captures\":\n-- n8n_order\n-- n8n_appointment\n-- n8n_rag\n- Add in the created functions the url of the corresponding n8n Webhook trigger node\n- Test your Agent\n- Get your projectID\n- In the Widget section choose Chat or Voice and copy the installation script\n![image](https://i.postimg.cc/855gyTZP/voiceflow-agent.png)\n![image](https://i.postimg.cc/5Nn4Sk43/voiceflow-agent2.png)\n\nPS. You can import a Twilio number to assign it to your agent for becoming a Phone Agent\n![image](https://i.postimg.cc/cLymTTFv/voiceflow-agent3.png)\n\n"
},
"typeVersion": 1
},
{
"id": "589165c8-920d-40e3-8e28-50e94dd37555",
"name": "When clicking Test workflow",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-380,
-1120
],
"parameters": {},
"typeVersion": 1
},
{
"id": "74c314bb-c445-42f8-8f9d-2ab646486044",
"name": "Qdrant Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreQdrant",
"position": [
600,
-1000
],
"parameters": {
"mode": "insert",
"options": {},
"qdrantCollection": {
"__rl": true,
"mode": "id",
"value": "="
}
},
"credentials": {
"qdrantApi": {
"id": "iyQ6MQiVaF3VMBmt",
"name": "QdrantApi account"
}
},
"typeVersion": 1
},
{
"id": "01c05ac3-ac5c-4f1a-a756-db8de4a30e56",
"name": "Create collection",
"type": "n8n-nodes-base.httpRequest",
"position": [
-80,
-1260
],
"parameters": {
"url": "https://QDRANTURL/collections/COLLECTION",
"method": "POST",
"options": {},
"jsonBody": "{\n \"filter\": {}\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "qhny6r5ql9wwotpn",
"name": "Qdrant API (Hetzner)"
}
},
"typeVersion": 4.2
},
{
"id": "2d7adb45-aae7-4617-b1d1-5a23f3eb3b20",
"name": "Refresh collection",
"type": "n8n-nodes-base.httpRequest",
"position": [
-80,
-1000
],
"parameters": {
"url": "https://QDRANTURL/collections/COLLECTION/points/delete",
"method": "POST",
"options": {},
"jsonBody": "{\n \"filter\": {}\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "qhny6r5ql9wwotpn",
"name": "Qdrant API (Hetzner)"
}
},
"typeVersion": 4.2
},
{
"id": "5e406bd7-8a93-4db2-8d3d-e92e8c9f4f01",
"name": "Get folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
140,
-1000
],
"parameters": {
"filter": {
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"folderId": {
"__rl": true,
"mode": "id",
"value": "=test-whatsapp"
}
},
"options": {},
"resource": "fileFolder"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "HEy5EuZkgPZVEa9w",
"name": "Google Drive account (n3w.it)"
}
},
"typeVersion": 3
},
{
"id": "f1f883fb-c9d1-42e6-98c2-791ed85e959f",
"name": "Download Files",
"type": "n8n-nodes-base.googleDrive",
"position": [
360,
-1000
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {
"googleFileConversion": {
"conversion": {
"docsToFormat": "text/plain"
}
}
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "HEy5EuZkgPZVEa9w",
"name": "Google Drive account (n3w.it)"
}
},
"typeVersion": 3
},
{
"id": "5fd88e03-3638-4d38-8df4-246e4a5f2bda",
"name": "Embeddings OpenAI",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
580,
-800
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "4zwP0MSr8zkNvvV9",
"name": "OpenAi account"
}
},
"typeVersion": 1.1
},
{
"id": "3740a841-e272-44f9-b76d-51fb90137fd3",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
760,
-800
],
"parameters": {
"options": {},
"dataType": "binary"
},
"typeVersion": 1
},
{
"id": "075d1038-d1fd-4527-8eda-961f20c7869a",
"name": "Token Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterTokenSplitter",
"position": [
760,
-600
],
"parameters": {
"chunkSize": 300,
"chunkOverlap": 30
},
"typeVersion": 1
},
{
"id": "57cc8eaf-26b3-480f-ab5d-c8646519cfa3",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
120,
-1320
],
"parameters": {
"color": 6,
"width": 880,
"height": 220,
"content": "# STEP 1\n\n## Create Qdrant Collection\nChange:\n- QDRANTURL\n- COLLECTION"
},
"typeVersion": 1
},
{
"id": "70bc0676-c0ea-4de8-8659-bfb8b0ea653f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
-1060
],
"parameters": {
"color": 4,
"width": 620,
"height": 400,
"content": "# STEP 2\n\n\n\n\n\n\n\n\n\n\n\n\n## Documents vectorization with Qdrant and Google Drive\nChange:\n- QDRANTURL\n- COLLECTION"
},
"typeVersion": 1
},
{
"id": "411c4f55-ae41-49b5-a821-df1a3d8fefec",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-380,
660
],
"parameters": {
"color": 5,
"width": 1220,
"content": "# STEP 5\nIf required retrive the informations by RAG system"
},
"typeVersion": 1
},
{
"id": "49d1fe78-4c38-4508-84c3-3a571ad9a2b0",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-360,
-360
],
"parameters": {
"color": 5,
"width": 1220,
"content": "# STEP 3\nIf required retrive the informations by Order system\n- Set your API URL Tracking service"
},
"typeVersion": 1
},
{
"id": "23d42754-0126-4b3a-91b0-b489ef83b36c",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-360,
80
],
"parameters": {
"color": 5,
"width": 1220,
"content": "# STEP 4\nIf required retrive the informations by Appointment system"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "20a19983-4edb-4179-a2d2-e2f53d0daf85",
"connections": {
"RAG": {
"ai_tool": [
[
{
"node": "Retrive Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"n8n_rag": {
"main": [
[
{
"node": "Retrive Agent",
"type": "main",
"index": 0
}
]
]
},
"n8n_order": {
"main": [
[
{
"node": "API URL Tracking",
"type": "main",
"index": 0
}
]
]
},
"Get folder": {
"main": [
[
{
"node": "Download Files",
"type": "main",
"index": 0
}
]
]
},
"Retrive Agent": {
"main": [
[
{
"node": "Webhook RAG response",
"type": "main",
"index": 0
}
]
]
},
"Download Files": {
"main": [
[
{
"node": "Qdrant Vector Store",
"type": "main",
"index": 0
}
]
]
},
"Token Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"Google Calendar": {
"main": [
[
{
"node": "Calendar response",
"type": "main",
"index": 0
}
]
]
},
"n8n_appointment": {
"main": [
[
{
"node": "Concert start date",
"type": "main",
"index": 0
}
]
]
},
"API URL Tracking": {
"main": [
[
{
"node": "Tracking response",
"type": "main",
"index": 0
}
]
]
},
"Calendar response": {
"main": [
[
{
"node": "Webhook calendar response",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI": {
"ai_embedding": [
[
{
"node": "Qdrant Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Tracking response": {
"main": [
[
{
"node": "Webhook tracking response",
"type": "main",
"index": 0
}
]
]
},
"Concert start date": {
"main": [
[
{
"node": "Google Calendar",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI2": {
"ai_embedding": [
[
{
"node": "Retrive Qdrant Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "RAG",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Chat Model2": {
"ai_languageModel": [
[
{
"node": "Retrive Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Chat Model3": {
"ai_languageModel": [
[
{
"node": "Concert start date",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Refresh collection": {
"main": [
[
{
"node": "Get folder",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Qdrant Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Concert start date",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Retrive Qdrant Vector Store": {
"ai_vectorStore": [
[
{
"node": "RAG",
"type": "ai_vectorStore",
"index": 0
}
]
]
},
"When clicking Test workflow": {
"main": [
[
{
"node": "Create collection",
"type": "main",
"index": 0
},
{
"node": "Refresh collection",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,225 @@
{
"id": "O2R3U22TB968fWUo",
"meta": {
"instanceId": "cb484ba7b742928a2048bf8829668bed5b5ad9787579adea888f05980292a4a7"
},
"name": "Generate google meet links in slack",
"tags": [
{
"id": "GkyPPgldsTmLDY6O",
"name": "createdBy:JC",
"createdAt": "2024-02-29T21:51:58.448Z",
"updatedAt": "2024-02-29T21:51:58.448Z"
}
],
"nodes": [
{
"id": "5577aaf6-f682-49c3-9d21-f819151f77c5",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
300,
480
],
"webhookId": "f442a7bb-451e-4371-8b7a-614caa0e04dd",
"parameters": {
"path": "slack-meet-trigger",
"options": {},
"httpMethod": "POST",
"responseData": "noData",
"responseMode": "lastNode"
},
"typeVersion": 1.1
},
{
"id": "018c32c7-c3eb-4679-8064-ab92bb62cac5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
140,
142
],
"parameters": {
"color": 6,
"width": 463.09809221779403,
"height": 482.56534054190786,
"content": "### 1. Setup: Add a Slack App\n**a.** Visit https://api.slack.com/apps, click on `New App` and choose a name and workspace.\n**b.** Click on `OAuth & Permissions` and scroll down to Scopes -> Bot token Scopes\n**c.** Add the `chat:write` scope & `chat:write.public`\n**d.** Navigate to `Slash Commands` and click `Create New Command`\n**e.** Use `/meet` as the command\n**f.** Copy the production URL from the **Webhook** node into `Request URL` within your slash command\n**g.** Add relevant description and usage hint\n**h.** Go to `Install app` and click install\n**i.** Don't worry about app distribution, that's only if you're trying to publish an app on the slack store"
},
"typeVersion": 1
},
{
"id": "3bfa07d4-ef3e-4ec4-91a2-ca94e2346299",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
240
],
"parameters": {
"color": 6,
"width": 291.779972644588,
"height": 192.66150688057675,
"content": "### 2. Setup: Google auth & calendar\n**a.** Visit [the docs](https://docs.n8n.io/integrations/builtin/credentials/google/oauth-single-service/) and follow the steps to setup Google auth credential\n**b.** Choose the calendar you wish to create google meet links from\n\n\n\n👇"
},
"typeVersion": 1
},
{
"id": "aab60499-7123-43c0-8f99-d0eade0f5672",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
238
],
"parameters": {
"color": 6,
"width": 292.3392628968803,
"height": 192.92455101677126,
"content": "### 3. Setup: Configure slack node authentication and your message\n**a.** Connect your slack account\n**b.** Configure your message text. Be sure to include the hangoutLink expression to output a meeting link\n\n👇"
},
"typeVersion": 1
},
{
"id": "a15fc232-ec8e-4dfb-add7-2a3c27c5a232",
"name": "Create event with google meet link",
"type": "n8n-nodes-base.googleCalendar",
"position": [
740,
480
],
"parameters": {
"end": "={{ $now.plus({minutes: 15}) }}",
"start": "={{ $now }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": ""
},
"additionalFields": {
"conferenceDataUi": {
"conferenceDataValues": {
"conferenceSolution": "hangoutsMeet"
}
}
}
},
"typeVersion": 1
},
{
"id": "57c2d5b8-f5d7-4db1-9e13-48265d174679",
"name": "Send msg with Google meet link",
"type": "n8n-nodes-base.slack",
"position": [
1060,
480
],
"parameters": {
"text": "=Join me here: {{ $('Create event with google meet link').item.json.hangoutLink }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Webhook').item.json.body.channel_id }}"
},
"otherOptions": {
"unfurl_links": false,
"includeLinkToWorkflow": false
}
},
"typeVersion": 2.1
},
{
"id": "898b9681-c532-490e-aea2-a4f693b52f35",
"name": "Delete temporary calendar event",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1400,
480
],
"parameters": {
"eventId": "={{ $('Create event with google meet link').item.json[\"id\"] }}",
"options": {},
"calendar": {
"__rl": true,
"mode": "list",
"value": ""
},
"operation": "delete"
},
"typeVersion": 1
},
{
"id": "ec70003a-6dea-4c1b-a16e-e64a206aba16",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
140,
-20
],
"parameters": {
"color": 4,
"width": 459.2991776576996,
"height": 146.4269155371431,
"content": "## Generate google meet links with a slack command \nSpin up instant google meet links directly from slack and send to all channel participants\n\n"
},
"typeVersion": 1
},
{
"id": "eee48232-8477-4bfb-8164-bfaf66062071",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1280,
240
],
"parameters": {
"color": 6,
"width": 292.3392628968803,
"height": 192.92455101677126,
"content": "### 3. Setup: Select google calendar account\n**a.** Select the same calendar you're using to create the initial event\n\n\n\n\n👇"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "09457e4b-ccba-497f-b046-3529edc7b332",
"connections": {
"Webhook": {
"main": [
[
{
"node": "Create event with google meet link",
"type": "main",
"index": 0
}
]
]
},
"Send msg with Google meet link": {
"main": [
[
{
"node": "Delete temporary calendar event",
"type": "main",
"index": 0
}
]
]
},
"Create event with google meet link": {
"main": [
[
{
"node": "Send msg with Google meet link",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,737 @@
{
"meta": {
"instanceId": "408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9"
},
"nodes": [
{
"id": "76589d1c-45f3-4a89-906f-8ef300d34964",
"name": "n8n Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
-2520,
-280
],
"webhookId": "5e7637dd-d222-4786-8cdc-7b66cebc1481",
"parameters": {
"path": "schedule_appointment",
"options": {
"ignoreBots": true,
"appendAttribution": true,
"useWorkflowTimezone": true
},
"formTitle": "Schedule an Appointment",
"formFields": {
"values": [
{
"fieldLabel": "Your Name",
"placeholder": "eg. Sam Smith",
"requiredField": true
},
{
"fieldType": "email",
"fieldLabel": "Email",
"placeholder": "eg. sam@example.com",
"requiredField": true
},
{
"fieldType": "textarea",
"fieldLabel": "Enquiry",
"placeholder": "eg. I'm looking for...",
"requiredField": true
}
]
},
"formDescription": "Welcome to Jim's Appointment Form.\nBefore we set a date, please tell me a little about yourself and how I can help."
},
"typeVersion": 2.1
},
{
"id": "194b7073-fa33-4e75-85ed-c02724c8075c",
"name": "Form End",
"type": "n8n-nodes-base.form",
"position": [
-420,
-260
],
"webhookId": "8fcc907b-bc2e-4fdf-a829-82c83e677724",
"parameters": {
"options": {
"formTitle": "Appointment Request Sent!"
},
"operation": "completion",
"completionTitle": "Appointment Request Sent!",
"completionMessage": "=Thank you for submitting an appointment request. A confirmation of this request will be sent to your inbox. I'll get back to you shortly with a confirmation of the appointment.\n\nHere is the summary of the appointment request.\n\nName: {{ $('Get Form Values').item.json.name }}\nDate & Time: {{ DateTime.fromISO($('Get Form Values').item.json.dateTime).format('EEE, dd MMM @ t') }}\nEnquiry: {{ $('Get Form Values').item.json.enquiry.trim() }}\n"
},
"typeVersion": 1
},
{
"id": "688ea2cc-b595-4b6f-9214-d5dfd3893172",
"name": "Enter Date & Time",
"type": "n8n-nodes-base.form",
"position": [
-1260,
-320
],
"webhookId": "0cd03415-66f8-4c82-8069-5bfd8ea310bd",
"parameters": {
"options": {
"formTitle": "Enter a Date & Time",
"formDescription": "=Please select a date and time"
},
"defineForm": "json",
"jsonOutput": "={{\n[\n {\n \"fieldLabel\":\"Date\",\n \"requiredField\":true,\n \"fieldType\": \"dropdown\",\n \"fieldOptions\":\n Array(5).fill(0)\n .map((_,idx) => $now.plus(idx+1, 'day'))\n .filter(d => !d.isWeekend)\n .map(d => ({ option: d.format('EEE, d MMM') }))\n },\n {\n \"fieldLabel\": \"Time\",\n \"requiredField\": true,\n \"fieldType\": \"dropdown\",\n \"fieldOptions\": [\n { \"option\": \"9:00 am\" },\n { \"option\": \"10:00 am\" },\n { \"option\": \"11:00 am\" },\n { \"option\": \"12:00 pm\" },\n { \"option\": \"1:00 pm\" },\n { \"option\": \"2:00 pm\" },\n { \"option\": \"3:00 pm\" },\n { \"option\": \"4:00 pm\" },\n { \"option\": \"5:00 pm\" },\n { \"option\": \"6:00 pm\" }\n ]\n }\n]\n}}"
},
"typeVersion": 1
},
{
"id": "602c40f9-ab11-4908-aab3-1a199126e097",
"name": "Get Form Values",
"type": "n8n-nodes-base.set",
"position": [
-900,
-260
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{\n{\n name: $('n8n Form Trigger').first().json['Your Name'],\n email: $('n8n Form Trigger').first().json.Email,\n enquiry: $('n8n Form Trigger').first().json.Enquiry,\n dateTime: DateTime.fromFormat(`${$json.Date} ${$json.Time}`, \"EEE, dd MMM t\"),\n submittedAt: $('n8n Form Trigger').first().json.submittedAt,\n}\n}}"
},
"typeVersion": 3.4
},
{
"id": "21f93645-5e27-4e9f-a72c-47a39e42a79c",
"name": "Terms & Conditions",
"type": "n8n-nodes-base.form",
"position": [
-1680,
-240
],
"webhookId": "dcf32f99-8fb7-457a-8a58-ac1a018b1873",
"parameters": {
"options": {
"formTitle": "Before we continue...",
"formDescription": "=Terms and Conditions for Booking an Appointment\n\nNon-Binding Nature of Discussions:\nAny information shared, discussed, or agreed upon during the call is non-binding and provisional. No agreement, service, or commitment shall be considered confirmed unless explicitly documented and agreed to in writing.\n\nProhibition of Recording and Note-Taking Tools:\nBy proceeding with the appointment, the user agrees not to use AI assistants, note-taking applications, recording devices, or any other technology to record or transcribe the conversation, whether manually or automatically. This is to ensure confidentiality and respect for the integrity of the discussion.\n\nConfirmation of Understanding:\nBy booking this appointment, you acknowledge and accept these terms and conditions in full."
},
"formFields": {
"values": [
{
"fieldType": "dropdown",
"fieldLabel": "Please select",
"multiselect": true,
"fieldOptions": {
"values": [
{
"option": "I accept the terms and conditions"
}
]
},
"requiredField": true
}
]
}
},
"typeVersion": 1
},
{
"id": "22e03fec-bd56-4fc3-864a-f1e81a864cb5",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-2340,
-140
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "8b4e9bba-cd57-46af-8042-4b47e5ebcd82",
"name": "Has Accepted?",
"type": "n8n-nodes-base.if",
"position": [
-1500,
-240
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "bc7c3e99-e610-4997-82a7-4851f2c04c19",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json[\"Please select\"] }}",
"rightValue": "I accept"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "627a4c00-e831-4a77-8aad-f417f0f8e6dd",
"name": "Send Receipt",
"type": "n8n-nodes-base.gmail",
"position": [
-580,
-260
],
"webhookId": "5f590407-4ab9-4ae6-bb85-38dbe41d6dce",
"parameters": {
"sendTo": "={{ $('Get Form Values').first().json.email }}",
"message": "=<p>Dear {{ $('Get Form Values').first().json.name }},</p>\n<p>Thanks for requesting an appointment. We will review and get back to you shortly.</p>\n<p>Here is the summary of the request that was sent:</p>\n<p>\nName: {{ $('Get Form Values').first().json.name }}<br/>\nEmail: {{ $('Get Form Values').first().json.email }}<br/>\nEnquiry: {{ $('Get Form Values').first().json.enquiry }}<br/>\nSubmitted at: {{ $('Get Form Values').first().json.submittedAt }}\n</p>\n",
"options": {},
"subject": "=Appointment Request Received for {{ DateTime.fromISO($('Get Form Values').first().json.dateTime).format('EEE, dd MMM @ t') }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "91d3dd7d-53f8-4f8e-9af2-ec54cf7f42ad",
"name": "Wait for Approval",
"type": "n8n-nodes-base.gmail",
"position": [
340,
-260
],
"webhookId": "ab9c6c5e-334d-44bb-a8fd-a58140bc680d",
"parameters": {
"sendTo": "=admin@example.com",
"message": "=<h2>A new appointment request was submitted!</h2>\n<p>\nRequesting appointment date is <strong>{{ DateTime.fromISO($('Execute Workflow Trigger').item.json.dateTime).format('EEE, dd MMM @ t') }}</strong>.\n</p>\n<p>\nName: {{ $('Execute Workflow Trigger').first().json.name }}<br/>\nEmail: {{ $('Execute Workflow Trigger').first().json.email }}<br/>\nEnquiry Summary: {{ $json.text }}<br/>\nSubmitted at: {{ $('Execute Workflow Trigger').first().json.submittedAt }}\n</p>",
"subject": "New Appointment Request!",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"approveLabel": "Confirm"
}
}
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "7a02b57b-b9b1-45b1-9b3d-aebb84259875",
"name": "Has Approval?",
"type": "n8n-nodes-base.if",
"position": [
520,
-260
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e5e37acb-9e9d-4a9e-bf59-a35dfc035886",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "96aab8be-4c5e-4e14-a6ea-6d2b743551be",
"name": "OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
0,
-120
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "6f2b5454-70a3-4391-b785-bb871c3e2081",
"name": "Create Appointment",
"type": "n8n-nodes-base.googleCalendar",
"position": [
720,
-340
],
"parameters": {
"end": "={{ DateTime.fromISO($('Execute Workflow Trigger').first().json.dateTime).plus(30, 'minute').toISO() }}",
"start": "={{ $('Execute Workflow Trigger').first().json.dateTime }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "c_5792bdf04bc395cbcbc6f7b754268245a33779d36640cc80a357711aa2f09a0a@group.calendar.google.com",
"cachedResultName": "n8n-events"
},
"additionalFields": {
"summary": "=Appointment Scheduled - {{ $('Execute Workflow Trigger').item.json.name }} & Jim",
"attendees": [
"={{ $('Execute Workflow Trigger').item.json.email }}"
],
"description": "={{ $('Summarise Enquiry').first().json.text }}\n\nOriginal message:\n> {{ $('Execute Workflow Trigger').item.json.enquiry }}",
"conferenceDataUi": {
"conferenceDataValues": {
"conferenceSolution": "hangoutsMeet"
}
}
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "kWMxmDbMDDJoYFVK",
"name": "Google Calendar account"
}
},
"typeVersion": 1.2
},
{
"id": "e6881867-5b3c-4b85-b06a-a0a3c01be227",
"name": "Send Rejection",
"type": "n8n-nodes-base.gmail",
"position": [
720,
-180
],
"webhookId": "5f590407-4ab9-4ae6-bb85-38dbe41d6dce",
"parameters": {
"sendTo": "={{ $('Execute Workflow Trigger').first().json.email }}",
"message": "=<p>Dear {{ $('Execute Workflow Trigger').first().json.name }},</p>\n<p>Unfortunately, we cannot schedule the requested appointment at the requested time.</p>\n<p>Kind regards</p>\n",
"options": {},
"subject": "=Appointment Request Rejected for {{ DateTime.fromISO($('Execute Workflow Trigger').first().json.dateTime).format('EEE, dd MMM @ t') }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Sf5Gfl9NiFTNXFWb",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "40785eca-943c-45f6-b4a9-0c95538621ed",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2580,
-555.2889298043726
],
"parameters": {
"color": 7,
"width": 763.0427617951669,
"height": 611.898918296892,
"content": "## 1. Qualify Enquiries Using AI\n[Learn more about the text classifier](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/)\n\nWith n8n's multi-forms, you\u2019re no longer stuck creating long, overwhelming forms. Instead, you have more flexibility and control to design smarter, more engaging form experiences.\n\nIn this demo, we\u2019ll explore an appointment request scenario where a user wants to schedule a call to discuss their inquiry. However, not all inquiries require a meeting, making it a perfect use case for AI to pre-qualify the request. We can handle this validation using the text classifier node."
},
"typeVersion": 1
},
{
"id": "985be8d1-e77a-475b-9ac2-dba163dbd950",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1800,
-549.8684464902185
],
"parameters": {
"color": 7,
"width": 781.472405063291,
"height": 606.0718987341766,
"content": "## 2. Split Form For Better User Experience\n[Learn more about the forms](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.form)\n\nOnboarding is a great reason to split your big form into smaller ones. Taking the user through a step by step process ensures a smooth experience and keeps them engaged throughout.\n\nHere, we take the opportunity of the extra context space to display a terms and conditions which the user must agree to making their request. The next form then asks for desired date and time of the event."
},
"typeVersion": 1
},
{
"id": "9b0a3f0e-e15d-4d0e-b620-1acc78bf812c",
"name": "Decline",
"type": "n8n-nodes-base.form",
"position": [
-2020,
-160
],
"webhookId": "4353eadb-b7a0-45f2-8dd8-5f6cd882d8d8",
"parameters": {
"options": {},
"operation": "completion",
"completionTitle": "Send me a DM Instead!",
"completionMessage": "Thanks for your enquiry but it may not necessarily need an appointment. Please feel free to email me instead at jim@example.com."
},
"typeVersion": 1
},
{
"id": "fcd3eb7d-6389-4c07-97cc-275ae387c963",
"name": "Decline1",
"type": "n8n-nodes-base.form",
"position": [
-1260,
-160
],
"webhookId": "4353eadb-b7a0-45f2-8dd8-5f6cd882d8d8",
"parameters": {
"options": {},
"operation": "completion",
"completionTitle": "Send me a DM Instead!",
"completionMessage": "Thanks for your enquiry but it may not necessarily need an appointment. Please feel free to email me instead at jim@example.com."
},
"typeVersion": 1
},
{
"id": "d89427cb-fffb-4aa4-b55c-b315fa0e92be",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1000,
-498.80432681242814
],
"parameters": {
"color": 7,
"width": 792.9401150747982,
"height": 497.4250863060987,
"content": "## 3. Send Acknowledgement to User and Start Approval Process\n[Learn more about the Gmail node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.gmail/)\n\nOnce all form steps are concluded, we can send a notification to the requester via email and in the background, trigger another email to the admin to initiate the approval process. The approval process works in a separate execution so doesn't interrupt the user's form experience."
},
"typeVersion": 1
},
{
"id": "041081e1-ee98-4b40-aa14-1980b23f4031",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
-620
],
"parameters": {
"color": 7,
"width": 609.4228768699652,
"height": 287.178089758343,
"content": "## 4. Approve or Decline Appointment\n[Learn more about the Waiting for Approval](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.gmail/message-operations/#send-a-message-and-wait-for-approval)\n\nThe Wait for Approval feature for Gmail is a special operation which allows for human-in-the-loop interaction in n8n workflows. In this example, the human interaction is the approval of the appointment request. The feature will put the workflow in a waiting state where a message is sent to the admin with 2 buttons: confirm and decline.\n\nWhen the admin clicks on the confirm button, the workflow resumes from the Gmail node and a meeting event is created for the requesting user in Google Calendar.\n\nWhen declined, a rejection email is sent to the requester instead."
},
"typeVersion": 1
},
{
"id": "d6af0f50-234f-46ca-aa41-7f3891aff8a3",
"name": "Trigger Approval Process",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
-740,
-260
],
"parameters": {
"mode": "each",
"options": {
"waitForSubWorkflow": false
},
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $workflow.id }}"
}
},
"typeVersion": 1.1
},
{
"id": "e524d6df-9b6d-4d61-8e71-08a0d3a751d7",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
-160,
-260
],
"parameters": {},
"typeVersion": 1
},
{
"id": "74dccbc1-7728-4336-a18a-2541007fd369",
"name": "Summarise Enquiry",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
0,
-260
],
"parameters": {
"text": "=The enquiry is as follows:\n{{ $('Execute Workflow Trigger').first().json.enquiry.substring(0, 500) }}",
"messages": {
"messageValues": [
{
"message": "Summarise the given enquiry"
}
]
},
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "b74f0f5a-39f0-4db3-beba-03caf981c5d2",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3080,
-640
],
"parameters": {
"width": 468.6766398158801,
"height": 690.6653164556957,
"content": "## Try it out!\n\n### This n8n template is a simple appointment scheduling workflow using n8n forms with AI thrown in the mix for good measure. It also uses n8n's wait for approval feature which allows the ability to confirm appointment requests and create events in Google Calendar.\n\n### How it works\n* We start with a form trigger which asks for the purpose of the appointment.\n* Instantly, we can qualify this by using a text classifier node which uses AI's contextual understanding to ensure the appointment is worthwhile. If not, an alternative is suggested instead.\n* Multi-page forms are then used to set the terms of the appointment and ask the user for a desired date and time.\n* An acknowledgement is sent to the user while an approval by email process is triggered in the background.\n* In a subworkflow, we use Gmail with the wait for approval operation to send an approval form to the admin user who can either confirm or decline the appointment request.\n* When approved, a Google Calendar event is created. When declined, the user is notified via email that the appointment request was declined.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!\n"
},
"typeVersion": 1
},
{
"id": "d3c87dfa-d6e5-402a-89e5-6d8f93b824a6",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
299,
-280
],
"parameters": {
"width": 177.66444188722656,
"height": 257.56869965477557,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### \ud83d\udea8 Set your admin email here!"
},
"typeVersion": 1
},
{
"id": "6351121d-6ebe-432d-b370-13296fd58e1a",
"name": "Enquiry Classifier",
"type": "@n8n/n8n-nodes-langchain.textClassifier",
"position": [
-2340,
-280
],
"parameters": {
"options": {
"fallback": "other"
},
"inputText": "={{ $json.Enquiry }}",
"categories": {
"categories": [
{
"category": "relevant enquiry",
"description": "Enquire about AI, automation, digital products and product engineering."
}
]
}
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Send Receipt": {
"main": [
[
{
"node": "Form End",
"type": "main",
"index": 0
}
]
]
},
"Has Accepted?": {
"main": [
[
{
"node": "Enter Date & Time",
"type": "main",
"index": 0
}
],
[
{
"node": "Decline1",
"type": "main",
"index": 0
}
]
]
},
"Has Approval?": {
"main": [
[
{
"node": "Create Appointment",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Rejection",
"type": "main",
"index": 0
}
]
]
},
"Get Form Values": {
"main": [
[
{
"node": "Trigger Approval Process",
"type": "main",
"index": 0
}
]
]
},
"n8n Form Trigger": {
"main": [
[
{
"node": "Enquiry Classifier",
"type": "main",
"index": 0
}
]
]
},
"Enter Date & Time": {
"main": [
[
{
"node": "Get Form Values",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Enquiry Classifier",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Summarise Enquiry": {
"main": [
[
{
"node": "Wait for Approval",
"type": "main",
"index": 0
}
]
]
},
"Wait for Approval": {
"main": [
[
{
"node": "Has Approval?",
"type": "main",
"index": 0
}
]
]
},
"Enquiry Classifier": {
"main": [
[
{
"node": "Terms & Conditions",
"type": "main",
"index": 0
}
],
[
{
"node": "Decline",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "Summarise Enquiry",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Terms & Conditions": {
"main": [
[
{
"node": "Has Accepted?",
"type": "main",
"index": 0
}
]
]
},
"Execute Workflow Trigger": {
"main": [
[
{
"node": "Summarise Enquiry",
"type": "main",
"index": 0
}
]
]
},
"Trigger Approval Process": {
"main": [
[
{
"node": "Send Receipt",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,602 @@
{
"id": "slP122GjD9meGkS6",
"meta": {
"instanceId": "178ef8a5109fc76c716d40bcadb720c455319f7b7a3fd5a39e4f336a091f524a"
},
"name": "Calendar_scheduling",
"tags": [],
"nodes": [
{
"id": "bd1dae81-daea-4539-bf1d-38eb9a2bd2f0",
"name": "Gmail Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
500,
560
],
"parameters": {
"filters": {
"readStatus": "unread",
"includeSpamTrash": false
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"credentials": {
"gmailOAuth2": {
"id": "kLFedNEM8Zwkergv",
"name": "Gmail account"
}
},
"typeVersion": 1
},
{
"id": "a97c3ab1-6fbc-441e-af11-3c746936013b",
"name": "Chat OpenAI",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
720,
740
],
"parameters": {
"model": "gpt-4",
"options": {
"temperature": 0.1
}
},
"credentials": {
"openAiApi": {
"id": "wJtZwsVKW5v6R2Iy",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "a1205598-7cd4-4278-ad53-0cfc7c7947ff",
"name": "Workflow Tool",
"type": "@n8n/n8n-nodes-langchain.toolWorkflow",
"position": [
1580,
759
],
"parameters": {
"name": "Calendar_Availability",
"workflowId": "={{ $workflow.id }}",
"description": "Call this tool to get my calendar availability as stringified JSON array."
},
"typeVersion": 1
},
{
"id": "5ba2c2b0-2218-45d2-a417-f86c80643397",
"name": "Chat OpenAI1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1420,
759
],
"parameters": {
"model": "gpt-4",
"options": {
"temperature": 0
}
},
"credentials": {
"openAiApi": {
"id": "wJtZwsVKW5v6R2Iy",
"name": "OpenAi account"
}
},
"typeVersion": 1
},
{
"id": "012835ec-c20a-4b84-bed8-67f6aac30698",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
460,
460
],
"parameters": {
"width": 616.8060552874073,
"height": 410.24791575252334,
"content": "## Check if incoming email is about appointment\nWe use LLM to check subject and body of the email and determine if it's an appointment request. "
},
"typeVersion": 1
},
{
"id": "ceaa4f77-acc8-437e-9d61-16cf344a7748",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1340,
460
],
"parameters": {
"width": 676.1951194231482,
"height": 241.70645019745504,
"content": "## Get calendar availability and compose a response\nMake sure to update the Workflow ID if you are running this as 2 workflows"
},
"typeVersion": 1
},
{
"id": "499def23-7dec-4131-91fd-326b1b824762",
"name": "Google Calendar",
"type": "n8n-nodes-base.googleCalendar",
"position": [
680,
1120
],
"parameters": {
"options": {
"timeMax": "={{ $now.plus(1, 'month').toISO() }}",
"timeMin": "={{ $now.minus(1, 'day').toISO() }}",
"singleEvents": true
},
"calendar": {
"__rl": true,
"mode": "list",
"value": "your_email@gmail.com",
"cachedResultName": "your_email@gmail.com"
},
"operation": "getAll",
"returnAll": true
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "s95HsHIMB7oK0dAH",
"name": "Google Calendar account"
}
},
"typeVersion": 1
},
{
"id": "0f5f43fa-3386-4682-b620-21db35651d3b",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
460,
1120
],
"parameters": {},
"typeVersion": 1
},
{
"id": "8b2b82b9-c11f-4e7f-ab23-16ea5e395e11",
"name": "Format response",
"type": "n8n-nodes-base.itemLists",
"position": [
1560,
1120
],
"parameters": {
"include": "allFieldsExcept",
"options": {},
"aggregate": "aggregateAllItemData",
"operation": "concatenateItems",
"fieldsToExclude": "sort",
"destinationFieldName": "response"
},
"typeVersion": 3
},
{
"id": "ac363d85-5c6e-4a9f-9cfc-ecc15a325b01",
"name": "Stringify Response",
"type": "n8n-nodes-base.set",
"position": [
1780,
1120
],
"parameters": {
"values": {
"string": [
{
"name": "response",
"value": "={{ JSON.stringify($json.response) }}"
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 2
},
{
"id": "399c5bc4-c8bd-4d0b-942a-9889447880a9",
"name": "Extract start, end and name",
"type": "n8n-nodes-base.set",
"position": [
1100,
1120
],
"parameters": {
"values": {
"string": [
{
"name": "start",
"value": "={{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"
},
{
"name": "end",
"value": "={{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"
},
{
"name": "name",
"value": "={{ $json.summary }}"
},
{
"name": "sort",
"value": "={{ $json.start.dateTime }}"
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 2
},
{
"id": "a39b6c7d-fdcc-452d-9ef5-50b038153330",
"name": "Filter only confirmed and with set time",
"type": "n8n-nodes-base.filter",
"position": [
880,
1120
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "confirmed"
}
],
"boolean": [
{
"value1": "={{ $json.start.dateTime }}",
"value2": "={{ undefined }}",
"operation": "notEqual"
}
]
}
},
"typeVersion": 1
},
{
"id": "0e0a2be9-cde7-497d-94c5-180128382bb7",
"name": "Is appointment request",
"type": "n8n-nodes-base.if",
"position": [
1100,
560
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.is_appointment }}",
"value2": "true"
}
],
"boolean": [
{
"value1": "={{ $json.is_appointment }}",
"value2": true
}
]
},
"combineOperation": "any"
},
"typeVersion": 1
},
{
"id": "a6e11f63-a56a-4fe0-91c8-0dde2720e905",
"name": "Classify appointment",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
720,
560
],
"parameters": {
"prompt": "=Please evaluate the following email to determine if it suggests scheduling a meeting or a call:\nSubject: {{ encodeURI($json.Subject) }}\nSnippet: {{ encodeURI($json.snippet) }}\nIndicate your assessment by responding with \"true\" if it suggests a meeting or call, or \"false\" otherwise. Use lowercase for your response.\n"
},
"typeVersion": 1
},
{
"id": "b6411b14-67f6-4195-a834-60a4dc5e4851",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
880,
740
],
"parameters": {
"jsonSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"is_appointment\": {\n \"type\": \"boolean\"\n }\n }\n}"
},
"typeVersion": 1
},
{
"id": "96248431-290b-4fb1-94a3-714e7c0008d4",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
1058.6115582634225
],
"parameters": {
"width": 810.4923211935056,
"height": 224.60561166142082,
"content": "### Get all query google events for the next month and extract relevant data"
},
"typeVersion": 1
},
{
"id": "48bc7c0c-0b74-418e-8c5c-6a6faf24722c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1513,
1060
],
"parameters": {
"width": 444.4130232558142,
"height": 220.42397542781927,
"content": "### Wrap the result in `response` object and return "
},
"typeVersion": 1
},
{
"id": "a68f7b27-1891-46c7-92b2-650cc17f94d6",
"name": "Sort",
"type": "n8n-nodes-base.itemLists",
"position": [
1320,
1120
],
"parameters": {
"options": {},
"operation": "sort",
"sortFieldsUi": {
"sortField": [
{
"fieldName": "sort"
}
]
}
},
"typeVersion": 3
},
{
"id": "2b5b5855-6d3f-4405-9f48-5d6c4ee2475b",
"name": "Mark as read",
"type": "n8n-nodes-base.gmail",
"position": [
1840,
739
],
"parameters": {
"messageId": "={{ $('Gmail Trigger').item.json.id }}",
"operation": "markAsRead"
},
"credentials": {
"gmailOAuth2": {
"id": "kLFedNEM8Zwkergv",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "accbe2df-367a-4bd3-a383-12ee79062e12",
"name": "Send Reply",
"type": "n8n-nodes-base.gmail",
"position": [
1840,
539
],
"parameters": {
"message": "={{ $json.output }}",
"options": {
"replyToSenderOnly": true
},
"messageId": "={{ $('Gmail Trigger').item.json.id }}",
"operation": "reply"
},
"credentials": {
"gmailOAuth2": {
"id": "kLFedNEM8Zwkergv",
"name": "Gmail account"
}
},
"typeVersion": 2
},
{
"id": "66d62337-d0c1-4744-b169-8e95c1d1492a",
"name": "Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1400,
539
],
"parameters": {
"text": "=Sender: {{ $('Gmail Trigger').item.json.From }}\\nSubject: {{ $('Gmail Trigger').item.json.Subject }}\\nEmail Text: {{ $('Gmail Trigger').item.json.snippet }}",
"options": {
"systemMessage": "=You are an email scheduling assistant. Based on the received email, check my availability and propose an appropriate response. \nAim to get a specific time, rather than just a day. When checking my availability, make sure that there's enough time in between meetings.\nIf I'm not available, ALWAYS propose a new time based on my availability. When proposing a new time, always leave 15 minutes buffer from previous meeting.\nToday date and time is: {{ $now.toISO() }}."
}
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "0cf0768b-ddc0-42a3-9c84-f93d43c66dc7",
"connections": {
"Sort": {
"main": [
[
{
"node": "Format response",
"type": "main",
"index": 0
}
]
]
},
"Agent": {
"main": [
[
{
"node": "Send Reply",
"type": "main",
"index": 0
},
{
"node": "Mark as read",
"type": "main",
"index": 0
}
]
]
},
"Chat OpenAI": {
"ai_languageModel": [
[
{
"node": "Classify appointment",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Chat OpenAI1": {
"ai_languageModel": [
[
{
"node": "Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Gmail Trigger": {
"main": [
[
{
"node": "Classify appointment",
"type": "main",
"index": 0
}
]
]
},
"Workflow Tool": {
"ai_tool": [
[
{
"node": "Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Format response": {
"main": [
[
{
"node": "Stringify Response",
"type": "main",
"index": 0
}
]
]
},
"Google Calendar": {
"main": [
[
{
"node": "Filter only confirmed and with set time",
"type": "main",
"index": 0
}
]
]
},
"Classify appointment": {
"main": [
[
{
"node": "Is appointment request",
"type": "main",
"index": 0
}
]
]
},
"Is appointment request": {
"main": [
[
{
"node": "Agent",
"type": "main",
"index": 0
}
]
]
},
"Execute Workflow Trigger": {
"main": [
[
{
"node": "Google Calendar",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Classify appointment",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Extract start, end and name": {
"main": [
[
{
"node": "Sort",
"type": "main",
"index": 0
}
]
]
},
"Filter only confirmed and with set time": {
"main": [
[
{
"node": "Extract start, end and name",
"type": "main",
"index": 0
}
]
]
}
}
}