diff --git a/Classify new bugs in Linear with OpenAI_s GPT-4 and move them to the right team.txt b/Classify new bugs in Linear with OpenAI_s GPT-4 and move them to the right team.txt new file mode 100644 index 0000000..4af1428 --- /dev/null +++ b/Classify new bugs in Linear with OpenAI_s GPT-4 and move them to the right team.txt @@ -0,0 +1,537 @@ +{ +"meta": { +"instanceId": "cb484ba7b742928a2048bf8829668bed5b5ad9787579adea888f05980292a4a7" +}, +"nodes": [ +{ +"id": "8920dc6e-b2fb-4446-8cb3-f3f6d626dcb3", +"name": "Linear Trigger", +"type": "n8n-nodes-base.linearTrigger", +"position": [ +420, +360 +], +"webhookId": "a02faf62-684f-44bb-809f-e962c9ede70d", +"parameters": { +"teamId": "7a330c36-4b39-4bf1-922e-b4ceeb91850a", +"resources": [ +"issue" +], +"authentication": "oAuth2" +}, +"credentials": { +"linearOAuth2Api": { +"id": "02MqKUMdPxr9t3mX", +"name": "Nik's Linear Creds" +} +}, +"typeVersion": 1 +}, +{ +"id": "61214884-62f9-4a00-9517-e2d51b44d0ae", +"name": "Only tickets that need to be classified", +"type": "n8n-nodes-base.filter", +"position": [ +1000, +360 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "bc3a756d-b2b6-407b-91c9-a1cd9da004e0", +"operator": { +"type": "string", +"operation": "notContains" +}, +"leftValue": "={{ $('Linear Trigger').item.json.data.description }}", +"rightValue": "Add a description here" +}, +{ +"id": "f3d8d0fc-332d-41a6-aef8-1f221bf30c0e", +"operator": { +"name": "filter.operator.equals", +"type": "string", +"operation": "equals" +}, +"leftValue": "={{ $('Linear Trigger').item.json.data.state.id }}", +"rightValue": "6b9a8eec-82dc-453a-878b-50f4c98d3e53" +}, +{ +"id": "9cdb55b2-3ca9-43bd-84b0-ef025b59ce18", +"operator": { +"type": "number", +"operation": "gt" +}, +"leftValue": "={{ $('Linear Trigger').item.json.data.labels.filter(label => label.id === 'f2b6e3e9-b42d-4106-821c-6a08dcb489a9').length }}", +"rightValue": 0 +} +] +} +}, +"typeVersion": 2 +}, +{ +"id": "da4d8e0c-895b-4a84-8319-438f971af403", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1000, +111.31510859283728 +], +"parameters": { +"color": 7, +"height": 219.68489140716272, +"content": "### When does this fire?\nIn our setup we have a general team in Linear where we post new tickets to. Additionally, the bug needs to have a certain label and the description needs to be filled. \nYou're of course free to adjust this to your needs\n👇" +}, +"typeVersion": 1 +}, +{ +"id": "b7e3a328-96c4-4082-93a9-0cb331367190", +"name": "Update team", +"type": "n8n-nodes-base.linear", +"position": [ +2160, +280 +], +"parameters": { +"issueId": "={{ $('Linear Trigger').item.json.data.id }}", +"operation": "update", +"updateFields": { +"teamId": "={{ $json.teamId }}" +} +}, +"credentials": { +"linearApi": { +"id": "oYIZvhmcNt5JWTCP", +"name": "Nik's Linear Key" +} +}, +"typeVersion": 1 +}, +{ +"id": "858764ce-cd24-4399-88ce-cf69e676beaa", +"name": "Get all linear teams", +"type": "n8n-nodes-base.httpRequest", +"position": [ +1300, +540 +], +"parameters": { +"url": "https://api.linear.app/graphql", +"method": "POST", +"options": {}, +"sendBody": true, +"authentication": "predefinedCredentialType", +"bodyParameters": { +"parameters": [ +{ +"name": "query", +"value": "{ teams { nodes { id name } } }" +} +] +}, +"nodeCredentialType": "linearOAuth2Api" +}, +"credentials": { +"linearOAuth2Api": { +"id": "02MqKUMdPxr9t3mX", +"name": "Nik's Linear Creds" +} +}, +"typeVersion": 3 +}, +{ +"id": "167f0c66-5bfb-4dd7-a345-81f4d62df2c4", +"name": "Set team ID", +"type": "n8n-nodes-base.set", +"position": [ +2000, +280 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "a46c4476-b851-4112-ac72-e805308c5ab7", +"name": "teamId", +"type": "string", +"value": "={{ $('Get all linear teams').first().json.data.teams.nodes.find(team => team.name === $json.message.content).id }}" +} +] +} +}, +"typeVersion": 3.3 +}, +{ +"id": "36363240-2b03-4af8-8987-0db95094403b", +"name": "Set me up", +"type": "n8n-nodes-base.set", +"position": [ +700, +360 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "a56f24c8-0a28-4dd2-885a-cb6a081a5bf4", +"name": "teams", +"type": "string", +"value": "- [Adore][Is responsible for every persona that is not Enterprise. This includes signup journeys, trials, n8n Cloud, the Canvas building experience and more, the nodes detail view (NDV), the nodes panel, the workflows list and the executions view] \n- [Payday][Is responsible for the Enterprise persona. This includes making sure n8n is performant, the enterprise features SSO, LDAP, SAML, Log streaming, environments, queue mode, version control, external storage. Additionally the team looks out for the execution logic in n8n and how branching works] \n- [Nodes][This team is responsible for everything that is related to a specific node in n8n] \n- [Other][This is a placeholder if you don't know to which team something belongs]" +}, +{ +"id": "d672cb59-72be-4fc8-9327-2623795f225d", +"name": "slackChannel", +"type": "string", +"value": "#yourChannelName" +} +] +} +}, +"typeVersion": 3.3 +}, +{ +"id": "49f2a157-b037-46d9-a6d7-97f8a72ee093", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +581.3284642016245, +85.15358950105212 +], +"parameters": { +"color": 5, +"width": 349.85308830334156, +"height": 439.62604295396085, +"content": "## Setup\n1. Add your Linear and OpenAi credentials\n2. Change the team in the `Linear Trigger` to match your needs\n3. Customize your teams and their areas of responsibility in the `Set me up` node. Please use the format `[Teamname][Description/Areas of responsibility]`. Also make sure that the teamnames match the names in Linear exactly.\n4. Change the Slack channel in the `Set me up` node to your Slack channel of choice." +}, +"typeVersion": 1 +}, +{ +"id": "8cdb3d0d-4fd3-4ea2-957f-daf746934728", +"name": "Check if AI was able to find a team", +"type": "n8n-nodes-base.if", +"position": [ +1780, +380 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "86bfb688-3ecc-4360-b83a-d706bb11c8f9", +"operator": { +"type": "string", +"operation": "notEquals" +}, +"leftValue": "={{ $json.message.content }}", +"rightValue": "Other" +} +] +} +}, +"typeVersion": 2 +}, +{ +"id": "a4cb20ca-658a-4b30-9185-5af9a32a7e20", +"name": "Notify in Slack", +"type": "n8n-nodes-base.slack", +"position": [ +2000, +460 +], +"parameters": { +"text": "The AI was not able to identify a fitting team for a bug", +"select": "channel", +"channelId": { +"__rl": true, +"mode": "name", +"value": "={{ $('Set me up').first().json.slackChannel }}" +}, +"otherOptions": {} +}, +"credentials": { +"slackApi": { +"id": "376", +"name": "Idea Bot" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "393b2392-80be-4a68-9240-dc1065e0081a", +"name": "Merge data", +"type": "n8n-nodes-base.merge", +"position": [ +1600, +380 +], +"parameters": { +"mode": "chooseBranch" +}, +"typeVersion": 2.1 +}, +{ +"id": "f25da511-b255-4a53-ba4e-5765916e90be", +"name": "OpenAI", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +1220, +360 +], +"parameters": { +"modelId": { +"__rl": true, +"mode": "list", +"value": "gpt-4-32k-0314", +"cachedResultName": "GPT-4-32K-0314" +}, +"options": {}, +"messages": { +"values": [ +{ +"role": "system", +"content": "I need you to classify a bug ticket and tell me which team should work on it" +}, +{ +"role": "system", +"content": "All possible teams will be described in the following format: [Teamname][Areas of responsibility] " +}, +{ +"role": "system", +"content": "=The possible teams are the following:\n {{ $('Set me up').first().json.teams }}" +}, +{ +"role": "system", +"content": "=This is the bug that we're trying to classify:\nTitle: {{ $('Linear Trigger').first().json.data.title }}\nDescription: {{ $('Linear Trigger').first().json.data.description }}" +}, +{ +"content": "Which team should work on this bug?" +}, +{ +"role": "system", +"content": "Do not respond with anything else than the name of the team from the list you were given" +} +] +} +}, +"credentials": { +"openAiApi": { +"id": "VQtv7frm7eLiEDnd", +"name": "OpenAi account 7" +} +}, +"typeVersion": 1 +} +], +"pinData": { +"Linear Trigger": [ +{ +"url": "https://linear.app/n8n/issue/N8N-6945/cannot-scroll-the-canvas-after-duplicating-or-pausing-a-note", +"data": { +"id": "94a4b770-3c80-4099-9376-ffe951f633db", +"url": "https://linear.app/n8n/issue/N8N-6945/cannot-scroll-the-canvas-after-duplicating-or-pausing-a-note", +"team": { +"id": "7a330c36-4b39-4bf1-922e-b4ceeb91850a", +"key": "N8N", +"name": "Engineering" +}, +"state": { +"id": "6b9a8eec-82dc-453a-878b-50f4c98d3e53", +"name": "Triage", +"type": "triage", +"color": "#FC7840" +}, +"title": "cannot scroll the canvas after duplicating or pausing a note", +"labels": [ +{ +"id": "f2b6e3e9-b42d-4106-821c-6a08dcb489a9", +"name": "type/bug", +"color": "#eb5757" +} +], +"number": 6945, +"teamId": "7a330c36-4b39-4bf1-922e-b4ceeb91850a", +"cycleId": null, +"dueDate": null, +"stateId": "6b9a8eec-82dc-453a-878b-50f4c98d3e53", +"trashed": null, +"botActor": { +"name": "Unknown", +"type": "apiKey" +}, +"estimate": null, +"labelIds": [ +"f2b6e3e9-b42d-4106-821c-6a08dcb489a9" +], +"parentId": null, +"priority": 0, +"createdAt": "2023-09-12T12:51:41.696Z", +"creatorId": "49ae7598-ae5d-42e6-8a03-9f6038a0d37a", +"projectId": null, +"sortOrder": -154747, +"startedAt": null, +"triagedAt": null, +"updatedAt": "2024-02-29T16:00:27.794Z", +"archivedAt": null, +"assigneeId": null, +"boardOrder": 0, +"canceledAt": null, +"identifier": "N8N-6945", +"completedAt": null, +"description": "## Description\n\nAfter using the canvas for a while I always had issues where the scrolling would stop working. I finally found a way to reproduce the issue reliably.\n\n## Expected\n\nI would like to always be able to scroll the canvas using CMD + click\n\n## Actual\n\nSometimes when using the app the scrolling stops working and you have to refresh to get it back to work.\n\n## Steps or workflow to reproduce (with screenshots/recordings)\n\n**n8n version:** \\[Deployment type\\] \\[version\\]\n\n1. Add any nodes to the canvas\n2. Click either the Duplicate or Pause buttons that appear when hovering over a node\n3. Try scrolling using CMD/CTRL + Click. Scrolling should no longer work while it should still work\n\nCreated by Omar", +"snoozedById": null, +"autoClosedAt": null, +"slaStartedAt": null, +"priorityLabel": "No priority", +"slaBreachesAt": null, +"subscriberIds": [ +"49ae7598-ae5d-42e6-8a03-9f6038a0d37a" +], +"autoArchivedAt": null, +"snoozedUntilAt": null, +"descriptionData": "{\"type\":\"doc\",\"content\":[{\"type\":\"heading\",\"attrs\":{\"level\":2,\"id\":\"d836020f-77f5-4ae0-9d6e-a69bd4567656\"},\"content\":[{\"type\":\"text\",\"text\":\"Description\"}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"After using the canvas for a while I always had issues where the scrolling would stop working. I finally found a way to reproduce the issue reliably.\"}]},{\"type\":\"heading\",\"attrs\":{\"level\":2,\"id\":\"4125614d-17b0-4530-bfc0-384d43bf80f9\"},\"content\":[{\"type\":\"text\",\"text\":\"Expected\"}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"I would like to always be able to scroll the canvas using CMD + click\"}]},{\"type\":\"heading\",\"attrs\":{\"level\":2,\"id\":\"3e8caaae-c152-46c1-a604-f0f9c75fb8c9\"},\"content\":[{\"type\":\"text\",\"text\":\"Actual\"}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Sometimes when using the app the scrolling stops working and you have to refresh to get it back to work.\"}]},{\"type\":\"heading\",\"attrs\":{\"level\":2,\"id\":\"73e4d549-a030-4b0c-b7d8-bcfa69d1b832\"},\"content\":[{\"type\":\"text\",\"text\":\"Steps or workflow to reproduce (with screenshots/recordings)\"}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"n8n version:\",\"marks\":[{\"type\":\"strong\",\"attrs\":{}}]},{\"type\":\"text\",\"text\":\" [Deployment type] [version]\"}]},{\"type\":\"ordered_list\",\"attrs\":{\"order\":1},\"content\":[{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Add any nodes to the canvas\"}]}]},{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Click either the Duplicate or Pause buttons that appear when hovering over a node\"}]}]},{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Try scrolling using CMD/CTRL + Click. Scrolling should no longer work while it should still work\"}]}]}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Created by Omar\"}]}]}", +"startedTriageAt": "2023-09-12T12:51:41.825Z", +"subIssueSortOrder": null, +"projectMilestoneId": null, +"previousIdentifiers": [], +"externalUserCreatorId": null, +"lastAppliedTemplateId": null +}, +"type": "Issue", +"actor": { +"id": "49ae7598-ae5d-42e6-8a03-9f6038a0d37a", +"name": "Niklas Hatje" +}, +"action": "update", +"createdAt": "2024-02-29T16:00:27.794Z", +"webhookId": "2120ca07-c896-413a-ab8d-a270e14c1d9e", +"updatedFrom": { +"updatedAt": "2024-02-29T16:00:27.794Z", +"description": "## Description\n\nAfter using the canvas for a while I always had issues where the scrolling would stop working. I finally found a way to reproduce the issue reliably.\n\n## Expected\n\nI would like to always be able to scroll the canvas using CMD + click\n\n## Actual\n\nSometimes when using the app the scrolling stops working and you have to refresh to get it back to work.\n\n## Steps or workflow to reproduce (with screenshots/recordings)\n\n**n8n version:** \\[Deployment type\\] \\[version\\]\n\n1. Add any nodes to the canvas\n2. Click either the Duplicate or Pause buttons that appear when hovering over a node\n3. Try scrolling using CMD/CTRL + Click. Scrolling should no longer work while it should still work\n\nCreated by: Omar", +"descriptionData": "{\"type\":\"doc\",\"content\":[{\"type\":\"heading\",\"attrs\":{\"id\":\"d836020f-77f5-4ae0-9d6e-a69bd4567656\",\"level\":2},\"content\":[{\"text\":\"Description\",\"type\":\"text\"}]},{\"type\":\"paragraph\",\"content\":[{\"text\":\"After using the canvas for a while I always had issues where the scrolling would stop working. I finally found a way to reproduce the issue reliably.\",\"type\":\"text\"}]},{\"type\":\"heading\",\"attrs\":{\"id\":\"4125614d-17b0-4530-bfc0-384d43bf80f9\",\"level\":2},\"content\":[{\"text\":\"Expected\",\"type\":\"text\"}]},{\"type\":\"paragraph\",\"content\":[{\"text\":\"I would like to always be able to scroll the canvas using CMD + click\",\"type\":\"text\"}]},{\"type\":\"heading\",\"attrs\":{\"id\":\"3e8caaae-c152-46c1-a604-f0f9c75fb8c9\",\"level\":2},\"content\":[{\"text\":\"Actual\",\"type\":\"text\"}]},{\"type\":\"paragraph\",\"content\":[{\"text\":\"Sometimes when using the app the scrolling stops working and you have to refresh to get it back to work.\",\"type\":\"text\"}]},{\"type\":\"heading\",\"attrs\":{\"id\":\"73e4d549-a030-4b0c-b7d8-bcfa69d1b832\",\"level\":2},\"content\":[{\"text\":\"Steps or workflow to reproduce (with screenshots/recordings)\",\"type\":\"text\"}]},{\"type\":\"paragraph\",\"content\":[{\"text\":\"n8n version:\",\"type\":\"text\",\"marks\":[{\"type\":\"strong\",\"attrs\":{}}]},{\"text\":\" [Deployment type] [version]\",\"type\":\"text\"}]},{\"type\":\"ordered_list\",\"attrs\":{\"order\":1},\"content\":[{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"text\":\"Add any nodes to the canvas\",\"type\":\"text\"}]}]},{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"text\":\"Click either the Duplicate or Pause buttons that appear when hovering over a node\",\"type\":\"text\"}]}]},{\"type\":\"list_item\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"text\":\"Try scrolling using CMD/CTRL + Click. Scrolling should no longer work while it should still work\",\"type\":\"text\"}]}]}]},{\"type\":\"paragraph\",\"content\":[{\"text\":\"Created by: Omar\",\"type\":\"text\"}]}]}" +}, +"organizationId": "1c35bbc6-9cd4-427e-8bc5-e5d370a9869f", +"webhookTimestamp": 1709222430026 +} +] +}, +"connections": { +"OpenAI": { +"main": [ +[ +{ +"node": "Merge data", +"type": "main", +"index": 0 +} +] +] +}, +"Set me up": { +"main": [ +[ +{ +"node": "Only tickets that need to be classified", +"type": "main", +"index": 0 +} +] +] +}, +"Merge data": { +"main": [ +[ +{ +"node": "Check if AI was able to find a team", +"type": "main", +"index": 0 +} +] +] +}, +"Set team ID": { +"main": [ +[ +{ +"node": "Update team", +"type": "main", +"index": 0 +} +] +] +}, +"Linear Trigger": { +"main": [ +[ +{ +"node": "Set me up", +"type": "main", +"index": 0 +} +] +] +}, +"Get all linear teams": { +"main": [ +[ +{ +"node": "Merge data", +"type": "main", +"index": 1 +} +] +] +}, +"Check if AI was able to find a team": { +"main": [ +[ +{ +"node": "Set team ID", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Notify in Slack", +"type": "main", +"index": 0 +} +] +] +}, +"Only tickets that need to be classified": { +"main": [ +[ +{ +"node": "OpenAI", +"type": "main", +"index": 0 +}, +{ +"node": "Get all linear teams", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Complete business WhatsApp AI-Powered RAG Chatbot using OpenAI.txt b/Complete business WhatsApp AI-Powered RAG Chatbot using OpenAI.txt new file mode 100644 index 0000000..af5d75d --- /dev/null +++ b/Complete business WhatsApp AI-Powered RAG Chatbot using OpenAI.txt @@ -0,0 +1,669 @@ +{ +"id": "APCp9GPNjUSFPSfJ", +"meta": { +"instanceId": "a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462", +"templateCredsSetupCompleted": true +}, +"name": "Business WhatsApp AI RAG Chatbot", +"tags": [], +"nodes": [ +{ +"id": "2c5b2dd1-c63f-4bc9-909e-5f4b2a385d01", +"name": "Respond to Webhook", +"type": "n8n-nodes-base.respondToWebhook", +"position": [ +1020, +1040 +], +"parameters": { +"options": {}, +"respondWith": "text", +"responseBody": "={{ $json.query['hub.challenge'] }}" +}, +"typeVersion": 1.1 +}, +{ +"id": "cc230fcd-f88c-40d4-8835-ac9dc6228b18", +"name": "AI Agent", +"type": "@n8n/n8n-nodes-langchain.agent", +"position": [ +1560, +1380 +], +"parameters": { +"text": "={{ $('Respond').item.json.body.entry[0].changes[0].value.messages[0].text.body }}", +"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 store’s 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 store’s 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: \"What’s 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 isn’t 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 router’s 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. You’ll 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": "283df38d-1a2b-44d9-8e29-5e928ca1c4c9", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +740, +1260 +], +"parameters": { +"width": 459, +"height": 485, +"content": "# STEP 4\n\n## RAG System\n\n\n\n\n\n\n\n\n\n\n\n\n\n* *Respond* webhook receives various POST Requests from Meta regarding WhatsApp messages (user messages + status notifications)\n* Check if the incoming JSON contains user message\n* Echo back the text message to the user. This is a custom message, not a WhatsApp Business template message\n" +}, +"typeVersion": 1 +}, +{ +"id": "b8f5ac53-03fe-4151-ac56-b246245702b6", +"name": "OpenAI Chat Model", +"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", +"position": [ +1560, +1580 +], +"parameters": { +"model": { +"__rl": true, +"mode": "list", +"value": "gpt-4o-mini" +}, +"options": {} +}, +"credentials": { +"openAiApi": { +"id": "CDX6QM4gLYanh0P4", +"name": "OpenAi account" +} +}, +"typeVersion": 1.2 +}, +{ +"id": "a02f4e76-1895-48ad-a2d5-6daf3347f181", +"name": "When clicking ‘Test workflow’", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +460, +100 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "35a71dd7-ae08-46c5-acb2-e66d92b311cb", +"name": "Qdrant Vector Store", +"type": "@n8n/n8n-nodes-langchain.vectorStoreQdrant", +"position": [ +1440, +220 +], +"parameters": { +"mode": "insert", +"options": {}, +"qdrantCollection": { +"__rl": true, +"mode": "id", +"value": "=COLLECTION" +} +}, +"credentials": { +"qdrantApi": { +"id": "iyQ6MQiVaF3VMBmt", +"name": "QdrantApi account" +} +}, +"typeVersion": 1 +}, +{ +"id": "1538c8b1-f914-4991-b311-e533df625c5f", +"name": "Create collection", +"type": "n8n-nodes-base.httpRequest", +"position": [ +760, +-40 +], +"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": "423b73a6-2497-4635-9ad0-9e768f32018d", +"name": "Refresh collection", +"type": "n8n-nodes-base.httpRequest", +"position": [ +760, +220 +], +"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": "9519866a-f28a-495a-9cb4-3b2170407943", +"name": "Get folder", +"type": "n8n-nodes-base.googleDrive", +"position": [ +980, +220 +], +"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" +} +}, +"typeVersion": 3 +}, +{ +"id": "c9a36259-8340-4382-8bb0-84b73a8288c6", +"name": "Download Files", +"type": "n8n-nodes-base.googleDrive", +"position": [ +1200, +220 +], +"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" +} +}, +"typeVersion": 3 +}, +{ +"id": "b20975d7-e367-49a3-ac8c-613289775463", +"name": "Embeddings OpenAI", +"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", +"position": [ +1420, +420 +], +"parameters": { +"options": {} +}, +"credentials": { +"openAiApi": { +"id": "CDX6QM4gLYanh0P4", +"name": "OpenAi account" +} +}, +"typeVersion": 1.1 +}, +{ +"id": "4c2d02a4-c954-42c4-97b0-b94ee3198f56", +"name": "Default Data Loader", +"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader", +"position": [ +1600, +420 +], +"parameters": { +"options": {}, +"dataType": "binary" +}, +"typeVersion": 1 +}, +{ +"id": "72591129-1691-4caf-bf63-c04db85708dc", +"name": "Token Splitter", +"type": "@n8n/n8n-nodes-langchain.textSplitterTokenSplitter", +"position": [ +1560, +580 +], +"parameters": { +"chunkSize": 300, +"chunkOverlap": 30 +}, +"typeVersion": 1 +}, +{ +"id": "cc74592d-6562-4816-917c-0d88913a8125", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +200, +1140 +], +"parameters": { +"color": 3, +"width": 405, +"height": 177, +"content": "## Important!\n### Configure the webhook nodes this way:\n* Make sure that both *Verify* and *Respond* have the same URL\n* *Verify* should have GET HTTP Method\n* *Respond* should have POST HTTP Method" +}, +"typeVersion": 1 +}, +{ +"id": "9c8d4973-dcc5-4506-967f-3b3a5df501fa", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +740, +800 +], +"parameters": { +"color": 5, +"width": 618, +"height": 392, +"content": "# STEP 3\n\n## Create Webhook\n* Go to your [Meta for Developers App page](https://developers.facebook.com/apps/), navigate to the App settings\n* Add a **production webhook URL** as a new Callback URL\n* *Verify* webhook receives a GET Request and sends back a verification code\n* After that you can delete this\n" +}, +"typeVersion": 1 +}, +{ +"id": "ec013e0c-a354-4f12-8ded-97013bb8fb21", +"name": "Verify", +"type": "n8n-nodes-base.webhook", +"position": [ +780, +1040 +], +"webhookId": "f0d2e6f6-8fda-424d-b377-0bd191343c20", +"parameters": { +"path": "f0d2e6f6-8fda-424d-b377-0bd191343c20", +"options": {}, +"responseMode": "responseNode" +}, +"typeVersion": 2 +}, +{ +"id": "253ddc93-5693-4362-aa6c-a80ab3f6df82", +"name": "Respond", +"type": "n8n-nodes-base.webhook", +"position": [ +760, +1420 +], +"webhookId": "f0d2e6f6-8fda-424d-b377-0bd191343c20", +"parameters": { +"path": "f0d2e6f6-8fda-424d-b377-0bd191343c20", +"options": {}, +"httpMethod": "POST" +}, +"typeVersion": 2 +}, +{ +"id": "2d4b956e-92d9-41da-a6d3-9f588e453d2a", +"name": "is Message?", +"type": "n8n-nodes-base.if", +"position": [ +980, +1420 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "loose" +}, +"combinator": "and", +"conditions": [ +{ +"id": "959fbffc-876a-4235-87be-2dedba4926cd", +"operator": { +"type": "object", +"operation": "exists", +"singleValue": true +}, +"leftValue": "={{ $json.body.entry[0].changes[0].value.messages[0] }}", +"rightValue": "" +} +] +}, +"looseTypeValidation": true +}, +"typeVersion": 2.2 +}, +{ +"id": "2af633a9-f6b0-4989-9e85-abb619d2b3bb", +"name": "Only message", +"type": "n8n-nodes-base.whatsApp", +"position": [ +1280, +1520 +], +"parameters": { +"textBody": "=You can only send text messages", +"operation": "send", +"phoneNumberId": "470271332838881", +"requestOptions": {}, +"additionalFields": {}, +"recipientPhoneNumber": "={{ $('Respond').item.json.body.entry[0].changes[0].value.contacts[0].wa_id }}" +}, +"credentials": { +"whatsAppApi": { +"id": "HDUOWQXeRXMVjo0Z", +"name": "WhatsApp account" +} +}, +"typeVersion": 1 +}, +{ +"id": "5235dd06-2235-4edb-904e-872848e2ed79", +"name": "Send", +"type": "n8n-nodes-base.whatsApp", +"position": [ +1980, +1380 +], +"parameters": { +"textBody": "={{ $json.output }}", +"operation": "send", +"phoneNumberId": "470271332838881", +"requestOptions": {}, +"additionalFields": {}, +"recipientPhoneNumber": "={{ $('Respond').item.json.body.entry[0].changes[0].value.contacts[0].wa_id }}" +}, +"credentials": { +"whatsAppApi": { +"id": "HDUOWQXeRXMVjo0Z", +"name": "WhatsApp account" +} +}, +"typeVersion": 1 +}, +{ +"id": "dafe692e-7767-4ded-966c-df812f58ae63", +"name": "Window Buffer Memory", +"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", +"position": [ +1760, +1580 +], +"parameters": {}, +"typeVersion": 1.3 +}, +{ +"id": "ba6254bd-4dad-47bb-a535-7b6b708ea763", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +960, +-100 +], +"parameters": { +"color": 6, +"width": 880, +"height": 220, +"content": "# STEP 1\n\n## Create Qdrant Collection\nChange:\n- QDRANTURL\n- COLLECTION" +}, +"typeVersion": 1 +}, +{ +"id": "83cf4483-cd45-4de6-9b88-e00727ed8352", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +740, +160 +], +"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": "4e0a4245-370f-4596-b01b-4eed8acbe2c3", +"name": "Sticky Note5", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1520, +1260 +], +"parameters": { +"width": 380, +"height": 260, +"content": "## Configure AI Agent\nSet System prompt and chat model. If you want you can set any tools" +}, +"typeVersion": 1 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"versionId": "4eb1a148-185f-4f16-a6ad-01c3201d4fc0", +"connections": { +"Verify": { +"main": [ +[ +{ +"node": "Respond to Webhook", +"type": "main", +"index": 0 +} +] +] +}, +"Respond": { +"main": [ +[ +{ +"node": "is Message?", +"type": "main", +"index": 0 +} +] +] +}, +"AI Agent": { +"main": [ +[ +{ +"node": "Send", +"type": "main", +"index": 0 +} +] +] +}, +"Get folder": { +"main": [ +[ +{ +"node": "Download Files", +"type": "main", +"index": 0 +} +] +] +}, +"is Message?": { +"main": [ +[ +{ +"node": "AI Agent", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Only message", +"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 +} +] +] +}, +"Embeddings OpenAI": { +"ai_embedding": [ +[ +{ +"node": "Qdrant Vector Store", +"type": "ai_embedding", +"index": 0 +} +] +] +}, +"OpenAI Chat Model": { +"ai_languageModel": [ +[ +{ +"node": "AI Agent", +"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 +} +] +] +}, +"Window Buffer Memory": { +"ai_memory": [ +[ +{ +"node": "AI Agent", +"type": "ai_memory", +"index": 0 +} +] +] +}, +"When clicking ‘Test workflow’": { +"main": [ +[ +{ +"node": "Create collection", +"type": "main", +"index": 0 +}, +{ +"node": "Refresh collection", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Compose reply draft in Gmail with OpenAI Assistant.txt b/Compose reply draft in Gmail with OpenAI Assistant.txt new file mode 100644 index 0000000..da4487a --- /dev/null +++ b/Compose reply draft in Gmail with OpenAI Assistant.txt @@ -0,0 +1,594 @@ +{ +"nodes": [ +{ +"id": "a99b3164-fe36-4dde-9525-110c1ae08afb", +"name": "Convert raw to base64", +"type": "n8n-nodes-base.code", +"position": [ +3320, +580 +], +"parameters": { +"mode": "runOnceForEachItem", +"jsCode": "const encoded = Buffer.from($json.raw).toString('base64');\n\nreturn { encoded };" +}, +"typeVersion": 2 +}, +{ +"id": "f0f731bd-7b2f-4c39-bc06-42fd57bc4ae8", +"name": "Add email draft to thread", +"type": "n8n-nodes-base.httpRequest", +"position": [ +3580, +580 +], +"parameters": { +"url": "https://www.googleapis.com/gmail/v1/users/me/drafts", +"method": "POST", +"options": {}, +"jsonBody": "={\"message\":{\"raw\":\"{{ $json.encoded }}\", \"threadId\": \"{{ $('Map fields for further processing').item.json[\"threadId\"] }}\"}}", +"sendBody": true, +"specifyBody": "json", +"authentication": "predefinedCredentialType", +"nodeCredentialType": "gmailOAuth2" +}, +"credentials": { +"gmailOAuth2": { +"id": "uBcIMfsTtKjexw7I", +"name": "Gmail (workfloowstutorial@gmail.com)" +} +}, +"typeVersion": 4.1 +}, +{ +"id": "c1ce3400-4582-46c7-a85d-8fa9c325ff7b", +"name": "Remove AI label from email", +"type": "n8n-nodes-base.gmail", +"position": [ +3820, +580 +], +"parameters": { +"resource": "thread", +"threadId": "={{ $('Map fields for further processing').item.json[\"threadId\"] }}", +"operation": "removeLabels" +}, +"credentials": { +"gmailOAuth2": { +"id": "uBcIMfsTtKjexw7I", +"name": "Gmail (workfloowstutorial@gmail.com)" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "65f0508a-ca2e-49ce-b02f-ef6505b5e983", +"name": "Schedule trigger (1 min)", +"type": "n8n-nodes-base.scheduleTrigger", +"position": [ +960, +580 +], +"parameters": { +"rule": { +"interval": [ +{ +"field": "minutes", +"minutesInterval": 1 +} +] +} +}, +"typeVersion": 1.1 +}, +{ +"id": "ca4a209b-a79d-4911-b69b-1db22808be60", +"name": "Map fields for further processing", +"type": "n8n-nodes-base.set", +"position": [ +2620, +580 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "a77b2d79-1e70-410c-a657-f3d618154ea1", +"name": "response", +"type": "string", +"value": "={{ $json.output }}" +}, +{ +"id": "20850cac-f82c-4f02-84f0-3de31871a5b8", +"name": "threadId", +"type": "string", +"value": "={{ $('Get single message content').item.json[\"threadId\"] }}" +}, +{ +"id": "d270c18e-39a0-4d87-85f0-cc1ffc9c10ff", +"name": "to", +"type": "string", +"value": "={{ $('Get single message content').item.json[\"from\"][\"text\"] }}" +}, +{ +"id": "30acb50b-bdde-44bf-803c-76e0ae65f526", +"name": "subject", +"type": "string", +"value": "={{ $('Get single message content').item.json[\"subject\"] }}" +}, +{ +"id": "88914536-8c25-4877-8914-feab5e32fae3", +"name": "messageId", +"type": "string", +"value": "={{ $('Get threads with specific labels').item.json[\"id\"] }}" +} +] +} +}, +"typeVersion": 3.3 +}, +{ +"id": "93eb3844-f1fe-4b09-bcae-3e372a19ab6f", +"name": "Convert response to HTML", +"type": "n8n-nodes-base.markdown", +"position": [ +2860, +580 +], +"parameters": { +"mode": "markdownToHtml", +"options": { +"simpleLineBreaks": false +}, +"markdown": "={{ $json.response }}", +"destinationKey": "response" +}, +"typeVersion": 1 +}, +{ +"id": "da35eda9-b63e-49f9-8fe8-7517c1445c92", +"name": "Build email raw", +"type": "n8n-nodes-base.set", +"position": [ +3100, +580 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "913e9cb1-10de-4637-bf48-40272c7c7fe3", +"name": "raw", +"type": "string", +"value": "=To: {{ $json.to }}\nSubject: {{ $json.subject }}\nContent-Type: text/html; charset=\"utf-8\"\n\n{{ $json.response }}" +} +] +} +}, +"typeVersion": 3.3 +}, +{ +"id": "b667a399-a178-42e3-a587-4eccd2a153d8", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +460, +460 +], +"parameters": { +"color": 4, +"width": 420.4803040774015, +"height": 189.69151356225348, +"content": "## Reply draft with OpenAI Assistant\nThis workflow automatically transfers content of incoming email messages with specific labels into OpenAI Assitant and returns reply draft. After draft is composed, trigger label is deleted from the thread.\n\n**Please remember to configure your OpenAI Assistant first.**" +}, +"typeVersion": 1 +}, +{ +"id": "fe47636b-2142-4c40-a937-2ec360b230ae", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +900, +460 +], +"parameters": { +"width": 451.41125086385614, +"height": 313.3056033573073, +"content": "### Schedule trigger and get emails\nRun the workflow in equal intervals and check for threads with specific labels (trigger labels)." +}, +"typeVersion": 1 +}, +{ +"id": "c9bfa42c-a045-404d-aebe-d87dceb68f1a", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +460, +680 +], +"parameters": { +"color": 3, +"width": 421.0932411886662, +"height": 257.42916378714597, +"content": "## ⚠️ Note\n\n1. Complete video guide for this workflow is available [on my YouTube](https://youtu.be/a8Dhj3Zh9vQ). \n2. Remember to add your credentials and configure nodes (covered in the video guide).\n3. If you like this workflow, please subscribe to [my YouTube channel](https://www.youtube.com/@workfloows) and/or [my newsletter](https://workfloows.com/).\n\n**Thank you for your support!**" +}, +"typeVersion": 1 +}, +{ +"id": "40424340-c0ec-435a-9ce0-0e0dc3b94cfc", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2160, +460 +], +"parameters": { +"width": 381.6458068293894, +"height": 313.7892229150129, +"content": "### Generate reply\nTransfer email content to OpenAI Assitant and return AI-generated reply.\n" +}, +"typeVersion": 1 +}, +{ +"id": "e7cce507-6658-414d-8cbc-3af847dad124", +"name": "Sticky Note5", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2800, +460 +], +"parameters": { +"width": 219.88389496558554, +"height": 314.75072291501283, +"content": "### Create HTML message\nConvert incoming Markdown from OpenAI Assistant into HTML content." +}, +"typeVersion": 1 +}, +{ +"id": "2b383967-0a23-46a1-9a19-a9532a3c3425", +"name": "Sticky Note7", +"type": "n8n-nodes-base.stickyNote", +"position": [ +3040, +460 +], +"parameters": { +"width": 461.3148409669012, +"height": 314.75072291501283, +"content": "### Build and encode message\nCreate raw message in RFC standard and encode it into base64 string (please see [Gmail API reference](https://developers.google.com/gmail/api/reference/rest/v1/users.drafts/create) for more details)." +}, +"typeVersion": 1 +}, +{ +"id": "07685b17-cf22-4adf-a6b7-7acc2d863115", +"name": "Sticky Note8", +"type": "n8n-nodes-base.stickyNote", +"position": [ +3520, +460 +], +"parameters": { +"width": 219.88389496558554, +"height": 314.75072291501283, +"content": "### Insert reply draft\nAdd reply draft from OpenAI Assistant to specific Gmail thread." +}, +"typeVersion": 1 +}, +{ +"id": "1e8109f8-7dd3-4308-a5e8-32382aa41805", +"name": "Sticky Note9", +"type": "n8n-nodes-base.stickyNote", +"position": [ +3760, +460 +], +"parameters": { +"width": 219.88389496558554, +"height": 314.75072291501283, +"content": "### Remove label\nDelete trigger label from the Gmail thread." +}, +"typeVersion": 1 +}, +{ +"id": "d488db90-7367-49fa-b366-ccdfc796b5b3", +"name": "Get threads with specific labels", +"type": "n8n-nodes-base.gmail", +"position": [ +1180, +580 +], +"parameters": { +"filters": { +"labelIds": [] +}, +"resource": "thread", +"returnAll": true +}, +"credentials": { +"gmailOAuth2": { +"id": "uBcIMfsTtKjexw7I", +"name": "Gmail (workfloowstutorial@gmail.com)" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "9f5262c5-d319-4a9d-af6e-aa42970d1a6f", +"name": "Ask OpenAI Assistant", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +2220, +580 +], +"parameters": { +"text": "={{ $json.text }}", +"prompt": "define", +"options": {}, +"resource": "assistant", +"assistantId": { +"__rl": true, +"mode": "list", +"value": "asst_kmKeAtwF2rv0vgF0ujY4jlp6", +"cachedResultName": "Customer assistant" +} +}, +"credentials": { +"openAiApi": { +"id": "jazew1WAaSRrjcHp", +"name": "OpenAI (workfloows@gmail.com)" +} +}, +"typeVersion": 1 +}, +{ +"id": "6ffd7d66-40b6-49a4-9e15-9742bda73d2f", +"name": "Loop over threads", +"type": "n8n-nodes-base.splitInBatches", +"position": [ +1440, +580 +], +"parameters": { +"options": {} +}, +"typeVersion": 3 +}, +{ +"id": "8afc47c8-075f-4f3d-a89d-fda81fc270fc", +"name": "Get thread messages", +"type": "n8n-nodes-base.gmail", +"position": [ +1700, +820 +], +"parameters": { +"options": { +"returnOnlyMessages": true +}, +"resource": "thread", +"threadId": "={{ $json.id }}", +"operation": "get" +}, +"credentials": { +"gmailOAuth2": { +"id": "uBcIMfsTtKjexw7I", +"name": "Gmail (workfloowstutorial@gmail.com)" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "2286bfa7-dcb8-4a61-a71b-ea58e21bf7ab", +"name": "Return last message in thread", +"type": "n8n-nodes-base.limit", +"position": [ +1920, +820 +], +"parameters": { +"keep": "lastItems" +}, +"typeVersion": 1 +}, +{ +"id": "44c52e61-dd88-4499-85db-69ce4704c2b2", +"name": "Get single message content", +"type": "n8n-nodes-base.gmail", +"position": [ +1700, +460 +], +"parameters": { +"simple": false, +"options": {}, +"messageId": "={{ $json.id }}", +"operation": "get" +}, +"credentials": { +"gmailOAuth2": { +"id": "uBcIMfsTtKjexw7I", +"name": "Gmail (workfloowstutorial@gmail.com)" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "7ca62611-f02e-47bf-b940-3a56ece443b7", +"name": "Sticky Note10", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1640, +340 +], +"parameters": { +"width": 219.88389496558554, +"height": 314.75072291501283, +"content": "### Return message content\nRetrieve content of the last message in the thread." +}, +"typeVersion": 1 +}, +{ +"id": "165df2a4-3c94-456d-9906-be8020098802", +"name": "Sticky Note11", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1640, +680 +], +"parameters": { +"width": 470.88389496558545, +"height": 314.75072291501283, +"content": "### Get last message from thread\nReturn all messages for a single thread and pass for further processing only the last one." +}, +"typeVersion": 1 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"connections": { +"Build email raw": { +"main": [ +[ +{ +"node": "Convert raw to base64", +"type": "main", +"index": 0 +} +] +] +}, +"Loop over threads": { +"main": [ +[ +{ +"node": "Get single message content", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Get thread messages", +"type": "main", +"index": 0 +} +] +] +}, +"Get thread messages": { +"main": [ +[ +{ +"node": "Return last message in thread", +"type": "main", +"index": 0 +} +] +] +}, +"Ask OpenAI Assistant": { +"main": [ +[ +{ +"node": "Map fields for further processing", +"type": "main", +"index": 0 +} +] +] +}, +"Convert raw to base64": { +"main": [ +[ +{ +"node": "Add email draft to thread", +"type": "main", +"index": 0 +} +] +] +}, +"Convert response to HTML": { +"main": [ +[ +{ +"node": "Build email raw", +"type": "main", +"index": 0 +} +] +] +}, +"Schedule trigger (1 min)": { +"main": [ +[ +{ +"node": "Get threads with specific labels", +"type": "main", +"index": 0 +} +] +] +}, +"Add email draft to thread": { +"main": [ +[ +{ +"node": "Remove AI label from email", +"type": "main", +"index": 0 +} +] +] +}, +"Get single message content": { +"main": [ +[ +{ +"node": "Ask OpenAI Assistant", +"type": "main", +"index": 0 +} +] +] +}, +"Return last message in thread": { +"main": [ +[ +{ +"node": "Loop over threads", +"type": "main", +"index": 0 +} +] +] +}, +"Get threads with specific labels": { +"main": [ +[ +{ +"node": "Loop over threads", +"type": "main", +"index": 0 +} +] +] +}, +"Map fields for further processing": { +"main": [ +[ +{ +"node": "Convert response to HTML", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Configure your own Image Creation API Using OpenAI DALLE-3.txt b/Configure your own Image Creation API Using OpenAI DALLE-3.txt new file mode 100644 index 0000000..c08567a --- /dev/null +++ b/Configure your own Image Creation API Using OpenAI DALLE-3.txt @@ -0,0 +1,145 @@ +{ +"id": "wDD4XugmHIvx3KMT", +"meta": { +"instanceId": "149cdf730f0c143663259ddc6124c9c26e824d8d2d059973b871074cf4bda531" +}, +"name": "Image Generation API", +"tags": [], +"nodes": [ +{ +"id": "d743f947-ad45-4e59-97d4-79b98eaddedb", +"name": "Webhook", +"type": "n8n-nodes-base.webhook", +"position": [ +260, +-20 +], +"webhookId": "970dd3c6-de83-46fd-9038-33c470571390", +"parameters": { +"path": "970dd3c6-de83-46fd-9038-33c470571390", +"options": {}, +"responseMode": "responseNode" +}, +"typeVersion": 1.1 +}, +{ +"id": "832e993e-69e9-475b-8322-776d88da0440", +"name": "Respond to Webhook", +"type": "n8n-nodes-base.respondToWebhook", +"position": [ +1400, +-20 +], +"parameters": { +"options": {}, +"respondWith": "binary" +}, +"typeVersion": 1 +}, +{ +"id": "53044a93-375f-48f2-971d-bf765bcdb7a0", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +180, +-120 +], +"parameters": { +"width": 301.7420425026802, +"height": 260.80333469825376, +"content": "## Webhook Trigger \n**This Node starts listening to requests to the Webhook URL**\n\n" +}, +"typeVersion": 1 +}, +{ +"id": "c7b3b04e-903b-4d7c-bbf1-2bc2f1b1a426", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +180, +-460 +], +"parameters": { +"width": 469.32758643852594, +"height": 297.34454352637044, +"content": "## Creating your Prompt-URL \n**To use this Workflow you need to append your prompt to your Webhook URL in the following way**\n\n1. Take your Webhook URL\n2. Ideate a Prompt and Replace every Space (\" \") by %20 (Url Encoding)\n3. Append \"?input=\" and right after that your encoded prompt to your url\n4. Copy paste this into a webbrowser as soon as you run the Webhook" +}, +"typeVersion": 1 +}, +{ +"id": "473ff6e5-441a-4706-86a4-190936cc6ac1", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +540, +-54.959833265087354 +], +"parameters": { +"width": 522.2493371551094, +"height": 109.59833265087394, +"content": "## Starting the Workflow\n**To start the workflow paste the encoded URL into your webbrowser**\n\n" +}, +"typeVersion": 1 +}, +{ +"id": "e8874f52-ef7e-4aea-be5b-81e3276da3d2", +"name": "OpenAI", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +1120, +-20 +], +"parameters": { +"prompt": "={{ $json.query.input }}", +"options": {}, +"resource": "image" +}, +"typeVersion": 1.1 +}, +{ +"id": "08c073a6-e01e-4b04-8051-502c918998c4", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1280, +-120 +], +"parameters": { +"width": 329.4629595446998, +"height": 278.4439182704484, +"content": "## Response\n**Watch the image being rendered in your webbrowser**\n\n" +}, +"typeVersion": 1 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"versionId": "19f7e652-5417-4b02-a1f5-8796bbac25c3", +"connections": { +"OpenAI": { +"main": [ +[ +{ +"node": "Respond to Webhook", +"type": "main", +"index": 0 +} +] +] +}, +"Webhook": { +"main": [ +[ +{ +"node": "OpenAI", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Conversational Interviews with AI Agents and n8n Forms.txt b/Conversational Interviews with AI Agents and n8n Forms.txt new file mode 100644 index 0000000..dfd158a --- /dev/null +++ b/Conversational Interviews with AI Agents and n8n Forms.txt @@ -0,0 +1,1254 @@ +{ +"nodes": [ +{ +"id": "d73e5113-119f-4e62-9872-48e6a971d760", +"name": "Stop Interview?", +"type": "n8n-nodes-base.if", +"position": [ +3380, +920 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "3cf788a6-94d0-4223-9caa-30b8e4df8e01", +"operator": { +"type": "boolean", +"operation": "true", +"singleValue": true +}, +"leftValue": "={{ $json.output.stop_interview }}", +"rightValue": "" +} +] +} +}, +"typeVersion": 2.2 +}, +{ +"id": "cda3c487-97fa-4037-b9a0-0802f4a02727", +"name": "Generate Row", +"type": "n8n-nodes-base.set", +"position": [ +3740, +1200 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "06146a75-b67a-42cf-aa6f-241f23c47b9a", +"name": "timestamp", +"type": "string", +"value": "={{ $now.toISO() }}" +}, +{ +"id": "b0278c64-58a7-487d-b7ba-d102fb5d4a0c", +"name": "type", +"type": "string", +"value": "next_question" +}, +{ +"id": "ba034ca1-408e-422f-b071-dab0ef12fb48", +"name": "question", +"type": "string", +"value": "={{ $('Parse Response').item.json.output.question }}" +}, +{ +"id": "a2231f6e-f507-408e-b598-53888cf8d4b5", +"name": "answer", +"type": "string", +"value": "={{ $('Get Answer').item.json.answer }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "3486f9ae-6a19-4f1f-be46-15376053e71f", +"name": "Generate Row1", +"type": "n8n-nodes-base.set", +"position": [ +3580, +760 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "06146a75-b67a-42cf-aa6f-241f23c47b9a", +"name": "timestamp", +"type": "string", +"value": "={{ $now.toISO() }}" +}, +{ +"id": "b0278c64-58a7-487d-b7ba-d102fb5d4a0c", +"name": "type", +"type": "string", +"value": "stop_interview" +}, +{ +"id": "ba034ca1-408e-422f-b071-dab0ef12fb48", +"name": "question", +"type": "string", +"value": "=None" +}, +{ +"id": "a2231f6e-f507-408e-b598-53888cf8d4b5", +"name": "answer", +"type": "string", +"value": "=None" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "a0e5d40d-e956-4ded-891f-ce5d0f55935f", +"name": "Clear For Next Interview", +"type": "@n8n/n8n-nodes-langchain.memoryManager", +"position": [ +3900, +760 +], +"parameters": { +"mode": "delete", +"deleteMode": "all" +}, +"typeVersion": 1.1 +}, +{ +"id": "66a33fcb-a902-4159-a025-2dff426c1fce", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2580, +860 +], +"parameters": { +"width": 180, +"height": 260, +"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### 🚨 Set Interview Topic Here!" +}, +"typeVersion": 1 +}, +{ +"id": "5cfb7114-a773-4c76-bb3b-7c004be5f799", +"name": "Send Reply To Agent", +"type": "n8n-nodes-base.set", +"position": [ +4060, +1200 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "06a9c730-4756-4bc8-a394-6ff249cf7117", +"name": "answer", +"type": "string", +"value": "={{ $('Get Answer').item.json.answer }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "aa30c462-7dfa-40a7-8e63-bed29b30213c", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1880, +1060 +], +"parameters": { +"color": 7, +"width": 490, +"height": 220, +"content": "## 1. Setup Interview\n[Learn more about the form trigger node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.formtrigger)\n\nThe form trigger node will be our entry point into this workflow and to start, we'll just ask for the user's name to start the interview.\nOur session storage will be using Redis via Upstash.com (you can use regular redis btw!) - whichever way, this ensures a highly scalable system able to handle many users." +}, +"typeVersion": 1 +}, +{ +"id": "5353a7c8-d0e4-429a-ab68-c54d9b845a43", +"name": "Start Interview", +"type": "n8n-nodes-base.formTrigger", +"position": [ +1880, +880 +], +"webhookId": "8d849295-ed30-41ab-a17c-464227cec8fb", +"parameters": { +"options": { +"path": "driving-lessons-survey", +"ignoreBots": true, +"buttonLabel": "Begin Interview!", +"appendAttribution": true, +"useWorkflowTimezone": true +}, +"formTitle": "=UK Practical Driving Test Satisfaction Interview", +"formFields": { +"values": [ +{ +"fieldLabel": "What is your name?", +"placeholder": "ie. Sam Smith", +"requiredField": true +} +] +}, +"responseMode": "lastNode", +"formDescription": "=Thanks for taking part in our Interview. You will be presented with an unending series of questions to help us with your experiences in preparing for and taking the UK Practical Driving Test.\n\nThe interviewer is an AI agent and the questions are dynamically generated. When you're done with answer, simple say STOP to exit the interview. Sessions are deleted after 24 hours." +}, +"typeVersion": 2.2 +}, +{ +"id": "c88a829f-c4b4-4ad4-b121-32b15fae9980", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2840, +600 +], +"parameters": { +"color": 7, +"width": 614, +"height": 280, +"content": "## 2. AI Researcher for Endless Interview Questions\n[Learn more about the AI Agent node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/)\n\nAn AI interviewer is an interesting take on a role traditionally understood as expensive and time-consuming - both in preparation and execution. What if this could be handed off to an AI/LLM, which could perform when it suits the interviewee and ask a never-ending list of open and follow-on questions for deeper insights?\n\nThis is what this AI researcher agent is designed to do! Upon activation, a loop is created where the agent generates the question and the user answers via the form node. This continues until the user asks to stop the interview." +}, +"typeVersion": 1 +}, +{ +"id": "10e5dbe0-0163-4c21-8811-9ce9a2a5063b", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +3580, +1380 +], +"parameters": { +"color": 7, +"width": 580, +"height": 202, +"content": "## 3. Record Answers and Prep for Next Question\n[Learn more about the n8n Form node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.form/)\n\nThe interview is no good if we can't record the answers somewhere for later analysis! Using n8n form node to capture the answer, we can simple push our new question and answer pair to our Redis session to build our transcript before continuing the loop with the agent." +}, +"typeVersion": 1 +}, +{ +"id": "0a0cc961-d364-40d2-9ece-cef7d17c4b45", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +3820, +460 +], +"parameters": { +"color": 7, +"width": 528, +"height": 253, +"content": "## 4. Graciously End the Interview\n[Read more about the Chat Manager node](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.memorymanager/)\n\nOnce the AI/LLM detects the user wishes to end the interview (which is done by the user explicitly saying in the form), then the loop breaks and we conclude the interview session and displaying the confirmation screen.\n\nFor this demo, I've created a special confirmation screen which also displays the transcript. This is done by redirecting to a webhook URL. If you don't need this, feel free to change this to \"show completion screen\" instead.\n" +}, +"typeVersion": 1 +}, +{ +"id": "279d9a67-1d3b-4ffe-a152-33164ef9e2c8", +"name": "Get Answer", +"type": "n8n-nodes-base.form", +"position": [ +3580, +1200 +], +"webhookId": "d96bb88d-db84-4a68-8f02-bcff9cb8429e", +"parameters": { +"options": { +"formTitle": "={{ $json.output.question }}", +"buttonLabel": "Next Question", +"formDescription": "Please answer the question or type \"stop interview\" to end the interview." +}, +"formFields": { +"values": [ +{ +"fieldType": "textarea", +"fieldLabel": "answer", +"requiredField": true +} +] +} +}, +"typeVersion": 1 +}, +{ +"id": "4e284505-afc3-4e3e-88c8-38021efbf3c1", +"name": "Sticky Note5", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1280, +500 +], +"parameters": { +"width": 522.6976744186048, +"height": 787.6241860465118, +"content": "## Try it out! \n\n### Conducting user interviews have been traditionally difficult due to preparation, timing and execution costs. What if we let an AI/LLM do it instead?\n\nThis template enables automated AI/LLM powered user interviews using n8n forms and an AI agent where the question and answers are recorded in a google sheet for later analysis. A powerful tool for any researcher.\n\n### Check out the full showcase post here: https://community.n8n.io/t/build-your-own-ai-interview-agents-with-n8n-forms/62312\n\n### How it works\n* A form trigger is used to start the interview and a new session is created in redis to capture the transcript.\n* An AI agent is then tasked to ask questions to the user regarding the topic of the interview. This is setup as a loop so the questions never stop unless the user wishes to end the interview.\n* Each answer is recorded in our session set up earlier between questions.\n* Finally, when the user requests to end the interview we break the loop and show the interview completion screen.\n\n### Why Redis?\nRedis is a fast key-value datastore which makes it ideal for sessions. This ensures the interview flow stays snappy between questions. For my live demo, I used Upstash.com which has a generous free tier.\n\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": "ff37e943-851f-4ea7-bcab-b33150881b72", +"name": "Set Interview Topic", +"type": "n8n-nodes-base.set", +"position": [ +2620, +880 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "386f91e1-cc3e-4912-84e3-5ecdbf5412c8", +"name": "answer", +"type": "string", +"value": "=Hello, my name is {{ $('Start Interview').first().json['What is your name?'] }}" +}, +{ +"id": "492d5ecc-4e76-4297-b8a7-9ca4f801c855", +"name": "interview_topic", +"type": "string", +"value": "Your experience preparing for and taking the UK practical driving test" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "446937bc-a599-4184-b52e-be0607d62d94", +"name": "UUID", +"type": "n8n-nodes-base.crypto", +"position": [ +2020, +880 +], +"parameters": { +"action": "generate" +}, +"typeVersion": 1 +}, +{ +"id": "da94c22a-4b26-4898-bde8-b57b5bf01f15", +"name": "Generate Row2", +"type": "n8n-nodes-base.set", +"position": [ +2300, +880 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "06146a75-b67a-42cf-aa6f-241f23c47b9a", +"name": "timestamp", +"type": "string", +"value": "={{ $now.toISO() }}" +}, +{ +"id": "b0278c64-58a7-487d-b7ba-d102fb5d4a0c", +"name": "type", +"type": "string", +"value": "start_interview" +}, +{ +"id": "ba034ca1-408e-422f-b071-dab0ef12fb48", +"name": "question", +"type": "string", +"value": "=What is your name?" +}, +{ +"id": "a2231f6e-f507-408e-b598-53888cf8d4b5", +"name": "answer", +"type": "string", +"value": "={{ $('Start Interview').first().json['What is your name?'] }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "9aba23d7-04af-4478-b39b-417f0917597d", +"name": "Create Session", +"type": "n8n-nodes-base.redis", +"position": [ +2160, +880 +], +"parameters": { +"key": "=session_{{ $('UUID').item.json.data }}", +"ttl": "={{ 60 * 60 * 24 }}", +"value": "={{ [] }}", +"expire": true, +"keyType": "list", +"operation": "set" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"typeVersion": 1 +}, +{ +"id": "217c9866-a162-41c6-b123-189869a6cb58", +"name": "Update Session", +"type": "n8n-nodes-base.redis", +"position": [ +2440, +880 +], +"parameters": { +"list": "=session_{{ $('UUID').first().json.data }}", +"tail": true, +"operation": "push", +"messageData": "={{ $json.toJsonString() }}" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"typeVersion": 1 +}, +{ +"id": "95e8b7c4-4f27-49f3-b509-5238c0f7bd5d", +"name": "Update Session1", +"type": "n8n-nodes-base.redis", +"position": [ +3900, +1200 +], +"parameters": { +"list": "=session_{{ $('UUID').first().json.data }}", +"tail": true, +"operation": "push", +"messageData": "={{ $json.toJsonString() }}" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"typeVersion": 1 +}, +{ +"id": "afaa55dd-844e-4bf3-8a31-3a0953caaf69", +"name": "Update Session2", +"type": "n8n-nodes-base.redis", +"position": [ +3740, +760 +], +"parameters": { +"list": "=session_{{ $('UUID').first().json.data }}", +"tail": true, +"operation": "push", +"messageData": "={{ $json.toJsonString() }}" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"typeVersion": 1 +}, +{ +"id": "c381d598-1902-4789-ac15-65ac2124fbdd", +"name": "Valid Session?", +"type": "n8n-nodes-base.if", +"position": [ +5080, +1240 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "500d6ca9-2a04-40f0-98e8-aa4290e6a30d", +"operator": { +"type": "array", +"operation": "exists", +"singleValue": true +}, +"leftValue": "={{ $json.data }}", +"rightValue": "" +} +] +} +}, +"typeVersion": 2.2 +}, +{ +"id": "f26ccdaa-4f94-4acb-894b-341648aee8b0", +"name": "Respond to Webhook", +"type": "n8n-nodes-base.respondToWebhook", +"position": [ +5440, +1240 +], +"parameters": { +"options": { +"responseCode": 200, +"responseHeaders": { +"entries": [ +{ +"name": "Content-Type", +"value": "text/html" +} +] +} +}, +"respondWith": "text", +"responseBody": "={{ $json.html }}" +}, +"typeVersion": 1.1 +}, +{ +"id": "09a05dc6-4a21-4df0-a83d-5e1b986090f8", +"name": "Window Buffer Memory2", +"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", +"position": [ +3000, +1120 +], +"parameters": { +"sessionKey": "={{ $('UUID').first().json.data }}", +"sessionIdType": "customKey" +}, +"typeVersion": 1.2 +}, +{ +"id": "26f87c7d-9e2c-41e8-b7eb-3c249a69f905", +"name": "Window Buffer Memory", +"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", +"position": [ +3900, +920 +], +"parameters": { +"sessionKey": "={{ $('UUID').first().json.data }}", +"sessionIdType": "customKey" +}, +"typeVersion": 1.2 +}, +{ +"id": "ab891c71-af03-49c9-b281-d0058374260b", +"name": "Sticky Note6", +"type": "n8n-nodes-base.stickyNote", +"position": [ +4180, +740 +], +"parameters": { +"width": 276.4353488372094, +"height": 320.31553488372094, +"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### 🚨 Set Your Webhook URL here!\nFor this demo, we want to show a customised completion screen with transcript so it's necessary to redirect to a webhook (see step 6)." +}, +"typeVersion": 1 +}, +{ +"id": "7a063851-1bea-4e34-897c-4038d08b845e", +"name": "Redirect to Completion Screen", +"type": "n8n-nodes-base.form", +"position": [ +4260, +760 +], +"webhookId": "9fdedf1b-e413-4fc3-94a4-9cc24bffff8a", +"parameters": { +"operation": "completion", +"redirectUrl": "=https:///webhook//ai-interview-transcripts/{{ $('UUID').first().json.data }}", +"respondWith": "redirect" +}, +"typeVersion": 1 +}, +{ +"id": "b67b3fa5-faf6-402b-9b9e-c783869770ca", +"name": "Sticky Note7", +"type": "n8n-nodes-base.stickyNote", +"position": [ +4640, +1220 +], +"parameters": { +"color": 5, +"width": 236.3564651162793, +"height": 345.82027906976737, +"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### 🚨 This is the webhook we want to redirect to!\nIf you're on n8n cloud, you may want to copy the webhook url generated here and use it as the form ending's redirect url." +}, +"typeVersion": 1 +}, +{ +"id": "583d1572-2d6f-4ca4-9e31-33dc1481e87a", +"name": "Sticky Note8", +"type": "n8n-nodes-base.stickyNote", +"position": [ +4580, +980 +], +"parameters": { +"color": 7, +"width": 588, +"height": 207, +"content": "## 6. Display the Transcript\n[Read more about the Webhook Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook)\n\nThis step is totally optional. For a nicer user experience, I use this webhook mini-flow to display the user's transcript for the completion screen. It works by capturing the session_id in the webhook's url and searching for it in our redis database. If a match is found the transcript is fetched and rendered into a webpage using the HTML node and returned to the user. If no match is found, a 404 message is displayed instead." +}, +"typeVersion": 1 +}, +{ +"id": "5fcf86b9-3fa3-48f5-a4a4-a1e261a48b49", +"name": "Webhook", +"type": "n8n-nodes-base.webhook", +"position": [ +4700, +1240 +], +"webhookId": "78df12c4-ccd0-46dd-be0d-4445c2bd04f2", +"parameters": { +"path": "ai-interview-transcripts/:session_id", +"options": { +"ignoreBots": true +}, +"responseMode": "responseNode" +}, +"typeVersion": 2 +}, +{ +"id": "6df57307-feef-4be5-861d-fdc0b92d1ef6", +"name": "404 Not Found", +"type": "n8n-nodes-base.html", +"position": [ +5260, +1320 +], +"parameters": { +"html": "\n\n\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\n\t\tDriving Practice Test 2024 Survey\n\n\t\t\n\t\n\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t

404 Not Found

\n\t\t\t\t\t\t

The requested session does not exist.

\n

Your session may have expired.

\n
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t
\n\t\t
\n\t\n\n" +}, +"typeVersion": 1.2 +}, +{ +"id": "0e968154-ead5-4194-834e-0d1175e7c1d9", +"name": "AI Researcher", +"type": "@n8n/n8n-nodes-langchain.agent", +"position": [ +2900, +920 +], +"parameters": { +"text": "={{ $json.answer }}", +"options": { +"systemMessage": "=You are a user research expert interviewing a user on the topic of \"{{ $('Set Interview Topic').first().json.interview_topic }}\".\n\n* Your task is to ask open-ended questions relevant to the interview topic.\n* Ask only one question at a time. Analyse the previous question and ask new question each time. If there is an opportunity to dig deeper into a previous answer, do so but limit to 1 follow-on question.\n* Keep asking questions until the user requests to stop the interview. When the user requests to stop the interview and no question is required, \"question\" is an empty string.\n* Use a friendly and polite tone when asking questions.\n* If the user answers are inrelevant to the question, ask the question again or move on to another question.\n* If the user's answer is beyond the scope of the interview, ignore the answer and ask if the user would like to stop the interview.\n*You must format your response using the following json schema as we require pre processing before responding to the user.\n```\n{\n \"type\":\"object\",\n \"properties\": {\n \"stop_interview\": { \"type\": \"boolean\" },\n \"question\": { \"type\": [\"string\", \"null\"] }\n }\n}\n```\n* Output only the json object and do not prefix or suffix the message with extraneous text." +}, +"promptType": "define", +"hasOutputParser": true +}, +"typeVersion": 1.7 +}, +{ +"id": "969d4094-1046-4f53-bf8b-5ae7e50bd3ed", +"name": "Parse Response", +"type": "n8n-nodes-base.set", +"position": [ +3220, +920 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "bf61134c-e24c-453e-97ef-5edd25726148", +"name": "output", +"type": "object", +"value": "={{\n$json.output\n .replace('```json', '')\n .replace('```', '')\n .parseJson()\n}}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "323b73c4-8c77-48a9-a549-f3e863ba72c2", +"name": "Groq Chat Model", +"type": "@n8n/n8n-nodes-langchain.lmChatGroq", +"position": [ +2860, +1120 +], +"parameters": { +"model": "llama-3.2-90b-text-preview", +"options": {} +}, +"credentials": { +"groqApi": { +"id": "YQVoV5K9FREww7t1", +"name": "Groq account" +} +}, +"typeVersion": 1 +}, +{ +"id": "bf4518c4-8e59-450e-be5a-92f31cf38528", +"name": "Show Transcript", +"type": "n8n-nodes-base.html", +"position": [ +5260, +1140 +], +"parameters": { +"html": "\n\n\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\n\t\tAI Interviewer Transcripts\n\n\t\t\n\t\n\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t

Thanks for Completing the Interview!

\n\t\t\t\t\t\t

If you liked this demo,
please follow me on http://linkedin.com/in/jimleuk and\n https://x.com/jimle_uk\n

\n

\n \n Support my work! Sign up to n8n using this link 🙏\n \n

\n
\n\t\t\t\t
\n
\n\t\t\t\t\t
\n\t\t\t\t\t\t

Transcript

\n

This session is deleted within 24 hours.

\n {{\n $json.data\n .map(item => JSON.parse(item))\n .filter(item => item.type === 'next_question')\n .map(item => `\n
\n
\n ${DateTime.fromISO(item.timestamp).format('dd MMM, hh:mm')}\n
\n
\n
${item.question}
\n
${item.answer}
\n
\n
\n `)\n .join('\\n')\n }}\n \t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t
\n\t\t
\n\t\n\n" +}, +"typeVersion": 1.2 +}, +{ +"id": "dff24e45-8e57-4dfc-8b65-9d315b406bd2", +"name": "Save to Google Sheet", +"type": "n8n-nodes-base.googleSheets", +"position": [ +5040, +760 +], +"parameters": { +"columns": { +"value": { +"name": "{{ $('Start Interview').first().json['What is your name?'] }}", +"session_id": "={{ $('UUID').first().json.data }}" +}, +"schema": [ +{ +"id": "session_id", +"type": "string", +"display": true, +"required": false, +"displayName": "session_id", +"defaultMatch": false, +"canBeUsedToMatch": true +}, +{ +"id": "timestamp", +"type": "string", +"display": true, +"required": false, +"displayName": "timestamp", +"defaultMatch": false, +"canBeUsedToMatch": true +}, +{ +"id": "name", +"type": "string", +"display": true, +"required": false, +"displayName": "name", +"defaultMatch": false, +"canBeUsedToMatch": true +}, +{ +"id": "type", +"type": "string", +"display": true, +"required": false, +"displayName": "type", +"defaultMatch": false, +"canBeUsedToMatch": true +}, +{ +"id": "question", +"type": "string", +"display": true, +"required": false, +"displayName": "question", +"defaultMatch": false, +"canBeUsedToMatch": true +}, +{ +"id": "answer", +"type": "string", +"display": true, +"required": false, +"displayName": "answer", +"defaultMatch": false, +"canBeUsedToMatch": true +} +], +"mappingMode": "autoMapInputData", +"matchingColumns": [] +}, +"options": { +"useAppend": true +}, +"operation": "append", +"sheetName": { +"__rl": true, +"mode": "list", +"value": 1695693704, +"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wKjVdm7HeufJkHrUJn_bW9bFI_blm0laoI_jgXKDe0Q/edit#gid=1695693704", +"cachedResultName": "transcripts" +}, +"documentId": { +"__rl": true, +"mode": "list", +"value": "1wKjVdm7HeufJkHrUJn_bW9bFI_blm0laoI_jgXKDe0Q", +"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wKjVdm7HeufJkHrUJn_bW9bFI_blm0laoI_jgXKDe0Q/edit?usp=drivesdk", +"cachedResultName": "AI Researcher with n8n Forms" +} +}, +"credentials": { +"googleSheetsOAuth2Api": { +"id": "FsFwFchwmgtBu5l7", +"name": "Google Sheets account" +} +}, +"typeVersion": 4.5 +}, +{ +"id": "8eb03a1c-02e4-4d49-bf68-bb148585828f", +"name": "Session to List", +"type": "n8n-nodes-base.splitOut", +"position": [ +4700, +760 +], +"parameters": { +"options": {}, +"fieldToSplitOut": "session" +}, +"typeVersion": 1 +}, +{ +"id": "c594aa2b-a29d-42e4-8799-1c557d78932d", +"name": "Messages To JSON", +"type": "n8n-nodes-base.set", +"position": [ +4860, +760 +], +"parameters": { +"mode": "raw", +"options": {}, +"jsonOutput": "={{\n{\n ...$json.session.parseJson(),\n session_id: `session_${$('UUID').first().json.data}`,\n name: $('Start Interview').first().json['What is your name?'],\n}\n}}" +}, +"typeVersion": 3.4 +}, +{ +"id": "106bd688-6ccc-4a6a-9b52-ee7187d9aebe", +"name": "Sticky Note9", +"type": "n8n-nodes-base.stickyNote", +"position": [ +4540, +420 +], +"parameters": { +"color": 7, +"width": 508, +"height": 293, +"content": "## 5. Save the Interview to Sheets\n[Read more about the Google Sheets node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlesheets/)\n\nFor easier data-sharing, we can have the workflow upload the session messages into data analysis tools for our team members.\n\nFor this demo, Google Sheets is an easy option. We'll pull the entire session out of redis and upload the messages one by one to sheets.\n\n### Check out the example sheet here: https://docs.google.com/spreadsheets/d/1wKjVdm7HeufJkHrUJn_bW9bFI_blm0laoI_jgXKDe0Q/edit?usp=sharing" +}, +"typeVersion": 1 +}, +{ +"id": "b7754724-7473-4245-8b54-85c370a2b1be", +"name": "Query By Session", +"type": "n8n-nodes-base.redis", +"position": [ +4920, +1240 +], +"parameters": { +"key": "=session_{{ $('Webhook').first().json.params.session_id }}", +"options": {}, +"operation": "get", +"propertyName": "data" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"typeVersion": 1 +}, +{ +"id": "4b6a0db6-1d33-4ed3-a955-7562e0dba1f0", +"name": "Get Session", +"type": "n8n-nodes-base.redis", +"position": [ +4540, +760 +], +"parameters": { +"key": "=session_{{ $('UUID').first().json.data }}", +"keyType": "list", +"options": {}, +"operation": "get", +"propertyName": "session" +}, +"credentials": { +"redis": { +"id": "AbPH1yYQ924bVUqm", +"name": "Upstash (ai interviewer)" +} +}, +"executeOnce": true, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"UUID": { +"main": [ +[ +{ +"node": "Create Session", +"type": "main", +"index": 0 +} +] +] +}, +"Webhook": { +"main": [ +[ +{ +"node": "Query By Session", +"type": "main", +"index": 0 +} +] +] +}, +"Get Answer": { +"main": [ +[ +{ +"node": "Generate Row", +"type": "main", +"index": 0 +} +] +] +}, +"Get Session": { +"main": [ +[ +{ +"node": "Session to List", +"type": "main", +"index": 0 +} +] +] +}, +"Generate Row": { +"main": [ +[ +{ +"node": "Update Session1", +"type": "main", +"index": 0 +} +] +] +}, +"404 Not Found": { +"main": [ +[ +{ +"node": "Respond to Webhook", +"type": "main", +"index": 0 +} +] +] +}, +"AI Researcher": { +"main": [ +[ +{ +"node": "Parse Response", +"type": "main", +"index": 0 +} +] +] +}, +"Generate Row1": { +"main": [ +[ +{ +"node": "Update Session2", +"type": "main", +"index": 0 +} +] +] +}, +"Generate Row2": { +"main": [ +[ +{ +"node": "Update Session", +"type": "main", +"index": 0 +} +] +] +}, +"Create Session": { +"main": [ +[ +{ +"node": "Generate Row2", +"type": "main", +"index": 0 +} +] +] +}, +"Parse Response": { +"main": [ +[ +{ +"node": "Stop Interview?", +"type": "main", +"index": 0 +} +] +] +}, +"Update Session": { +"main": [ +[ +{ +"node": "Set Interview Topic", +"type": "main", +"index": 0 +} +] +] +}, +"Valid Session?": { +"main": [ +[ +{ +"node": "Show Transcript", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "404 Not Found", +"type": "main", +"index": 0 +} +] +] +}, +"Groq Chat Model": { +"ai_languageModel": [ +[ +{ +"node": "AI Researcher", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Session to List": { +"main": [ +[ +{ +"node": "Messages To JSON", +"type": "main", +"index": 0 +} +] +] +}, +"Show Transcript": { +"main": [ +[ +{ +"node": "Respond to Webhook", +"type": "main", +"index": 0 +} +] +] +}, +"Start Interview": { +"main": [ +[ +{ +"node": "UUID", +"type": "main", +"index": 0 +} +] +] +}, +"Stop Interview?": { +"main": [ +[ +{ +"node": "Generate Row1", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Get Answer", +"type": "main", +"index": 0 +} +] +] +}, +"Update Session1": { +"main": [ +[ +{ +"node": "Send Reply To Agent", +"type": "main", +"index": 0 +} +] +] +}, +"Update Session2": { +"main": [ +[ +{ +"node": "Clear For Next Interview", +"type": "main", +"index": 0 +} +] +] +}, +"Messages To JSON": { +"main": [ +[ +{ +"node": "Save to Google Sheet", +"type": "main", +"index": 0 +} +] +] +}, +"Query By Session": { +"main": [ +[ +{ +"node": "Valid Session?", +"type": "main", +"index": 0 +} +] +] +}, +"Send Reply To Agent": { +"main": [ +[ +{ +"node": "AI Researcher", +"type": "main", +"index": 0 +} +] +] +}, +"Set Interview Topic": { +"main": [ +[ +{ +"node": "AI Researcher", +"type": "main", +"index": 0 +} +] +] +}, +"Window Buffer Memory": { +"ai_memory": [ +[ +{ +"node": "Clear For Next Interview", +"type": "ai_memory", +"index": 0 +} +] +] +}, +"Window Buffer Memory2": { +"ai_memory": [ +[ +{ +"node": "AI Researcher", +"type": "ai_memory", +"index": 0 +} +] +] +}, +"Clear For Next Interview": { +"main": [ +[ +{ +"node": "Redirect to Completion Screen", +"type": "main", +"index": 0 +} +] +] +}, +"Redirect to Completion Screen": { +"main": [ +[ +{ +"node": "Get Session", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Convert URL HTML to Markdown Format and Get Page Links.txt b/Convert URL HTML to Markdown Format and Get Page Links.txt new file mode 100644 index 0000000..ab45e34 --- /dev/null +++ b/Convert URL HTML to Markdown Format and Get Page Links.txt @@ -0,0 +1,427 @@ +{ +"meta": { +"instanceId": "6b6a2db47bdf8371d21090c511052883cc9a3f6af5d0d9d567c702d74a18820e" +}, +"nodes": [ +{ +"id": "f4570aad-db25-4dcd-8589-b1c8335935de", +"name": "When clicking ‘Test workflow’", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +-180, +3800 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "bd481559-85f2-4865-8d85-e50e72369f26", +"name": "Wait", +"type": "n8n-nodes-base.wait", +"position": [ +940, +3620 +], +"webhookId": "f10708f0-38c6-4c75-b635-37222d5b183a", +"parameters": { +"amount": 45 +}, +"typeVersion": 1.1 +}, +{ +"id": "cc9e9947-19e4-47c5-95b0-a631d688a8b6", +"name": "Sticky Note36", +"type": "n8n-nodes-base.stickyNote", +"position": [ +549.7858793743054, +3709.534654112671 +], +"parameters": { +"color": 7, +"width": 327.8244990224782, +"height": 268.48353140372035, +"content": "**40 at a time seems to be the memory limit on my server - run until complete with batches of 40 or increase based on your server memory**\n" +}, +"typeVersion": 1 +}, +{ +"id": "9ebbd993-9194-40b1-a98e-352eb3a3f9eb", +"name": "Sticky Note28", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-50.797941767307435, +3729.028866440868 +], +"parameters": { +"color": 7, +"width": 574.7594700148138, +"height": 248.90718753310907, +"content": "**Firecrawl.dev retrieves markdown inc. title, description, links & content. First define the URLs you'd like to scrape**\n" +}, +"typeVersion": 1 +}, +{ +"id": "71c0f975-c0f9-47ae-a245-f852387ad461", +"name": "Connect to your own data source", +"type": "n8n-nodes-base.noOp", +"position": [ +1380, +3820 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "fba918e7-2c88-4de3-a789-cadbf4f2584e", +"name": "Get urls from own data source", +"type": "n8n-nodes-base.noOp", +"position": [ +0, +3800 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "221a75eb-0bc8-4747-9ec1-1879c46d9163", +"name": "Example fields from data source", +"type": "n8n-nodes-base.set", +"notes": "Define URLs in array", +"position": [ +200, +3800 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "cc2c6af0-68d3-49eb-85fe-3288d2ed0f6b", +"name": "Page", +"type": "array", +"value": "[\"https://www.automake.io/\", \"https://www.n8n.io/\"]" +} +] +}, +"includeOtherFields": true +}, +"notesInFlow": true, +"typeVersion": 3.4 +}, +{ +"id": "5a914964-e8ef-4064-8ecb-f1866de0d8c6", +"name": "Sticky Note33", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-40, +4000 +], +"parameters": { +"color": 3, +"width": 510.3561134140244, +"height": 94.13486342358942, +"content": "**REQUIRED**\nConnect to your database of urls to input. Name the column `Page` like in the `Example fields from data source` node and make sure it has one link per row like `split out page urls`" +}, +"typeVersion": 1 +}, +{ +"id": "5c004d5c-afeb-47c9-b30b-eb88880f87b9", +"name": "Sticky Note34", +"type": "n8n-nodes-base.stickyNote", +"position": [ +900, +4000 +], +"parameters": { +"color": 3, +"width": 284.87764467541297, +"height": 168.68864948728321, +"content": "**REQUIRED**\nUpdate the Auth parameter to your own [Firecrawl](https://firecrawl.dev) dev token\n\n**Header Auth parameter**\nname - Authorization\nvalue - your-own-api-key" +}, +"typeVersion": 1 +}, +{ +"id": "53d97054-a5e4-4819-bdd9-f8632c33eba2", +"name": "Sticky Note35", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1360, +4000 +], +"parameters": { +"color": 3, +"width": 284.87764467541297, +"height": 91.91340067739628, +"content": "**REQUIRED** \nOutput the data to your own data source e.g. Airtable" +}, +"typeVersion": 1 +}, +{ +"id": "357a463f-7581-43ba-8930-af27e4762905", +"name": "Sticky Note37", +"type": "n8n-nodes-base.stickyNote", +"position": [ +900, +3570.2075673933587 +], +"parameters": { +"color": 7, +"width": 181.96744211154697, +"height": 189.23753199986137, +"content": "**Respect API limits (10 requests per min)**\n" +}, +"typeVersion": 1 +}, +{ +"id": "77311c67-f50f-427a-87fd-b29b1f542bbc", +"name": "40 items at a time", +"type": "n8n-nodes-base.limit", +"position": [ +580, +3800 +], +"parameters": { +"maxItems": 40 +}, +"typeVersion": 1 +}, +{ +"id": "43557ab1-4e52-4598-83a9-e39d5afc6de7", +"name": "10 at a time", +"type": "n8n-nodes-base.splitInBatches", +"position": [ +740, +3800 +], +"parameters": { +"options": {}, +"batchSize": 10 +}, +"typeVersion": 3 +}, +{ +"id": "555d52e7-010b-462b-9382-26804493de1c", +"name": "Markdown data and Links", +"type": "n8n-nodes-base.set", +"position": [ +1160, +3820 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "3a959c64-4c3c-4072-8427-67f6f6ecba1b", +"name": "title", +"type": "string", +"value": "={{ $json.data.metadata.title }}" +}, +{ +"id": "d2da0859-a7a0-4c39-913a-150ecb95d075", +"name": "description", +"type": "string", +"value": "={{ $json.data.metadata.description }}" +}, +{ +"id": "62bd2d76-b78d-4501-a59b-a25ed7b345b0", +"name": "content", +"type": "string", +"value": "={{ $json.data.markdown }}" +}, +{ +"id": "d4c712fa-b52a-498f-8abc-26dc72be61f7", +"name": "links", +"type": "string", +"value": "={{ $json.data.links }} " +} +] +} +}, +"notesInFlow": true, +"typeVersion": 3.4 +}, +{ +"id": "aac948e6-ac86-4cea-be84-f27919d6d936", +"name": "Split out page URLs", +"type": "n8n-nodes-base.splitOut", +"position": [ +380, +3800 +], +"parameters": { +"options": {}, +"fieldToSplitOut": "Page" +}, +"typeVersion": 1 +}, +{ +"id": "71c5a0d4-540e-4766-ae99-bdc427019dac", +"name": "Retrieve Page Markdown and Links", +"type": "n8n-nodes-base.httpRequest", +"notes": "curl -X POST https://api.firecrawl.dev/v1/scrape \\\n -H 'Content-Type: application/json' \\\n -H 'Authorization: Bearer YOUR_API_KEY' \\\n -d '{\n \"url\": \"https://docs.firecrawl.dev\",\n \"formats\" : [\"markdown\", \"html\"]\n }'\n", +"position": [ +960, +3820 +], +"parameters": { +"url": "https://api.firecrawl.dev/v1/scrape", +"method": "POST", +"options": {}, +"jsonBody": "={\n \"url\": \"{{ $json.Page }}\",\n \"formats\" : [\"markdown\", \"links\"]\n} ", +"sendBody": true, +"sendHeaders": true, +"specifyBody": "json", +"authentication": "genericCredentialType", +"genericAuthType": "httpHeaderAuth", +"headerParameters": { +"parameters": [ +{ +"name": "Content-Type", +"value": "application/json" +} +] +} +}, +"credentials": { +"httpHeaderAuth": { +"id": "nbamiF1MDku2NNz7", +"name": "Firecrawl Bearer" +} +}, +"retryOnFail": true, +"typeVersion": 4.2, +"waitBetweenTries": 5000 +}, +{ +"id": "a2f12929-262e-4354-baa3-f9e3c05ec2eb", +"name": "Sticky Note38", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-840, +3340 +], +"parameters": { +"color": 4, +"width": 581.9949654101088, +"height": 818.5240734585421, +"content": "## Convert URL HTML to Markdown and Get Page Links\n\n## Use Case\nTransform web pages into AI-friendly markdown format:\n- You need to process webpage content for LLM analysis\n- You want to extract both content and links from web pages\n- You need clean, formatted text without HTML markup\n- You want to respect API rate limits while crawling pages\n\n## What this Workflow Does\nThe workflow uses Firecrawl.dev API to process webpages:\n- Converts HTML content to markdown format\n- Extracts all links from each webpage\n- Handles API rate limiting automatically\n- Processes URLs in batches from your database\n\n## Setup\n1. Create a [Firecrawl.dev](https://www.firecrawl.dev/) account and get your API key\n2. Add your Firecrawl API key to the HTTP Request node's Authorization header\n3. Connect your URL database to the input node (column name must be \"Page\") or edit the array in `Example fields from data source`\n4. Configure your preferred output database connection\n\n## How to Adjust it to Your Needs\n- Modify input source to pull URLs from different databases\n- Adjust rate limiting parameters if needed\n- Customize output format for your specific use case\n\n\nMade by Simon @ [automake.io](https://automake.io)\n" +}, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"Wait": { +"main": [ +[ +{ +"node": "10 at a time", +"type": "main", +"index": 0 +} +] +] +}, +"10 at a time": { +"main": [ +null, +[ +{ +"node": "Retrieve Page Markdown and Links", +"type": "main", +"index": 0 +} +] +] +}, +"40 items at a time": { +"main": [ +[ +{ +"node": "10 at a time", +"type": "main", +"index": 0 +} +] +] +}, +"Split out page URLs": { +"main": [ +[ +{ +"node": "40 items at a time", +"type": "main", +"index": 0 +} +] +] +}, +"Markdown data and Links": { +"main": [ +[ +{ +"node": "Connect to your own data source", +"type": "main", +"index": 0 +} +] +] +}, +"Get urls from own data source": { +"main": [ +[ +{ +"node": "Example fields from data source", +"type": "main", +"index": 0 +} +] +] +}, +"Connect to your own data source": { +"main": [ +[ +{ +"node": "Wait", +"type": "main", +"index": 0 +} +] +] +}, +"Example fields from data source": { +"main": [ +[ +{ +"node": "Split out page URLs", +"type": "main", +"index": 0 +} +] +] +}, +"Retrieve Page Markdown and Links": { +"main": [ +[ +{ +"node": "Markdown data and Links", +"type": "main", +"index": 0 +} +] +] +}, +"When clicking ‘Test workflow’": { +"main": [ +[ +{ +"node": "Get urls from own data source", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Convert text to speech with OpenAI.txt b/Convert text to speech with OpenAI.txt new file mode 100644 index 0000000..3324d9d --- /dev/null +++ b/Convert text to speech with OpenAI.txt @@ -0,0 +1,192 @@ +{ +"id": "6Yzmlp5xF6oHo1VW", +"meta": { +"instanceId": "173f55e6572798fa42ea9c5c92623a3c3308080d3fcd2bd784d26d855b1ce820" +}, +"name": "Text to Speech (OpenAI)", +"tags": [], +"nodes": [ +{ +"id": "938fedbd-e34c-40af-af2f-b9c669e1a6e9", +"name": "When clicking \"Test workflow\"", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +380, +380 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "1d59db5d-8fe6-4292-a221-a0d0194c6e0c", +"name": "Set input text and TTS voice", +"type": "n8n-nodes-base.set", +"position": [ +760, +380 +], +"parameters": { +"mode": "raw", +"options": {}, +"jsonOutput": "{\n \"input_text\": \"The quick brown fox jumped over the lazy dog.\",\n \"voice\": \"alloy\"\n}\n" +}, +"typeVersion": 3.2 +}, +{ +"id": "9d54de1d-59b7-4c1f-9e88-13572da5292c", +"name": "Send HTTP Request to OpenAI's TTS Endpoint", +"type": "n8n-nodes-base.httpRequest", +"position": [ +1120, +380 +], +"parameters": { +"url": "https://api.openai.com/v1/audio/speech", +"method": "POST", +"options": {}, +"sendBody": true, +"sendHeaders": true, +"authentication": "predefinedCredentialType", +"bodyParameters": { +"parameters": [ +{ +"name": "model", +"value": "tts-1" +}, +{ +"name": "input", +"value": "={{ $json.input_text }}" +}, +{ +"name": "voice", +"value": "={{ $json.voice }}" +} +] +}, +"headerParameters": { +"parameters": [ +{ +"name": "Authorization", +"value": "Bearer $OPENAI_API_KEY" +} +] +}, +"nodeCredentialType": "openAiApi" +}, +"credentials": { +"openAiApi": { +"id": "VokTSv2Eg5m5aDg7", +"name": "OpenAi account" +} +}, +"typeVersion": 4.1 +}, +{ +"id": "1ce72c9c-aa6f-4a18-9d5a-3971686a51ec", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +280, +256 +], +"parameters": { +"width": 273, +"height": 339, +"content": "## Workflow Trigger\nYou can replace this manual trigger with another trigger type as required by your use case." +}, +"typeVersion": 1 +}, +{ +"id": "eb487535-5f36-465e-aeee-e9ff62373e53", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +660, +257 +], +"parameters": { +"width": 273, +"height": 335, +"content": "## Manually Set OpenAI TTS Configuration\n" +}, +"typeVersion": 1 +}, +{ +"id": "36b380bd-0703-4b60-83cb-c4ad9265864d", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1020, +260 +], +"parameters": { +"width": 302, +"height": 335, +"content": "## Send Request to OpenAI TTS API\n" +}, +"typeVersion": 1 +}, +{ +"id": "ff35ff28-62b5-49c8-a657-795aa916b524", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +660, +620 +], +"parameters": { +"color": 4, +"width": 273, +"height": 278, +"content": "### Configuration Options\n- \"input_text\" is the text you would like to be turned into speech, and can be replaced with a programmatic value for your use case. Bear in mind that the maximum number of tokens per API call is 4,000.\n\n- \"voice\" is the voice used by the TTS model. The default is alloy, other options can be found here: [OpenAI TTS Docs](https://platform.openai.com/docs/guides/text-to-speech)" +}, +"typeVersion": 1 +}, +{ +"id": "5f7ef80e-b5c8-41df-9411-525fafc2d910", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1020, +620 +], +"parameters": { +"color": 4, +"width": 299, +"height": 278, +"content": "### Output\nThe output returned by OpenAI's TTS endpoint is a .mp3 audio file (binary).\n\n\n### Credentials\nTo use this workflow, you'll have to configure and provide a valid OpenAI credential.\n" +}, +"typeVersion": 1 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"versionId": "19d67805-e208-4f0e-af44-c304e66e8ce8", +"connections": { +"Set input text and TTS voice": { +"main": [ +[ +{ +"node": "Send HTTP Request to OpenAI's TTS Endpoint", +"type": "main", +"index": 0 +} +] +] +}, +"When clicking \"Test workflow\"": { +"main": [ +[ +{ +"node": "Set input text and TTS voice", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Create a Branded AI-Powered Website Chatbot.txt b/Create a Branded AI-Powered Website Chatbot.txt new file mode 100644 index 0000000..6cee604 --- /dev/null +++ b/Create a Branded AI-Powered Website Chatbot.txt @@ -0,0 +1,754 @@ +{ +"meta": { +"instanceId": "67d4d33d8b0ad4e5e12f051d8ad92fc35893d7f48d7f801bc6da4f39967b3592", +"templateCredsSetupCompleted": true +}, +"nodes": [ +{ +"id": "22c8d63b-ce3c-4aab-b3f6-4bae8c1b9ec5", +"name": "Window Buffer Memory", +"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", +"position": [ +1460, +880 +], +"parameters": { +"sessionKey": "={{ $json.sessionId }}", +"sessionIdType": "customKey", +"contextWindowLength": 20 +}, +"typeVersion": 1.2 +}, +{ +"id": "45403d5c-6e85-424f-b40b-c6214b57457b", +"name": "Respond to Webhook", +"type": "n8n-nodes-base.respondToWebhook", +"position": [ +1880, +580 +], +"parameters": { +"options": {} +}, +"typeVersion": 1.1 +}, +{ +"id": "1111262a-1743-4bae-abf1-f69d2e1a580c", +"name": "OpenAI Chat Model", +"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", +"position": [ +1360, +760 +], +"parameters": { +"model": "gpt-4o-2024-08-06", +"options": { +"temperature": 0.4 +} +}, +"credentials": { +"openAiApi": { +"id": "XWFTuTtx9oWglhNn", +"name": "OpenAi account" +} +}, +"typeVersion": 1 +}, +{ +"id": "df891547-c715-4dc6-bfcc-c0ac5cfcaf02", +"name": "Make Appointment", +"type": "@n8n/n8n-nodes-langchain.toolHttpRequest", +"position": [ +1820, +840 +], +"parameters": { +"url": "https://graph.microsoft.com/v1.0/me/events", +"method": "POST", +"jsonBody": "{\n \"subject\": \"Meetings with at \",\n \"start\": {\n \"dateTime\": \"{dateStartTime}\",\n \"timeZone\": \"Europe/London\"\n },\n \"end\": {\n \"dateTime\": \"{dateEndTime}\",\n \"timeZone\": \"Europe/London\"\n },\n \"body\": {\n \"contentType\": \"HTML\",\n \"content\": \"{reason}\"\n },\n \"attendees\": [\n {\n \"emailAddress\": {\n \"address\": \"{email}\",\n \"name\": \"{name}\"\n },\n \"type\": \"required\"\n }\n ],\n \"location\": {\n \"displayName\": \"Online Meeting\"\n },\n \"isOnlineMeeting\": true,\n \"onlineMeetingProvider\": \"teamsForBusiness\",\n \"showAs\": \"busy\",\n \"categories\": [\n \"Meeting\"\n ]\n}", +"sendBody": true, +"sendQuery": true, +"specifyBody": "json", +"authentication": "predefinedCredentialType", +"parametersQuery": { +"values": [ +{ +"name": "Content-Type", +"value": "application/json", +"valueProvider": "fieldValue" +} +] +}, +"toolDescription": "Call this tool to make the appointment, ensure you send the user email, name, company, reason for the meeting and the appointment start time and the date in ISO String format with timezone for . When creating an appointment, always send JSON.", +"nodeCredentialType": "microsoftOutlookOAuth2Api", +"placeholderDefinitions": { +"values": [ +{ +"name": "dateStartTime", +"type": "string", +"description": "The date and start time of the appointment in toISOString format with timezone for Europe/London" +}, +{ +"name": "dateEndTime", +"type": "string", +"description": "The date and end time of the appointment in toISOString format, always 30 minutes after the dateStartTime, format with timezone for Europe/London" +}, +{ +"name": "reason", +"type": "string", +"description": "Detailed description of the meeting, will be sent to us and the customer" +}, +{ +"name": "email", +"type": "string", +"description": "The customers email address." +}, +{ +"name": "name", +"type": "string", +"description": "The customers full name, must be second and last name" +} +] +} +}, +"credentials": { +"microsoftOutlookOAuth2Api": { +"id": "E0WY3yUNKgrxIwLU", +"name": "Microsoft Outlook Business" +} +}, +"typeVersion": 1.1 +}, +{ +"id": "44141c44-de49-4707-b287-24007c84ca21", +"name": "Execute Workflow Trigger", +"type": "n8n-nodes-base.executeWorkflowTrigger", +"position": [ +2160, +580 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "795e1451-57d8-4563-8b86-5a75df2427b6", +"name": "varResponse", +"type": "n8n-nodes-base.set", +"position": [ +3120, +460 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "c0b6e779-0f7b-41f0-81f8-457f2b31ccfe", +"name": "response", +"type": "array", +"value": "={{ $json.freeTimeSlots.toJsonString() }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "4283635f-649c-4cc7-84b9-37524ddb6ce0", +"name": "freeTimeSlots", +"type": "n8n-nodes-base.code", +"position": [ +2900, +460 +], +"parameters": { +"jsCode": "// Input: An array with objects containing a 'value' array of events.\nconst businessHoursStart = \"08:00:00Z\"; // Business hours start time\nconst businessHoursEnd = \"17:30:00Z\"; // Business hours end time\n\nconst inputData = items[0].json.value; // Assuming the input data is in the 'value' array of the first item\n\n// Function to convert ISO datetime string to a Date object with specified time\nfunction getDateWithTime(dateString, time) {\n const datePart = new Date(dateString).toISOString().split(\"T\")[0]; // Extract the date part (YYYY-MM-DD)\n return new Date(`${datePart}T${time}`);\n}\n\n// Function to get day of the week from a date string\nfunction getDayOfWeek(dateString) {\n const daysOfWeek = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"];\n return daysOfWeek[new Date(dateString).getUTCDay()];\n}\n\n// Organise events by date\nconst eventsByDate = {};\ninputData.forEach(event => {\n const eventDate = new Date(event.start.dateTime).toISOString().split(\"T\")[0]; // Extract the date\n if (!eventsByDate[eventDate]) {\n eventsByDate[eventDate] = [];\n }\n if (event.showAs === \"busy\") {\n eventsByDate[eventDate].push({\n start: new Date(event.start.dateTime),\n end: new Date(event.end.dateTime),\n timeZone: event.start.timeZone // Add timeZone to the event object\n });\n }\n});\n\n// Find free slots within business hours for each date\nconst freeTimeSlots = [];\n\nfor (const [date, busyEvents] of Object.entries(eventsByDate)) {\n // Sort events by their start time\n busyEvents.sort((a, b) => a.start - b.start);\n\n // Define business start and end times for the current date\n const businessStart = getDateWithTime(date, businessHoursStart);\n const businessEnd = getDateWithTime(date, businessHoursEnd);\n\n let freeStart = businessStart;\n\n // Loop through busy events to find free slots\n for (const event of busyEvents) {\n if (freeStart < event.start) {\n // Add free slot if there's a gap between freeStart and the event start\n freeTimeSlots.push({\n date,\n dayOfWeek: getDayOfWeek(date), // Add day of the week key\n freeStart: freeStart.toISOString(),\n freeEnd: event.start.toISOString(),\n timeZone: event.timeZone // Add the timezone for the free slot\n });\n }\n // Move freeStart to the end of the current busy event\n freeStart = event.end;\n }\n\n // Check if there's free time after the last busy event until the end of business hours\n if (freeStart < businessEnd) {\n freeTimeSlots.push({\n date,\n dayOfWeek: getDayOfWeek(date), // Add day of the week key\n freeStart: freeStart.toISOString(),\n freeEnd: businessEnd.toISOString(),\n timeZone: busyEvents[0].timeZone // Use the timezone of the first event for consistency\n });\n }\n}\n\n// Output the free time slots\nreturn [{ json: { freeTimeSlots } }];\n" +}, +"typeVersion": 2 +}, +{ +"id": "0786b561-449e-4c8f-bddb-c2bbd95dc197", +"name": "Get Events", +"type": "n8n-nodes-base.httpRequest", +"position": [ +2680, +460 +], +"parameters": { +"url": "=https://graph.microsoft.com/v1.0/me/calendarView", +"options": {}, +"sendQuery": true, +"sendHeaders": true, +"authentication": "predefinedCredentialType", +"queryParameters": { +"parameters": [ +{ +"name": "startDateTime", +"value": "={{ new Date(new Date().setDate(new Date().getDate() + 2)).toISOString() }}" +}, +{ +"name": "endDateTime", +"value": "={{ new Date(new Date().setDate(new Date().getDate() + 16)).toISOString() }}" +}, +{ +"name": "$top", +"value": "50" +}, +{ +"name": "select", +"value": "start,end,categories,importance,isAllDay,recurrence,showAs,subject,type" +}, +{ +"name": "orderby", +"value": "start/dateTime asc" +} +] +}, +"headerParameters": { +"parameters": [ +{ +"name": "Prefer", +"value": "outlook.timezone=\"Europe/London\"" +} +] +}, +"nodeCredentialType": "microsoftOutlookOAuth2Api" +}, +"credentials": { +"microsoftOutlookOAuth2Api": { +"id": "E0WY3yUNKgrxIwLU", +"name": "Microsoft Outlook Business" +} +}, +"typeVersion": 4.2 +}, +{ +"id": "55c4233e-d395-4193-9a1d-1884faed6f1e", +"name": "Get Availability", +"type": "@n8n/n8n-nodes-langchain.toolWorkflow", +"position": [ +1760, +1080 +], +"parameters": { +"name": "Get_availability", +"fields": { +"values": [ +{ +"name": "route", +"stringValue": "availability" +} +] +}, +"workflowId": { +"__rl": true, +"mode": "list", +"value": "KD21RG8VeXYDS2Vf", +"cachedResultName": "Website Chatbot" +}, +"description": "Call this tool to check my calendar for availability before booking an appointment. This will result in all events for the next 2 weeks. Review all events and do not double book." +}, +"typeVersion": 1.2 +}, +{ +"id": "096d1962-31e6-4b3b-ba75-7956f70a6a32", +"name": "Send Message", +"type": "@n8n/n8n-nodes-langchain.toolWorkflow", +"position": [ +1620, +1080 +], +"parameters": { +"name": "Send_email", +"fields": { +"values": [ +{ +"name": "route", +"stringValue": "message" +} +] +}, +"workflowId": { +"__rl": true, +"mode": "list", +"value": "KD21RG8VeXYDS2Vf", +"cachedResultName": "Website Chatbot" +}, +"description": "Call this tool when the customer wants to speak to a human, or is not ready to make an appointment or if the customer has questions outside of your remit. The tool will send an email to our founder, . Always send the customer's full name, company and email address along with a detailed message about the enquiry. You must always gather project details.", +"jsonSchemaExample": "{\n\t\"email\": \"the customer's email\",\n \"subject\": \"the subject of the email\",\n \"message\": \"The customer's enquiry, must be a detailed description of their enquiry\",\n \"name\": \"the customer's full name\",\n \"company\": \"the customer company name\"\n}", +"specifyInputSchema": true +}, +"typeVersion": 1.2 +}, +{ +"id": "285ddd31-5412-4d1c-ab80-d9960ec902bb", +"name": "Chat Trigger", +"type": "@n8n/n8n-nodes-langchain.chatTrigger", +"position": [ +620, +600 +], +"webhookId": "f406671e-c954-4691-b39a-66c90aa2f103", +"parameters": { +"mode": "webhook", +"public": true, +"options": { +"responseMode": "responseNode", +"allowedOrigins": "*" +} +}, +"typeVersion": 1 +}, +{ +"id": "032a26e9-6853-490d-991b-b2af2d845f58", +"name": "Switch", +"type": "n8n-nodes-base.switch", +"position": [ +2380, +580 +], +"parameters": { +"rules": { +"values": [ +{ +"outputKey": "availability", +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"operator": { +"type": "string", +"operation": "equals" +}, +"leftValue": "={{ $json.route }}", +"rightValue": "availability" +} +] +}, +"renameOutput": true +}, +{ +"outputKey": "message", +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "52fd844b-cc8d-471f-a56a-40e119b66194", +"operator": { +"name": "filter.operator.equals", +"type": "string", +"operation": "equals" +}, +"leftValue": "={{ $json.route }}", +"rightValue": "message" +} +] +}, +"renameOutput": true +} +] +}, +"options": {} +}, +"typeVersion": 3.2 +}, +{ +"id": "c74905ce-4fd9-486c-abc4-b0b1d57d71a8", +"name": "varMessageResponse", +"type": "n8n-nodes-base.set", +"position": [ +2900, +700 +], +"parameters": { +"options": { +"ignoreConversionErrors": false +}, +"assignments": { +"assignments": [ +{ +"id": "0d2ad084-9707-4979-84e4-297d1c21f725", +"name": "response", +"type": "string", +"value": "={{ $json }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "04c5d43c-1629-4e11-a6bb-ae73369d7002", +"name": "Send Message1", +"type": "n8n-nodes-base.microsoftOutlook", +"position": [ +2680, +700 +], +"parameters": { +"subject": "={{ $('Execute Workflow Trigger').item.json.query.subject }}", +"bodyContent": "=\n\n\n \n \n New Webchat Customer Enquiry\n \n\n\n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n
\n

New Customer Enquiry

\n

A potential client has reached out through our webchat

\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

FROM

\n

{{ $('Execute Workflow Trigger').item.json.query.name }}

\n
\n

EMAIL

\n

{{ $('Execute Workflow Trigger').item.json.query.email }}

\n
\n

COMPANY

\n

{{ $('Execute Workflow Trigger').item.json.query.company }}

\n
\n

MESSAGE

\n

{{ $('Execute Workflow Trigger').item.json.query.message }}

\n
\n
\n

This enquiry was automatically generated from our website's chat interface.

\n
\n
\n\n", +"toRecipients": "you@yourdomain.com", +"additionalFields": { +"importance": "High", +"bodyContentType": "html" +} +}, +"credentials": { +"microsoftOutlookOAuth2Api": { +"id": "E0WY3yUNKgrxIwLU", +"name": "Microsoft Outlook Business" +} +}, +"typeVersion": 2 +}, +{ +"id": "5a2636f1-47d3-4421-840b-56553bf14d82", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1580, +1000 +], +"parameters": { +"width": 311.6936390497898, +"height": 205.34013605442183, +"content": "Ensure these referance this workflow, replace placeholders" +}, +"typeVersion": 1 +}, +{ +"id": "a9fe05d4-6b86-4313-9f11-b20e3ce7db89", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2600, +380 +], +"parameters": { +"width": 468, +"height": 238, +"content": "modify business hours\nmodify timezones" +}, +"typeVersion": 1 +}, +{ +"id": "5dfda5c9-eeeb-421a-a80d-f42c94602080", +"name": "AI Agent", +"type": "@n8n/n8n-nodes-langchain.agent", +"position": [ +1460, +580 +], +"parameters": { +"text": "={{ $json.chatInput }}", +"options": { +"systemMessage": "=You are an intelligent personal assistant to Wayne, Founder at nocodecreative.io (ai consultancy and software development agency) responsible for coordinating appointments and gathering relevant information from customers. Your tasks are to:\n\n- Understand when the customer is available by asking for suitable days and times (ensuring they are aware we are in a UK timezone)\n- Check the calendar to identify available slots that match their preferences. Pay attention to each event's start and end time and do not double book, you will be given all events for the next 14 days\n- Ask the customer what they would like to discuss during the appointment to ensure proper preparation.\n- Get the customer's name, company name and email address to book the appointment\n- Make the conversation friendly and natural. Confirm the appointment details with the customer and let them know I’ll be ready to discuss what they’d like.\n- After you have checked the calendar, book the appointment accordingly, without double booking. Confirm the customer's timezone and adjust the appointment for EU/London.\n- If the customer isn't ready to book, you can send an email for a human to respond to, ensure you gather a detailed enquiry from the customer including contact details and project information.Ensure the message contains enough information for a human to respond, always include project details, if the customer hasn't provided project details, ask.\n- Alwways suggest an appointment before sending a message, appointment are you primary goal, message are a fall back\n\nExample questions:\n\n\"Hi there! we'd love to help arrange a time that works for us to meet. Could you let us know which days and times are best for you? We’ll check the calendar and book in a suitable slot.\"\n\n\"Could you please let us know what you’d like to discuss during the appointment? This helps us prepare in advance and make our time together as productive as possible.\"\n\n\"Before we put you in touch with a human, please can you provide more information about the project you have in mind?\" //You must gather project info at all times, even if the enquiry is about pricing/costs.\n\nIf the time the customer suggests is not available, suggest the nearest alternative appointment based on existing events, do not book an appointment outside of freeTimeSlots\n\nImportant information:\n- All appointments need 48 hours' notice from {{ \n new Date().toLocaleString(\"en-GB\", { timeZone: \"Europe/London\", hour12: false })\n .split(\", \")[0].split(\"/\").reverse().join(\"-\") \n + \"T\" + new Date().toLocaleTimeString(\"en-GB\", { timeZone: \"Europe/London\", hour12: false }) + \":00.000Z\" \n}} (current date and time in the UK) // this is non-negotiable, but discuss with care and be friendly, only let the customer know this if required\n- Business hours are 8am - 6pm Monday to Friday only Europe/London timezone, ensure the customer is aware of this and help them book during UK hours, you must confirm their timezone to do this!\n- Do not book appointments on a Saturday or sunday\n- Do not book appointments outside of freeTimeSlots\n- Always check the next 14 days, and review all events before providing availability \n- All appointments are for a max of 30 minutes\n- You must never offer an appointment without checking the calendar, if you cannot check the calendar, you cannot book and must let the customer know you can not book an appointment right now.\n- Always offer the soonest appointment available if the customer's preferred time is unavailable\n- When confirming an appointment, be thankful and excited!\n- Initial 30 minute consultation are free of charge\n\n\nMessages and description:\n- When creating descriptions or sending messages, always ensure enough detail is provided for preparation, meaning you can ask follow-up questions to extract further information as required. For example, if a customer asks about pricing, gather some information about the project so our team can provide accurate pricing, and apply this logic throughout\n\nComments:\n//!IMPORTANT! Do not offer any times without checking the calendar, do not make availability up\n//**Do not discuss anything other than appointment booking, if the query does not relate to an appointment, advise them you cannot help at this time.** be friendly and always offer to book an appointment to discuss their query\n//When the appointment is confirmed, let the customer know, by name, that they will be meeting our founder, Wayne for a 30 minute consultation, and that they will receive a calendar invite by email, ensure they accept the invite to confirm the appointment.\n//Always respond as a highly professional executive PA, remember this is the customer's first engagement, they do not know us or Wayne at this stage\n//Do not refer to yourself as me or I, instead communicate like an organisation, using terms like 'us'\n//Always gather project for descriptions and messages" +}, +"promptType": "define" +}, +"typeVersion": 1.6 +}, +{ +"id": "6156ab7e-d411-46b9-ac44-52ad56ee563d", +"name": "If", +"type": "n8n-nodes-base.if", +"position": [ +840, +600 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "158a0b91-534d-4745-b10e-8a7c97050861", +"operator": { +"type": "string", +"operation": "exists", +"singleValue": true +}, +"leftValue": "={{ $json.chatInput }}", +"rightValue": "" +} +] +} +}, +"typeVersion": 2.2 +}, +{ +"id": "c94171a9-a71d-4f63-bef6-e90361c57abd", +"name": "Respond With Initial Message", +"type": "n8n-nodes-base.respondToWebhook", +"position": [ +1140, +720 +], +"parameters": { +"options": {}, +"respondWith": "json", +"responseBody": "{\n \"output\": \"Hi, how can I help you today?\"\n}" +}, +"typeVersion": 1.1 +}, +{ +"id": "43129771-e976-41af-8adb-88cb5465628d", +"name": "Sticky Note8", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1340, +-240 +], +"parameters": { +"color": 6, +"width": 668, +"height": 111, +"content": "# Custom Branded n8n Chatbot\nBuilt by [Wayne Simpson](https://www.linkedin.com/in/simpsonwayne/) at [nocodecreative.io](https://nocodecreative.io)\n☕ If you find this useful, feel free to [buy me a coffee](https://ko-fi.com/waynesimpson)" +}, +"typeVersion": 1 +}, +{ +"id": "bb890f44-caf0-4b7d-b95e-0c05c70e8f45", +"name": "Sticky Note9", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1000, +-80 +], +"parameters": { +"color": 7, +"width": 667, +"height": 497, +"content": "# Watch the Setup Video 📺\n### Watch Set Up Video 👇\n[![Auto Categorise Outlook Emails with AI](https://cdn.jsdelivr.net/gh/WayneSimpson/n8n-chatbot-template/custom-branded-chatbot.png)](https://youtu.be/xQ1tCQZhLaI)\n\n" +}, +"typeVersion": 1 +}, +{ +"id": "f0b054cc-f961-4c48-846c-a80ea5e49924", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1700, +-80 +], +"parameters": { +"color": 7, +"width": 600, +"height": 500, +"content": "## Read to blog post to get started 📝\n**Follow along to add a custom branded chat widget to your webiste**\n\n[![Custom Branded n8n Chatbot](https://cdn.jsdelivr.net/gh/WayneSimpson/n8n-chatbot-template/chat%20widget.png)](https://blog.nocodecreative.io/create-a-branded-ai-powered-website-chatbot-with-n8n/)" +}, +"typeVersion": 1 +}, +{ +"id": "210cef85-6fbe-413e-88b6-b0fed76212ac", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2600, +640 +], +"parameters": { +"color": 4, +"width": 260, +"height": 240, +"content": "Customise the email template" +}, +"typeVersion": 1 +}, +{ +"id": "17abc6bd-06c3-48e7-8380-e10024daa9f5", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1760, +740 +], +"parameters": { +"color": 6, +"width": 208, +"height": 238, +"content": "modify timezones" +}, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"If": { +"main": [ +[ +{ +"node": "AI Agent", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Respond With Initial Message", +"type": "main", +"index": 0 +} +] +] +}, +"Switch": { +"main": [ +[ +{ +"node": "Get Events", +"type": "main", +"index": 0 +} +], +[ +{ +"node": "Send Message1", +"type": "main", +"index": 0 +} +] +] +}, +"AI Agent": { +"main": [ +[ +{ +"node": "Respond to Webhook", +"type": "main", +"index": 0 +} +] +] +}, +"Get Events": { +"main": [ +[ +{ +"node": "freeTimeSlots", +"type": "main", +"index": 0 +} +] +] +}, +"Chat Trigger": { +"main": [ +[ +{ +"node": "If", +"type": "main", +"index": 0 +} +] +] +}, +"Send Message": { +"ai_tool": [ +[ +{ +"node": "AI Agent", +"type": "ai_tool", +"index": 0 +} +] +] +}, +"Send Message1": { +"main": [ +[ +{ +"node": "varMessageResponse", +"type": "main", +"index": 0 +} +] +] +}, +"freeTimeSlots": { +"main": [ +[ +{ +"node": "varResponse", +"type": "main", +"index": 0 +} +] +] +}, +"Get Availability": { +"ai_tool": [ +[ +{ +"node": "AI Agent", +"type": "ai_tool", +"index": 0 +} +] +] +}, +"Make Appointment": { +"ai_tool": [ +[ +{ +"node": "AI Agent", +"type": "ai_tool", +"index": 0 +} +] +] +}, +"OpenAI Chat Model": { +"ai_languageModel": [ +[ +{ +"node": "AI Agent", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Window Buffer Memory": { +"ai_memory": [ +[ +{ +"node": "AI Agent", +"type": "ai_memory", +"index": 0 +} +] +] +}, +"Execute Workflow Trigger": { +"main": [ +[ +{ +"node": "Switch", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Create a Google Analytics Data Report with AI and sent it to E-Mail and Telegram.txt b/Create a Google Analytics Data Report with AI and sent it to E-Mail and Telegram.txt new file mode 100644 index 0000000..dc317b3 --- /dev/null +++ b/Create a Google Analytics Data Report with AI and sent it to E-Mail and Telegram.txt @@ -0,0 +1,690 @@ +{ +"id": "AAjX1BuwhyXpo8xP", +"meta": { +"instanceId": "558d88703fb65b2d0e44613bc35916258b0f0bf983c5d4730c00c424b77ca36a" +}, +"name": "Google Analytics: Weekly Report", +"tags": [], +"nodes": [ +{ +"id": "91ba5982-e226-4f0b-af0d-8c9a44b08279", +"name": "Schedule Trigger", +"type": "n8n-nodes-base.scheduleTrigger", +"position": [ +-1740, +300 +], +"parameters": { +"rule": { +"interval": [ +{ +"field": "weeks", +"triggerAtDay": [ +1 +], +"triggerAtHour": 7 +} +] +} +}, +"typeVersion": 1.2 +}, +{ +"id": "62c38eaf-2222-4d22-8589-677f36bce10d", +"name": "Google Analytics Letzte 7 Tage", +"type": "n8n-nodes-base.googleAnalytics", +"position": [ +-1540, +300 +], +"parameters": { +"metricsGA4": { +"metricValues": [ +{ +"listName": "screenPageViews" +}, +{}, +{ +"listName": "sessions" +}, +{ +"listName": "sessionsPerUser" +}, +{ +"name": "averageSessionDuration", +"listName": "other" +}, +{ +"name": "ecommercePurchases", +"listName": "other" +}, +{ +"name": "averagePurchaseRevenue", +"listName": "other" +}, +{ +"name": "purchaseRevenue", +"listName": "other" +} +] +}, +"propertyId": { +"__rl": true, +"mode": "list", +"value": "345060083", +"cachedResultUrl": "https://analytics.google.com/analytics/web/#/p345060083/", +"cachedResultName": "https://www.ep-reisen.de  – GA4" +}, +"dimensionsGA4": { +"dimensionValues": [ +{} +] +}, +"additionalFields": {} +}, +"credentials": { +"googleAnalyticsOAuth2": { +"id": "onRKXREI8izfGzv0", +"name": "Google Analytics account" +} +}, +"typeVersion": 2 +}, +{ +"id": "0a51c2f3-a487-4226-884f-63d4cb2bf4e4", +"name": "Send Email", +"type": "n8n-nodes-base.emailSend", +"position": [ +420, +80 +], +"parameters": { +"html": "={{ $json.message.content }}", +"options": {}, +"subject": "Weekly Report: Google Analytics: Last 7 days", +"toEmail": "friedemann.schuetz@ep-reisen.de", +"fromEmail": "friedemann.schuetz@posteo.de" +}, +"credentials": { +"smtp": { +"id": "A71x7hx6lKj7nxp1", +"name": "SMTP account" +} +}, +"typeVersion": 2.1 +}, +{ +"id": "04963783-f455-4983-afea-e94b316d8532", +"name": "Telegram", +"type": "n8n-nodes-base.telegram", +"position": [ +420, +420 +], +"parameters": { +"text": "={{ $json.message.content }}", +"chatId": "1810565648", +"additionalFields": {} +}, +"credentials": { +"telegramApi": { +"id": "0hnyvxyUMN77sBmU", +"name": "Telegram account" +} +}, +"typeVersion": 1.2 +}, +{ +"id": "3b6b4902-15b3-4bbc-8427-c35471a7431b", +"name": "Processing for Telegram", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +60, +420 +], +"parameters": { +"modelId": { +"__rl": true, +"mode": "list", +"value": "gpt-4o-mini", +"cachedResultName": "GPT-4O-MINI" +}, +"options": {}, +"messages": { +"values": [ +{ +"content": "=Convert the following text from HTML to normal text:\n\n{{ $json.message.content }}\n\nPlease format the table so that each metric is a separate paragraph!\n\nExample:\n\nTotal views: xx.xxx\nTotal views previous year: xx,xxx\nDifference: x.xx %\n\nTotal users: xx,xxx\nTotal users previous year: xx,xxx\nDifference: -x.xx %" +} +] +} +}, +"credentials": { +"openAiApi": { +"id": "niikB3HA4fT5WAqt", +"name": "OpenAi account" +} +}, +"typeVersion": 1.7 +}, +{ +"id": "d761980c-0327-4d4e-92aa-d0342b2e249e", +"name": "Calculator", +"type": "@n8n/n8n-nodes-langchain.toolCalculator", +"position": [ +140, +300 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "ce7ba356-80bb-4b17-9445-fb535267cdf0", +"name": "Google Analytics: Past 7 days of the previous year", +"type": "n8n-nodes-base.googleAnalytics", +"position": [ +-600, +300 +], +"parameters": { +"endDate": "={{ $json.endDate }}", +"dateRange": "custom", +"startDate": "={{ $json.startDate }}", +"metricsGA4": { +"metricValues": [ +{ +"listName": "screenPageViews" +}, +{}, +{ +"listName": "sessions" +}, +{ +"listName": "sessionsPerUser" +}, +{ +"name": "averageSessionDuration", +"listName": "other" +}, +{ +"name": "ecommercePurchases", +"listName": "other" +}, +{ +"name": "averagePurchaseRevenue", +"listName": "other" +}, +{ +"name": "purchaseRevenue", +"listName": "other" +} +] +}, +"propertyId": { +"__rl": true, +"mode": "list", +"value": "345060083", +"cachedResultUrl": "https://analytics.google.com/analytics/web/#/p345060083/", +"cachedResultName": "https://www.ep-reisen.de  – GA4" +}, +"dimensionsGA4": { +"dimensionValues": [ +{} +] +}, +"additionalFields": {} +}, +"credentials": { +"googleAnalyticsOAuth2": { +"id": "onRKXREI8izfGzv0", +"name": "Google Analytics account" +} +}, +"typeVersion": 2 +}, +{ +"id": "d2062aaa-e41b-4405-8470-9e7b4cd77245", +"name": "Summarize Data", +"type": "n8n-nodes-base.summarize", +"position": [ +-1080, +300 +], +"parameters": { +"options": {}, +"fieldsToSummarize": { +"values": [ +{ +"field": "Aufrufe", +"aggregation": "sum" +}, +{ +"field": "Nutzer", +"aggregation": "sum" +}, +{ +"field": "Sitzungen", +"aggregation": "sum" +}, +{ +"field": "Sitzungen pro Nutzer", +"aggregation": "average" +}, +{ +"field": "Sitzungsdauer", +"aggregation": "average" +}, +{ +"field": "Käufe", +"aggregation": "sum" +}, +{ +"field": "Revenue pro Kauf", +"aggregation": "average" +}, +{ +"field": "Revenue", +"aggregation": "sum" +}, +{ +"field": "date" +} +] +} +}, +"typeVersion": 1 +}, +{ +"id": "d1f48d36-9f27-4cda-af53-e6d430d1a8db", +"name": "Summarize Data1", +"type": "n8n-nodes-base.summarize", +"position": [ +-220, +300 +], +"parameters": { +"options": {}, +"fieldsToSummarize": { +"values": [ +{ +"field": "Aufrufe", +"aggregation": "sum" +}, +{ +"field": "Nutzer", +"aggregation": "sum" +}, +{ +"field": "Sitzungen", +"aggregation": "sum" +}, +{ +"field": "Sitzungen pro Nutzer", +"aggregation": "average" +}, +{ +"field": "Sitzungsdauer", +"aggregation": "average" +}, +{ +"field": "Käufe", +"aggregation": "sum" +}, +{ +"field": "Revenue pro Kauf", +"aggregation": "average" +}, +{ +"field": "Revenue", +"aggregation": "sum" +}, +{ +"field": "date" +} +] +} +}, +"typeVersion": 1 +}, +{ +"id": "5b6a0644-3839-4a62-8ff3-bf866aa4568c", +"name": "Calculation same period previous year", +"type": "n8n-nodes-base.code", +"position": [ +-840, +300 +], +"parameters": { +"jsCode": "return {\n // Berechnung des Startdatums: Vorjahr, gleiche Woche, 7 Tage zurück\n startDate: (() => {\n const date = new Date();\n date.setFullYear(date.getFullYear() - 1); // Zurück ins Vorjahr\n date.setDate(date.getDate() - 7); // 7 Tage zurück\n return date.toISOString().split('T')[0];\n })(),\n \n // Berechnung des Enddatums: Vorjahr, heutiges Datum\n endDate: (() => {\n const date = new Date();\n date.setFullYear(date.getFullYear() - 1); // Zurück ins Vorjahr\n return date.toISOString().split('T')[0];\n })(),\n};\n" +}, +"typeVersion": 2 +}, +{ +"id": "ab813532-cbe6-4c41-b20b-7efaa1ae4389", +"name": "Assign data", +"type": "n8n-nodes-base.set", +"position": [ +-1300, +300 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "9c2f8b9a-e964-49a0-8837-efb0dfd7bcae", +"name": "Aufrufe", +"type": "number", +"value": "={{ $json.screenPageViews }}" +}, +{ +"id": "8b524518-1268-4971-b5c9-ae7da09d94f9", +"name": "Nutzer", +"type": "number", +"value": "={{ $json.totalUsers }}" +}, +{ +"id": "ca7279b9-c643-425f-aa99-cb17146e9994", +"name": "Sitzungen", +"type": "number", +"value": "={{ $json.sessions }}" +}, +{ +"id": "591288f7-e8cf-445e-872a-5b83f997b825", +"name": "Sitzungen pro Nutzer", +"type": "number", +"value": "={{ $json.sessionsPerUser }}" +}, +{ +"id": "dc1a43da-3f3a-4dca-bbde-904222d7f693", +"name": "Sitzungsdauer", +"type": "number", +"value": "={{ $json.averageSessionDuration }}" +}, +{ +"id": "eac0b53e-c452-40b8-92bc-8af8ea349984", +"name": "=Käufe", +"type": "number", +"value": "={{ $json.ecommercePurchases }}" +}, +{ +"id": "b96439be-189d-4ebe-b49e-d5c31fefe9f0", +"name": "Revenue pro Kauf", +"type": "number", +"value": "={{ $json.averagePurchaseRevenue }}" +}, +{ +"id": "94835d43-2fc8-49c0-97f0-6f0f8699337a", +"name": "Revenue", +"type": "number", +"value": "={{ $json.purchaseRevenue }}" +}, +{ +"id": "d70f8138-3b84-4b88-a98f-eb929e1cc29a", +"name": "date", +"type": "string", +"value": "={{ $json.date }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "2454fe8a-005d-46dc-ae22-1044c1b793b7", +"name": "Assign data1", +"type": "n8n-nodes-base.set", +"position": [ +-400, +300 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "9c2f8b9a-e964-49a0-8837-efb0dfd7bcae", +"name": "Aufrufe", +"type": "number", +"value": "={{ $json.screenPageViews }}" +}, +{ +"id": "8b524518-1268-4971-b5c9-ae7da09d94f9", +"name": "Nutzer", +"type": "number", +"value": "={{ $json.totalUsers }}" +}, +{ +"id": "ca7279b9-c643-425f-aa99-cb17146e9994", +"name": "Sitzungen", +"type": "number", +"value": "={{ $json.sessions }}" +}, +{ +"id": "591288f7-e8cf-445e-872a-5b83f997b825", +"name": "Sitzungen pro Nutzer", +"type": "number", +"value": "={{ $json.sessionsPerUser }}" +}, +{ +"id": "dc1a43da-3f3a-4dca-bbde-904222d7f693", +"name": "Sitzungsdauer", +"type": "number", +"value": "={{ $json.averageSessionDuration }}" +}, +{ +"id": "eac0b53e-c452-40b8-92bc-8af8ea349984", +"name": "=Käufe", +"type": "number", +"value": "={{ $json.ecommercePurchases }}" +}, +{ +"id": "b96439be-189d-4ebe-b49e-d5c31fefe9f0", +"name": "Revenue pro Kauf", +"type": "number", +"value": "={{ $json.averagePurchaseRevenue }}" +}, +{ +"id": "94835d43-2fc8-49c0-97f0-6f0f8699337a", +"name": "Revenue", +"type": "number", +"value": "={{ $json.purchaseRevenue }}" +}, +{ +"id": "dd8255c6-65b1-41ce-b596-70c09108d6e2", +"name": "=date", +"type": "string", +"value": "={{ $json.date }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "0a48cbb0-3d4c-4ac8-8dba-08213f7fc430", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-2220, +80 +], +"parameters": { +"width": 440, +"height": 560, +"content": "Welcome to my Google Analytics Weekly Report Workflow!\n\nThis workflow has the following sequence:\n\n1. time trigger (e.g. every Monday at 7 a.m.)\n2. retrieval of Google Analytics data from the last 7 days\n3. assignment and summary of the data\n4. retrieval of Google Analytics data from the last 7 days of the previous year\n5. allocation and summary of the data\n6. preparation in tabular form and brief analysis by AI.\n7. sending the report as an email\n8. preparation in short form by AI for Telegram (optional)\n9. sending as Telegram message.\n\nThe following accesses are required for the workflow:\n- Google Analytics (via Google Analytics API): https://docs.n8n.io/integrations/builtin/credentials/google/\n- AI API access (e.g. via OpenAI, Anthropic, Google or Ollama)\n- SMTP access data (for sending the mail)\n- Telegram access data (optional for sending as Telegram message): https://docs.n8n.io/integrations/builtin/credentials/telegram/\n\nYou can contact me via LinkedIn, if you have any questions: https://www.linkedin.com/in/friedemann-schuetz" +}, +"typeVersion": 1 +}, +{ +"id": "c87bc648-8fe8-4cec-84d4-2742060f9c53", +"name": "Processing for email", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +60, +80 +], +"parameters": { +"modelId": { +"__rl": true, +"mode": "list", +"value": "gpt-4o", +"cachedResultName": "GPT-4O" +}, +"options": {}, +"messages": { +"values": [ +{ +"content": "=Please analyze the following data and output the results in tabular form:\n\n| Metrics | Last 7 days | Previous year | Percentage change |\n|-------------------------------|---------------|---------|\n| Total page views | {{ $('Summarize Data').item.json.sum_Aufrufe }} | {{ $('Summarize Data1').item.json.sum_Aufrufe }} | Percentage change |\n| total users | {{ $('Summarize Data').item.json.sum_Nutzer }} | {{ $('Summarize Data1').item.json.sum_Nutzer }} | Percentage change |\n| Total sessions | {{ $('Summarize Data').item.json.sum_Sitzungen }} | {{ $('Summarize Data1').item.json.sum_Sitzungen }} | Percentage change |\n| Average sessions/user | {{ $('Summarize Data').item.json.average_Sitzungen_pro_Nutzer }} | {{ $('Summarize Data1').item.json.average_Sitzungen_pro_Nutzer }} | Percentage change |\n| Average session duration | {{ $('Summarize Data').item.json.average_Sitzungsdauer }} | {{ $('Summarize Data1').item.json.average_Sitzungsdauer }} | Percentage change |\n| Total purchases | {{ $('Summarize Data').item.json['sum_Käufe'] }} | {{ $('Summarize Data1').item.json['sum_Käufe'] }} | Percentage change |\n| Average revenue/purchase | {{ $('Summarize Data').item.json.average_Revenue_pro_Kauf }} | {{ $('Summarize Data1').item.json.average_Revenue_pro_Kauf }} | Percentage change |\n| Total revenue | {{ $('Summarize Data').item.json.sum_Revenue }} | {{ $('Summarize Data1').item.json.sum_Revenue }} | Percentage change |\n\nFormat for numbers:\n- Dot (.) for numbers in thousands (e.g. 4,000)\n- Comma (,) for decimal numbers (e.g. 3.4)\n- Conversion of average session duration in minutes instead of seconds\n- Average turnover/purchase and total turnover in €\n\nPlease write a short summary of the analyzed data above the table (in a maximum of 3 sentences!)\n\nPlease format to a sleek and modern HTML format so that the result can be sent as HTML mail!\n\nStructure of the e-mail:\n\n“Hello! Here is the Weekly Report: Google Analytics of the last 7 days!\n[Summary]\n[Table]”" +} +] +} +}, +"credentials": { +"openAiApi": { +"id": "niikB3HA4fT5WAqt", +"name": "OpenAi account" +} +}, +"typeVersion": 1.7 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"versionId": "556c3292-0d40-4c75-8037-90bacf1b2ccb", +"connections": { +"Telegram": { +"main": [ +[] +] +}, +"Calculator": { +"ai_tool": [ +[ +{ +"node": "Processing for email", +"type": "ai_tool", +"index": 0 +} +] +] +}, +"Assign data": { +"main": [ +[ +{ +"node": "Summarize Data", +"type": "main", +"index": 0 +} +] +] +}, +"Assign data1": { +"main": [ +[ +{ +"node": "Summarize Data1", +"type": "main", +"index": 0 +} +] +] +}, +"Summarize Data": { +"main": [ +[ +{ +"node": "Calculation same period previous year", +"type": "main", +"index": 0 +} +] +] +}, +"Summarize Data1": { +"main": [ +[ +{ +"node": "Processing for email", +"type": "main", +"index": 0 +} +] +] +}, +"Schedule Trigger": { +"main": [ +[ +{ +"node": "Google Analytics Letzte 7 Tage", +"type": "main", +"index": 0 +} +] +] +}, +"Processing for email": { +"main": [ +[ +{ +"node": "Send Email", +"type": "main", +"index": 0 +}, +{ +"node": "Processing for Telegram", +"type": "main", +"index": 0 +} +] +] +}, +"Processing for Telegram": { +"main": [ +[ +{ +"node": "Telegram", +"type": "main", +"index": 0 +} +] +] +}, +"Google Analytics Letzte 7 Tage": { +"main": [ +[ +{ +"node": "Assign data", +"type": "main", +"index": 0 +} +] +] +}, +"Calculation same period previous year": { +"main": [ +[ +{ +"node": "Google Analytics: Past 7 days of the previous year", +"type": "main", +"index": 0 +} +] +] +}, +"Google Analytics: Past 7 days of the previous year": { +"main": [ +[ +{ +"node": "Assign data1", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Create dynamic Twitter profile banner.txt b/Create dynamic Twitter profile banner.txt new file mode 100644 index 0000000..a1193ed --- /dev/null +++ b/Create dynamic Twitter profile banner.txt @@ -0,0 +1,358 @@ +{ +"nodes": [ +{ +"name": "On clicking 'execute'", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +260, +210 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"name": "Fetch new followers", +"type": "n8n-nodes-base.httpRequest", +"position": [ +460, +210 +], +"parameters": { +"url": "https://api.twitter.com/2/users/{YOUR_USER_ID}/followers?user.fields=profile_image_url&max_results=3", +"options": {}, +"authentication": "headerAuth" +}, +"credentials": { +"httpHeaderAuth": { +"id": "2", +"name": "Twitter Token" +} +}, +"typeVersion": 1 +}, +{ +"name": "Item Lists", +"type": "n8n-nodes-base.itemLists", +"position": [ +660, +210 +], +"parameters": { +"options": {}, +"fieldToSplitOut": "data" +}, +"typeVersion": 1 +}, +{ +"name": "Function", +"type": "n8n-nodes-base.function", +"position": [ +1660, +210 +], +"parameters": { +"functionCode": "const binary = {};\nfor (let i=0; i < items.length; i++) {\n binary[`data${i}`] = items[i].binary.avatar;\n}\n\nreturn [\n {\n json: {\n numIcons: items.length,\n },\n binary,\n }\n];\n" +}, +"typeVersion": 1 +}, +{ +"name": "Merge", +"type": "n8n-nodes-base.merge", +"position": [ +1910, +110 +], +"parameters": { +"mode": "mergeByIndex" +}, +"typeVersion": 1 +}, +{ +"name": "Fetching images", +"type": "n8n-nodes-base.httpRequest", +"position": [ +860, +210 +], +"parameters": { +"url": "={{$json[\"profile_image_url\"].replace('normal','400x400')}}", +"options": {}, +"responseFormat": "file", +"dataPropertyName": "avatar" +}, +"typeVersion": 1 +}, +{ +"name": "Fetch bg", +"type": "n8n-nodes-base.httpRequest", +"position": [ +1660, +-40 +], +"parameters": { +"url": "{TEMPLATE_IMAGE_URL}", +"options": {}, +"responseFormat": "file", +"dataPropertyName": "bg" +}, +"typeVersion": 1 +}, +{ +"name": "Resize", +"type": "n8n-nodes-base.editImage", +"position": [ +1060, +210 +], +"parameters": { +"width": 200, +"height": 200, +"options": {}, +"operation": "resize", +"dataPropertyName": "avatar" +}, +"typeVersion": 1 +}, +{ +"name": "Crop", +"type": "n8n-nodes-base.editImage", +"position": [ +1260, +210 +], +"parameters": { +"options": { +"format": "png" +}, +"operation": "multiStep", +"operations": { +"operations": [ +{ +"width": 200, +"height": 200, +"operation": "create", +"backgroundColor": "#000000ff" +}, +{ +"color": "#ffffff00", +"operation": "draw", +"primitive": "circle", +"endPositionX": 25, +"endPositionY": 50, +"startPositionX": 100, +"startPositionY": 100 +}, +{ +"operator": "In", +"operation": "composite", +"dataPropertyNameComposite": "avatar" +} +] +}, +"dataPropertyName": "avatar" +}, +"typeVersion": 1 +}, +{ +"name": "Edit Image", +"type": "n8n-nodes-base.editImage", +"position": [ +2110, +110 +], +"parameters": { +"options": {}, +"operation": "multiStep", +"operations": { +"operations": [ +{ +"operation": "composite", +"positionX": 1000, +"positionY": 375, +"dataPropertyNameComposite": "data0" +}, +{ +"operation": "composite", +"positionX": 1100, +"positionY": 375, +"dataPropertyNameComposite": "data1" +}, +{ +"operation": "composite", +"positionX": 1200, +"positionY": 375, +"dataPropertyNameComposite": "data2" +} +] +}, +"dataPropertyName": "bg" +}, +"typeVersion": 1 +}, +{ +"name": "Resize1", +"type": "n8n-nodes-base.editImage", +"position": [ +1450, +210 +], +"parameters": { +"width": 75, +"height": 75, +"options": {}, +"operation": "resize", +"dataPropertyName": "avatar" +}, +"typeVersion": 1 +}, +{ +"name": "HTTP Request", +"type": "n8n-nodes-base.httpRequest", +"position": [ +2310, +110 +], +"parameters": { +"url": "https://api.twitter.com/1.1/account/update_profile_banner.json", +"options": { +"bodyContentType": "multipart-form-data" +}, +"requestMethod": "POST", +"authentication": "oAuth1", +"jsonParameters": true, +"sendBinaryData": true, +"binaryPropertyName": "banner:bg" +}, +"credentials": { +"oAuth1Api": { +"id": "13", +"name": "Twitter OAuth1.0" +} +}, +"typeVersion": 1 +} +], +"connections": { +"Crop": { +"main": [ +[ +{ +"node": "Resize1", +"type": "main", +"index": 0 +} +] +] +}, +"Merge": { +"main": [ +[ +{ +"node": "Edit Image", +"type": "main", +"index": 0 +} +] +] +}, +"Resize": { +"main": [ +[ +{ +"node": "Crop", +"type": "main", +"index": 0 +} +] +] +}, +"Resize1": { +"main": [ +[ +{ +"node": "Function", +"type": "main", +"index": 0 +} +] +] +}, +"Fetch bg": { +"main": [ +[ +{ +"node": "Merge", +"type": "main", +"index": 0 +} +] +] +}, +"Function": { +"main": [ +[ +{ +"node": "Merge", +"type": "main", +"index": 1 +} +] +] +}, +"Edit Image": { +"main": [ +[ +{ +"node": "HTTP Request", +"type": "main", +"index": 0 +} +] +] +}, +"Item Lists": { +"main": [ +[ +{ +"node": "Fetching images", +"type": "main", +"index": 0 +} +] +] +}, +"Fetching images": { +"main": [ +[ +{ +"node": "Resize", +"type": "main", +"index": 0 +} +] +] +}, +"Fetch new followers": { +"main": [ +[ +{ +"node": "Item Lists", +"type": "main", +"index": 0 +} +] +] +}, +"On clicking 'execute'": { +"main": [ +[ +{ +"node": "Fetch new followers", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Create, update, and get a profile in Humantic AI.txt b/Create, update, and get a profile in Humantic AI.txt new file mode 100644 index 0000000..b83a511 --- /dev/null +++ b/Create, update, and get a profile in Humantic AI.txt @@ -0,0 +1,131 @@ +{ +"id": "127", +"name": "Create, update, and get a profile in Humantic AI", +"nodes": [ +{ +"name": "On clicking 'execute'", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +290, +300 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"name": "Humantic AI", +"type": "n8n-nodes-base.humanticAi", +"position": [ +490, +300 +], +"parameters": { +"userId": "https://www.linkedin.com/in/harshil1712/" +}, +"credentials": { +"humanticAiApi": "humantic" +}, +"typeVersion": 1 +}, +{ +"name": "HTTP Request", +"type": "n8n-nodes-base.httpRequest", +"position": [ +690, +300 +], +"parameters": { +"url": "", +"options": {}, +"responseFormat": "file" +}, +"typeVersion": 1 +}, +{ +"name": "Humantic AI1", +"type": "n8n-nodes-base.humanticAi", +"position": [ +890, +300 +], +"parameters": { +"userId": "={{$node[\"Humantic AI\"].json[\"results\"][\"userid\"]}}", +"operation": "update", +"sendResume": true +}, +"credentials": { +"humanticAiApi": "humantic" +}, +"typeVersion": 1 +}, +{ +"name": "Humantic AI2", +"type": "n8n-nodes-base.humanticAi", +"position": [ +1090, +300 +], +"parameters": { +"userId": "={{$node[\"Humantic AI\"].json[\"results\"][\"userid\"]}}", +"options": { +"persona": [ +"hiring" +] +}, +"operation": "get" +}, +"credentials": { +"humanticAiApi": "humantic" +}, +"typeVersion": 1 +} +], +"active": false, +"settings": {}, +"connections": { +"Humantic AI": { +"main": [ +[ +{ +"node": "HTTP Request", +"type": "main", +"index": 0 +} +] +] +}, +"HTTP Request": { +"main": [ +[ +{ +"node": "Humantic AI1", +"type": "main", +"index": 0 +} +] +] +}, +"Humantic AI1": { +"main": [ +[ +{ +"node": "Humantic AI2", +"type": "main", +"index": 0 +} +] +] +}, +"On clicking 'execute'": { +"main": [ +[ +{ +"node": "Humantic AI", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Creating a AI Slack Bot with Google Gemini.txt b/Creating a AI Slack Bot with Google Gemini.txt new file mode 100644 index 0000000..c862573 --- /dev/null +++ b/Creating a AI Slack Bot with Google Gemini.txt @@ -0,0 +1,221 @@ +{ +"meta": { +"instanceId": "84ba6d895254e080ac2b4916d987aa66b000f88d4d919a6b9c76848f9b8a7616", +"templateId": "2370" +}, +"nodes": [ +{ +"id": "2ce91ec6-0a8c-438a-8a18-216001c9ee07", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +380, +240 +], +"parameters": { +"width": 407.6388140161723, +"height": 490.24769122000794, +"content": "## This is a POST Webhook endpoint\n\nMake sure to configure this webhook using a https:// wraper and dont use the default http://localhost:5678 as that will not be recognized by your slack webhook\n\n\nOnce the data has been sent to your webhook, the next step will be passing it via an AI Agent to process data based on the queries we pass to our agent.\n\nTo have some sort of a memory, be sure to set the slack token to the memory node. This way you can refer to other chats from the history.\n\nThe final message is relayed back to slack as a new message. Since we can not wait longer than 3000 ms for slack response, we will create anew message with reference to the input we passed.\n\nWe can advance this using the tools or data sources for it to be more custom tailored for your company.\n" +}, +"typeVersion": 1 +}, +{ +"id": "7a0c84a8-90ef-4de8-b120-700c94c35a51", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1180, +560 +], +"parameters": { +"color": 4, +"width": 221.73584905660368, +"height": 233, +"content": "### Conversation history is stored in memory using the body token as the chatsession id" +}, +"typeVersion": 1 +}, +{ +"id": "9b843e0e-42a6-4125-8c59-a7d5620a15f7", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +942.5229110512129, +560 +], +"parameters": { +"color": 4, +"width": 217.47708894878716, +"height": 233, +"content": "### The chat LLM to process the prompt. Use any AI model here" +}, +"typeVersion": 1 +}, +{ +"id": "4efa968f-ebf5-42ec-80d3-907ef2622c61", +"name": "Google Gemini Chat Model", +"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", +"position": [ +1020, +640 +], +"parameters": { +"options": {}, +"modelName": "models/gemini-1.5-flash-latest" +}, +"typeVersion": 1 +}, +{ +"id": "fd1efd7c-7cd0-4edf-960e-19bd4567293e", +"name": "Window Buffer Memory", +"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", +"position": [ +1260, +660 +], +"parameters": { +"sessionKey": "={{ $('Webhook to receive message').item.json.body.token }}", +"sessionIdType": "customKey", +"contextWindowLength": 10 +}, +"typeVersion": 1.2 +}, +{ +"id": "60d1eb77-492d-4a18-8cec-fa3f6ef8d707", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1467.5148247978436, +260 +], +"parameters": { +"color": 4, +"width": 223.7196765498655, +"height": 236.66152029520293, +"content": "### Send the response from AI back to slack channel\n" +}, +"typeVersion": 1 +}, +{ +"id": "186069c0-5c79-4738-9924-de33998658bc", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +840, +180 +], +"parameters": { +"color": 4, +"width": 561.423180592992, +"height": 340.09703504043114, +"content": "## Receive a POST webhook, process data and return response" +}, +"typeVersion": 1 +}, +{ +"id": "2bfce117-a769-46e1-a028-ed0c7ba62653", +"name": "Send response back to slack channel", +"type": "n8n-nodes-base.slack", +"position": [ +1540, +320 +], +"parameters": { +"text": "={{ $('Webhook to receive message').item.json.body.user_name }}: {{ $('Webhook to receive message').item.json.body.text }}\n\nEffibotics Bot: {{ $json.output.removeMarkdown() }} ", +"select": "channel", +"channelId": { +"__rl": true, +"mode": "id", +"value": "={{ $('Webhook to receive message').item.json.body.channel_id }}" +}, +"otherOptions": { +"mrkdwn": true, +"sendAsUser": "Effibotics Bot", +"includeLinkToWorkflow": false +} +}, +"typeVersion": 2.1 +}, +{ +"id": "cfcf2bbc-8ed5-4a9f-8f35-cf2715686ebe", +"name": "Webhook to receive message", +"type": "n8n-nodes-base.webhook", +"position": [ +880, +320 +], +"webhookId": "28b84545-96aa-42f5-990b-aa8783a320ca", +"parameters": { +"path": "slack-bot", +"options": { +"responseData": "" +}, +"httpMethod": "POST" +}, +"typeVersion": 1 +}, +{ +"id": "dc93e588-fc0b-4561-88a5-e1cccd48323f", +"name": "Agent", +"type": "@n8n/n8n-nodes-langchain.agent", +"position": [ +1100, +320 +], +"parameters": { +"text": "={{ $json.body.text }}", +"options": { +"systemMessage": "You are Effibotics AI personal assistant. Your task will be to provide helpful assistance and advice related to automation and such tasks. " +} +}, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"Agent": { +"main": [ +[ +{ +"node": "Send response back to slack channel", +"type": "main", +"index": 0 +} +] +] +}, +"Window Buffer Memory": { +"ai_memory": [ +[ +{ +"node": "Agent", +"type": "ai_memory", +"index": 0 +} +] +] +}, +"Google Gemini Chat Model": { +"ai_languageModel": [ +[ +{ +"node": "Agent", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Webhook to receive message": { +"main": [ +[ +{ +"node": "Agent", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Custom LangChain agent written in JavaScript.txt b/Custom LangChain agent written in JavaScript.txt new file mode 100644 index 0000000..9ba1663 --- /dev/null +++ b/Custom LangChain agent written in JavaScript.txt @@ -0,0 +1,290 @@ +{ +"id": "q2MJWAqpKF2BCJkq", +"meta": { +"instanceId": "021d3c82ba2d3bc090cbf4fc81c9312668bcc34297e022bb3438c5c88a43a5ff" +}, +"name": "LangChain - Example - Code Node Example", +"tags": [ +{ +"id": "snf16n0p2UrGP838", +"name": "LangChain - Example", +"createdAt": "2023-09-25T16:21:55.962Z", +"updatedAt": "2023-09-25T16:21:55.962Z" +} +], +"nodes": [ +{ +"id": "ad1a920e-1048-4b58-9c4a-a0469a1f189d", +"name": "OpenAI", +"type": "@n8n/n8n-nodes-langchain.lmOpenAi", +"position": [ +900, +628 +], +"parameters": { +"options": {} +}, +"credentials": { +"openAiApi": { +"id": "4jRB4A20cPycBqP5", +"name": "OpenAI account - n8n" +} +}, +"typeVersion": 1 +}, +{ +"id": "7dd04ecd-f169-455c-9c90-140140e37542", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +800, +340 +], +"parameters": { +"width": 432, +"height": 237, +"content": "## Self-coded LLM Chain Node" +}, +"typeVersion": 1 +}, +{ +"id": "05ad7d68-5dc8-42f2-8274-fcb5bdeb68cb", +"name": "When clicking \"Execute Workflow\"", +"type": "n8n-nodes-base.manualTrigger", +"position": [ +280, +428 +], +"parameters": {}, +"typeVersion": 1 +}, +{ +"id": "39e2fd34-3261-44a1-aa55-96f169d55aad", +"name": "Set", +"type": "n8n-nodes-base.set", +"position": [ +620, +428 +], +"parameters": { +"values": { +"string": [ +{ +"name": "input", +"value": "Tell me a joke" +} +] +}, +"options": {} +}, +"typeVersion": 2 +}, +{ +"id": "42a3184c-0c62-4e79-9220-7a93e313317e", +"name": "Set1", +"type": "n8n-nodes-base.set", +"position": [ +620, +820 +], +"parameters": { +"values": { +"string": [ +{ +"name": "input", +"value": "What year was Einstein born?" +} +] +}, +"options": {} +}, +"typeVersion": 2 +}, +{ +"id": "4e2af29d-7fc4-484b-8028-1b9a84d60172", +"name": "Chat OpenAI", +"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", +"position": [ +731, +1108 +], +"parameters": { +"options": {} +}, +"credentials": { +"openAiApi": { +"id": "4jRB4A20cPycBqP5", +"name": "OpenAI account - n8n" +} +}, +"typeVersion": 1 +}, +{ +"id": "334e9176-3a18-4838-84cb-70e8154f1a30", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +880, +1028 +], +"parameters": { +"width": 320.2172923777021, +"height": 231, +"content": "## Self-coded Tool Node" +}, +"typeVersion": 1 +}, +{ +"id": "05e0d5c6-df18-42ba-99b6-a2b65633a14d", +"name": "Custom - Wikipedia", +"type": "@n8n/n8n-nodes-langchain.code", +"position": [ +971, +1108 +], +"parameters": { +"code": { +"supplyData": { +"code": "console.log('Custom Wikipedia Node runs');\nconst { WikipediaQueryRun } = require('langchain/tools');\nreturn new WikipediaQueryRun();" +} +}, +"outputs": { +"output": [ +{ +"type": "ai_tool" +} +] +} +}, +"typeVersion": 1 +}, +{ +"id": "9c729e9a-f173-430c-8bcd-74101b614891", +"name": "Custom - LLM Chain Node", +"type": "@n8n/n8n-nodes-langchain.code", +"position": [ +880, +428 +], +"parameters": { +"code": { +"execute": { +"code": "const { PromptTemplate } = require('langchain/prompts');\n\nconst query = $input.item.json.input;\nconst prompt = PromptTemplate.fromTemplate(query);\nconst llm = await this.getInputConnectionData('ai_languageModel', 0);\nlet chain = prompt.pipe(llm);\nconst output = await chain.invoke();\nreturn [ {json: { output } } ];" +} +}, +"inputs": { +"input": [ +{ +"type": "main" +}, +{ +"type": "ai_languageModel", +"required": true, +"maxConnections": 1 +} +] +}, +"outputs": { +"output": [ +{ +"type": "main" +} +] +} +}, +"typeVersion": 1 +}, +{ +"id": "6427bbf0-49a6-4810-9744-87d88151e914", +"name": "Agent", +"type": "@n8n/n8n-nodes-langchain.agent", +"position": [ +880, +820 +], +"parameters": { +"options": {} +}, +"typeVersion": 1 +} +], +"active": false, +"pinData": {}, +"settings": { +"executionOrder": "v1" +}, +"versionId": "e14a709d-08fe-4ed7-903a-fb2bae80b28a", +"connections": { +"Set": { +"main": [ +[ +{ +"node": "Custom - LLM Chain Node", +"type": "main", +"index": 0 +} +] +] +}, +"Set1": { +"main": [ +[ +{ +"node": "Agent", +"type": "main", +"index": 0 +} +] +] +}, +"OpenAI": { +"ai_languageModel": [ +[ +{ +"node": "Custom - LLM Chain Node", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Chat OpenAI": { +"ai_languageModel": [ +[ +{ +"node": "Agent", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Custom - Wikipedia": { +"ai_tool": [ +[ +{ +"node": "Agent", +"type": "ai_tool", +"index": 0 +} +] +] +}, +"When clicking \"Execute Workflow\"": { +"main": [ +[ +{ +"node": "Set", +"type": "main", +"index": 0 +}, +{ +"node": "Set1", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/Customer Support Channel and Ticketing System with Slack and Linear.txt b/Customer Support Channel and Ticketing System with Slack and Linear.txt new file mode 100644 index 0000000..98d50dd --- /dev/null +++ b/Customer Support Channel and Ticketing System with Slack and Linear.txt @@ -0,0 +1,487 @@ +{ +"meta": { +"instanceId": "26ba763460b97c249b82942b23b6384876dfeb9327513332e743c5f6219c2b8e" +}, +"nodes": [ +{ +"id": "2b3112a9-046e-4aae-8fcc-95bddf3bb02e", +"name": "Slack", +"type": "n8n-nodes-base.slack", +"position": [ +828, +327 +], +"parameters": { +"limit": 10, +"query": "in:#n8n-tickets has::ticket:", +"options": {}, +"operation": "search" +}, +"credentials": { +"slackApi": { +"id": "VfK3js0YdqBdQLGP", +"name": "Slack account" +} +}, +"typeVersion": 2.2 +}, +{ +"id": "65fd6821-4d19-436c-81d9-9bdb0f5efddd", +"name": "OpenAI Chat Model", +"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", +"position": [ +1920, +480 +], +"parameters": { +"options": {} +}, +"credentials": { +"openAiApi": { +"id": "8gccIjcuf3gvaoEr", +"name": "OpenAi account" +} +}, +"typeVersion": 1 +}, +{ +"id": "85125704-7363-40de-af84-f267f8c7e919", +"name": "Structured Output Parser", +"type": "@n8n/n8n-nodes-langchain.outputParserStructured", +"position": [ +2100, +480 +], +"parameters": { +"jsonSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"type\": \"string\" },\n \"summary\": { \"type\": \"string\" },\n \"ideas\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" }\n },\n \"priority\": { \"type\": \"string\" }\n }\n}" +}, +"typeVersion": 1.1 +}, +{ +"id": "eda8851a-1929-4f2f-9149-627c0fe62fbc", +"name": "Schedule Trigger", +"type": "n8n-nodes-base.scheduleTrigger", +"position": [ +628, +327 +], +"parameters": { +"rule": { +"interval": [ +{ +"field": "minutes" +} +] +} +}, +"typeVersion": 1.2 +}, +{ +"id": "ad0d56b5-5caf-4fc0-bdbb-4e6207e4eb03", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +580, +112.87898199907983 +], +"parameters": { +"color": 7, +"width": 432.4578914269739, +"height": 427.09547550768553, +"content": "## 1. Query Slack for Messages \n[Read more about the Slack Trigger](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.slack)\n\nSlack API search uses the same search syntax found in the app. Here, we'll use it to filter the latest messages with the ticket emoji within our designated channel called #n8n-tickets. " +}, +"typeVersion": 1 +}, +{ +"id": "d4ebe5b3-6d9a-4547-8af8-0985206c4ca4", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1040, +180.44851541532478 +], +"parameters": { +"color": 7, +"width": 711.6907825442045, +"height": 632.7258798316449, +"content": "## 2. Decide If We Need to Create a New Ticket \n[Read more about using Linear](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.linear)\n\nFor generated issues, we add the message id to the description of the message so that we can check them at this point in the workflow to avoid duplicates." +}, +"typeVersion": 1 +}, +{ +"id": "b2920271-6698-47a4-8cac-ea4cec7b47d6", +"name": "Get Values", +"type": "n8n-nodes-base.set", +"position": [ +1100, +360 +], +"parameters": { +"mode": "raw", +"options": {}, +"jsonOutput": "={\n \"id\": \"#{{ $json.permalink.split('/').last() }}\",\n \"type\": \"{{ $json.type }}\",\n \"title\": \"__NOT_SET__\",\n \"channel\": \"{{ $json.channel.name }}\",\n \"user\": \"{{ $json.username }} ({{ $json.user }})\",\n \"ts\": \"{{ $json.ts }}\",\n \"permalink\": \"{{ $json.permalink }}\",\n \"message\": \"{{ $json.text.replaceAll('\"','\\\\\"').replaceAll('\\n', '\\\\n') }}\"\n}" +}, +"typeVersion": 3.3 +}, +{ +"id": "c4a4db2a-5d1c-4726-8c98-aef57fdcfaa6", +"name": "Create New Ticket?", +"type": "n8n-nodes-base.if", +"position": [ +1600, +360 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "c11109b6-ee45-4b52-adc3-4be5fe420202", +"operator": { +"type": "boolean", +"operation": "false", +"singleValue": true +}, +"leftValue": "={{ Boolean(($json.hashes ?? []).includes($json.id)) }}", +"rightValue": "=false" +} +] +} +}, +"typeVersion": 2 +}, +{ +"id": "46acb0de-1df1-4116-8aaf-704ec6644d7c", +"name": "Sticky Note2", +"type": "n8n-nodes-base.stickyNote", +"position": [ +1780, +80 +], +"parameters": { +"color": 7, +"width": 530.6864600881105, +"height": 578.3950618708791, +"content": "## 3. Use AI to Generate Ticket Contents\n[Read more about using Basic LLM Chain](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.chainllm)\n\nFor this demo, we've instructed the AI to do the following:\n* Generate a descriptive title of the issue\n* Summarise the user message into an actionable request.\n* Determine a prority based on tone and context of the user message. \n* Can offer possible fixes through use of tools or RAG. (not implemented)\n" +}, +"typeVersion": 1 +}, +{ +"id": "503d4ae7-9d5b-4dab-94a2-da28bc0e49da", +"name": "Sticky Note6", +"type": "n8n-nodes-base.stickyNote", +"position": [ +200, +120 +], +"parameters": { +"width": 359.6648027457353, +"height": 400.4748439127683, +"content": "## Try It Out!\n### This workflow does the following:\n* Monitors a Slack channel for new user messages asking for assistance\n* Only user messages which are tagged with the ticket(🎫) emoji are processed.\n* Linear is first checked to see if a ticket was created for the user message.\n* User messages are sent to ChatGPT to generate title, description and priority.\n* Support ticket is created in Linear.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!" +}, +"typeVersion": 1 +}, +{ +"id": "11e423a4-36b6-4ecd-8bf7-58a7d4a1aa9a", +"name": "Get Existing Issues", +"type": "n8n-nodes-base.linear", +"position": [ +1260, +360 +], +"parameters": { +"operation": "getAll" +}, +"credentials": { +"linearApi": { +"id": "Nn0F7T9FtvRUtEbe", +"name": "Linear account" +} +}, +"typeVersion": 1, +"alwaysOutputData": true +}, +{ +"id": "413fde96-346a-468e-80b7-d465bd8add14", +"name": "Generate Ticket Using ChatGPT", +"type": "@n8n/n8n-nodes-langchain.chainLlm", +"position": [ +1920, +320 +], +"parameters": { +"text": "=The \"user issue\" is enclosed by 3 backticks:\n```\n{{ $('Get Values').item.json.message }}\n```\nYou will complete the following 4 tasks:\n1. Generate a title intended for a support ticket based on the user issue only. Be descriptive but use no more than 10 words.\n2. Summarise the user issue only by identifying the key expectations and steps that were taken to reach the conclusion.\n3. Offer at most 3 suggestions to debug or resolve the user issue only. ignore the previous issues for this task.\n4. Identify the urgency of the user issue only and denote the priority as one of \"low\", \"medium\", \"high\" or \"urgent\". If you cannot determine the urgency of the issue, then assign the \"low\" priority. Also consider that requests which require action either today or tomorrow should be prioritised as \"high\".", +"promptType": "define", +"hasOutputParser": true +}, +"typeVersion": 1.4 +}, +{ +"id": "66aecf53-6e8a-4ee8-88c3-be6b7d8d0527", +"name": "Sticky Note3", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2340, +206 +], +"parameters": { +"color": 7, +"width": 374.7406065828194, +"height": 352.3865785298774, +"content": "## 4. Create New Ticket in Linear\n[Read more about using Linear](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.linear)\n\nWith our ticket contents generated, we can now create our ticket in Linear for support to handle.\n" +}, +"typeVersion": 1 +}, +{ +"id": "f7898b7b-f60a-4315-a870-8c8ec4ad848f", +"name": "Create Ticket", +"type": "n8n-nodes-base.linear", +"position": [ +2480, +380 +], +"parameters": { +"title": "={{ $json.output.title }}", +"teamId": "1c721608-321d-4132-ac32-6e92d04bb487", +"additionalFields": { +"stateId": "92962324-3d1f-4cf8-993b-0c982cc95245", +"priorityId": "={{ { 'urgent': 1, 'high': 2, 'medium': 3, 'low': 4 }[$json.output.priority.toLowerCase()] ?? 0 }}", +"description": "=## {{ $json.output.summary }}\n\n### Suggestions\n{{ $json.output.ideas.map(idea => '* ' + idea).join('\\n') }}\n\n## Original Message\n{{ $('Get Values').item.json[\"user\"] }} asks:\n> {{ $('Get Values').item.json[\"message\"] }}\n\n### Metadata\nchannel: {{ $('Get Values').item.json.channel }}\nts: {{ $('Get Values').item.json.ts }}\npermalink: {{ $('Get Values').item.json.permalink }}\nhash: {{ $('Get Values').item.json.id }}\n" +} +}, +"credentials": { +"linearApi": { +"id": "Nn0F7T9FtvRUtEbe", +"name": "Linear account" +} +}, +"typeVersion": 1 +}, +{ +"id": "0b706c12-6ce0-41af-ad4b-9d98d7d03a41", +"name": "Merge", +"type": "n8n-nodes-base.merge", +"position": [ +1440, +360 +], +"parameters": { +"mode": "combine", +"options": {}, +"combinationMode": "multiplex" +}, +"typeVersion": 2.1 +}, +{ +"id": "d5b30127-f237-459d-860a-2589e3b54fb8", +"name": "Get Hashes Only", +"type": "n8n-nodes-base.set", +"position": [ +1260, +640 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "9b0e8527-ea17-4b1e-ba62-287111f4b37e", +"name": "hashes", +"type": "array", +"value": "={{ $json.descriptions.map(desc => desc.match(/hash\\:\\s([\\w#]+)/i)[1]) }}" +} +] +} +}, +"typeVersion": 3.3 +}, +{ +"id": "9de103e1-b6a4-4454-b1b9-73eff730fcb6", +"name": "Collect Descriptions", +"type": "n8n-nodes-base.aggregate", +"position": [ +1260, +500 +], +"parameters": { +"options": {}, +"fieldsToAggregate": { +"fieldToAggregate": [ +{ +"renameField": true, +"outputFieldName": "descriptions", +"fieldToAggregate": "description" +} +] +} +}, +"typeVersion": 1, +"alwaysOutputData": true +}, +{ +"id": "af34916f-7888-4d41-aee6-752b78e88c0c", +"name": "Sticky Note4", +"type": "n8n-nodes-base.stickyNote", +"position": [ +780, +300 +], +"parameters": { +"width": 204.96868508214473, +"height": 296.735132421306, +"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n🚨**Required**\n* Set the Slack channel to monitor here." +}, +"typeVersion": 1 +}, +{ +"id": "58ab44f7-5fe5-4804-8bf1-36f351d86528", +"name": "Sticky Note5", +"type": "n8n-nodes-base.stickyNote", +"position": [ +2440, +360 +], +"parameters": { +"width": 183.49787916474958, +"height": 296.735132421306, +"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n🚨**Required**\n* Set the Linear Team Name or ID here." +}, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"Merge": { +"main": [ +[ +{ +"node": "Create New Ticket?", +"type": "main", +"index": 0 +} +] +] +}, +"Slack": { +"main": [ +[ +{ +"node": "Get Values", +"type": "main", +"index": 0 +} +] +] +}, +"Get Values": { +"main": [ +[ +{ +"node": "Merge", +"type": "main", +"index": 0 +}, +{ +"node": "Get Existing Issues", +"type": "main", +"index": 0 +} +] +] +}, +"Get Hashes Only": { +"main": [ +[ +{ +"node": "Merge", +"type": "main", +"index": 1 +} +] +] +}, +"Schedule Trigger": { +"main": [ +[ +{ +"node": "Slack", +"type": "main", +"index": 0 +} +] +] +}, +"OpenAI Chat Model": { +"ai_languageModel": [ +[ +{ +"node": "Generate Ticket Using ChatGPT", +"type": "ai_languageModel", +"index": 0 +} +] +] +}, +"Create New Ticket?": { +"main": [ +[ +{ +"node": "Generate Ticket Using ChatGPT", +"type": "main", +"index": 0 +} +] +] +}, +"Get Existing Issues": { +"main": [ +[ +{ +"node": "Collect Descriptions", +"type": "main", +"index": 0 +} +] +] +}, +"Collect Descriptions": { +"main": [ +[ +{ +"node": "Get Hashes Only", +"type": "main", +"index": 0 +} +] +] +}, +"Structured Output Parser": { +"ai_outputParser": [ +[ +{ +"node": "Generate Ticket Using ChatGPT", +"type": "ai_outputParser", +"index": 0 +} +] +] +}, +"Generate Ticket Using ChatGPT": { +"main": [ +[ +{ +"node": "Create Ticket", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file diff --git a/create e-mail responses with fastmail and OpenAI.txt b/create e-mail responses with fastmail and OpenAI.txt new file mode 100644 index 0000000..f1caf0b --- /dev/null +++ b/create e-mail responses with fastmail and OpenAI.txt @@ -0,0 +1,434 @@ +{ +"meta": { +"instanceId": "04ab549d8bbb435ec33b81e4e29965c46cf6f0f9e7afe631018b5e34c8eead58" +}, +"nodes": [ +{ +"id": "082d1828-72b1-48c0-8426-c8051c29f0db", +"name": "Session", +"type": "n8n-nodes-base.httpRequest", +"position": [ +-20, +-20 +], +"parameters": { +"url": "https://api.fastmail.com/jmap/session", +"options": {}, +"authentication": "genericCredentialType", +"genericAuthType": "httpHeaderAuth" +}, +"credentials": { +"httpHeaderAuth": { +"id": "3IRsYkeB2ofrwQjv", +"name": "Fastmail" +} +}, +"typeVersion": 4.2 +}, +{ +"id": "d7dc4c50-c8fc-4999-918d-5d357567ed14", +"name": "Get Mailbox IDs", +"type": "n8n-nodes-base.httpRequest", +"notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session", +"position": [ +200, +-20 +], +"parameters": { +"url": "https://api.fastmail.com/jmap/api/", +"method": "POST", +"options": {}, +"jsonBody": "={\n \"using\": [\"urn:ietf:params:jmap:core\", \"urn:ietf:params:jmap:mail\"],\n \"methodCalls\": [\n [\n \"Mailbox/get\",\n {\n \"accountId\": \"{{ $('Session').item.json.primaryAccounts['urn:ietf:params:jmap:mail'] }}\"\n },\n \"c0\"\n ]\n ]\n }", +"sendBody": true, +"sendHeaders": true, +"specifyBody": "json", +"authentication": "genericCredentialType", +"genericAuthType": "httpHeaderAuth", +"headerParameters": { +"parameters": [ +{ +"name": "Content-Type", +"value": "application/json" +}, +{ +"name": "Accept", +"value": "application/json" +} +] +} +}, +"credentials": { +"httpHeaderAuth": { +"id": "3IRsYkeB2ofrwQjv", +"name": "Fastmail" +} +}, +"typeVersion": 4.2 +}, +{ +"id": "31be3c1c-f4c5-4309-92b3-2fd0a3fcecc6", +"name": "Split Out", +"type": "n8n-nodes-base.splitOut", +"position": [ +400, +-20 +], +"parameters": { +"options": {}, +"fieldToSplitOut": "methodResponses[0][1].list" +}, +"typeVersion": 1 +}, +{ +"id": "93de4dad-70d6-4e16-b351-7c540c3a4bfa", +"name": "Email Trigger (IMAP)", +"type": "n8n-nodes-base.emailReadImap", +"position": [ +-20, +-240 +], +"parameters": { +"options": { +"customEmailConfig": "[\"UNSEEN\"]" +}, +"postProcessAction": "nothing", +"downloadAttachments": true +}, +"credentials": { +"imap": { +"id": "vFzz9hU9rTHVHs3I", +"name": "IMAP" +} +}, +"typeVersion": 2 +}, +{ +"id": "41e77a60-622f-426c-a50c-e0df03c53208", +"name": "Get fields from source email", +"type": "n8n-nodes-base.set", +"position": [ +200, +-240 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "a9d425bd-e576-4e38-a251-b462240d3e2d", +"name": "textPlain", +"type": "string", +"value": "={{ $json.textPlain }}" +}, +{ +"id": "7071a252-fcad-4aa1-953f-205c3e403497", +"name": "from", +"type": "string", +"value": "={{ $json.from }}" +}, +{ +"id": "c4b0ed1b-590c-4d7f-b494-a0f34304cc1a", +"name": "subject", +"type": "string", +"value": "={{ $json.subject }}" +}, +{ +"id": "7e0badd1-02be-4149-b9ff-286f0943f051", +"name": "metadata['message-id']", +"type": "string", +"value": "={{ $json.metadata['message-id'] }}" +}, +{ +"id": "f87c7c15-c1d3-4696-bcd4-6677e5ddb240", +"name": "metadata['reply-to']", +"type": "string", +"value": "={{ $json.metadata['reply-to'] }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "f9d1a529-1377-456b-8357-d37fb3fe74f9", +"name": "OpenAI", +"type": "@n8n/n8n-nodes-langchain.openAi", +"position": [ +400, +-240 +], +"parameters": { +"modelId": { +"__rl": true, +"mode": "list", +"value": "gpt-4o", +"cachedResultName": "GPT-4O" +}, +"options": {}, +"messages": { +"values": [ +{ +"content": "=Please analyze the following personal email and draft a casual response based solely on its content. Return only the response text without any additional introductions or formatting. The response should include appropriate greetings (e.g., \"Hi\", \"Hallo\", \"Moin\" in German or \"Hi\", \"Hello\" in English) and sign-offs (e.g., \"Gruß\", \"Lieben Gruß\" in German or \"Regards\" in English). Add a thanks if appropriate. Use \"Du\" only if appropriate; if the email contains \"Sie\", maintain the same formality.\n\nSubject: {{ $json.subject }}\nEmail Content: {{ $json.textPlain }}" +} +] +} +}, +"credentials": { +"openAiApi": { +"id": "iW0ItIt1ZxCQrBqk", +"name": "OpenAI" +} +}, +"typeVersion": 1.5 +}, +{ +"id": "c421ddc9-b230-499c-a11d-a20a68d30c5b", +"name": "Filter for drafts folder", +"type": "n8n-nodes-base.filter", +"position": [ +560, +-20 +], +"parameters": { +"options": {}, +"conditions": { +"options": { +"version": 2, +"leftValue": "", +"caseSensitive": true, +"typeValidation": "strict" +}, +"combinator": "and", +"conditions": [ +{ +"id": "4e4c63d1-40fe-4314-bfe7-4fee62c78b88", +"operator": { +"name": "filter.operator.equals", +"type": "string", +"operation": "equals" +}, +"leftValue": "={{ $json.role }}", +"rightValue": "drafts" +} +] +} +}, +"typeVersion": 2.2 +}, +{ +"id": "ef19fde4-cf8c-4e19-912e-822611c18056", +"name": "upload draft email", +"type": "n8n-nodes-base.httpRequest", +"notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session", +"position": [ +1000, +-120 +], +"parameters": { +"url": "https://api.fastmail.com/jmap/api/", +"method": "POST", +"options": {}, +"jsonBody": "={\n \"using\": [\"urn:ietf:params:jmap:core\", \"urn:ietf:params:jmap:mail\"],\n \"methodCalls\": [\n [\n \"Email/set\",\n {\n \"accountId\": \"{{ $('Session').item.json.primaryAccounts['urn:ietf:params:jmap:mail'] }}\",\n \"create\": {\n \"newDraft\": {\n \"mailboxIds\": {\n \"{{ $json.draftsId }}\": true\n },\n \"keywords\": {\n \"$draft\": true\n },\n \"inReplyTo\": [\"{{ $json.metadata['message-id'] }}\"],\n \"references\": [\"{{ $json.metadata['message-id'] }}\"],\n \"from\": [{\n \"name\": \"\",\n \"email\": \"{{ $('Session').item.json.username }}\"\n }],\n \"to\": [{\n \"name\": \"{{ $json['to-friendly'] }}\",\n \"email\": \"{{ $json.to }}\"\n }],\n \"subject\": \"{{ $json.subject }}\",\n \"bodyValues\": {\n \"textBody\": {\n \"value\": \"{{ $json.message.content.replace(/\\n/g, '\\\\n') }}\"\n }\n },\n \"bodyStructure\": {\n \"partId\": \"textBody\"\n }\n }\n }\n },\n \"c1\"\n ]\n ]\n}", +"sendBody": true, +"sendHeaders": true, +"specifyBody": "json", +"authentication": "genericCredentialType", +"genericAuthType": "httpHeaderAuth", +"headerParameters": { +"parameters": [ +{ +"name": "Content-Type", +"value": "application/json" +}, +{ +"name": "Accept", +"value": "application/json" +} +] +} +}, +"credentials": { +"httpHeaderAuth": { +"id": "3IRsYkeB2ofrwQjv", +"name": "Fastmail" +} +}, +"typeVersion": 4.2 +}, +{ +"id": "f4ecb64a-c978-4aa3-943e-c4a7f0592b91", +"name": "gather data for draft email", +"type": "n8n-nodes-base.set", +"position": [ +800, +-120 +], +"parameters": { +"options": {}, +"assignments": { +"assignments": [ +{ +"id": "78885ad0-fa62-407e-82de-f297190265be", +"name": "draftsId", +"type": "string", +"value": "={{ $json.id }}" +}, +{ +"id": "fcb31dde-0881-4b98-8bc2-e3e215148a5c", +"name": "to-friendly", +"type": "string", +"value": "={{ $('Get fields from source email').item.json.from.match(/[^<]+/)[0].trim().replaceAll(/\\\"/g, \"\") }}" +}, +{ +"id": "84c80af6-68dd-44bd-97ba-fde78a42e88a", +"name": "subject", +"type": "string", +"value": "=Re: {{ $('Get fields from source email').item.json.subject }}" +}, +{ +"id": "590e9856-9c6f-4d23-af42-8a0a1384ac00", +"name": "message.content", +"type": "string", +"value": "={{ $('OpenAI').item.json.message.content }}" +}, +{ +"id": "4f24e071-24e3-4101-a423-ad5bbcca9fc7", +"name": "metadata['message-id']", +"type": "string", +"value": "={{ $('Get fields from source email').item.json.metadata['message-id'] }}" +}, +{ +"id": "80c92734-0296-4299-9f98-15cc62e93d44", +"name": "to", +"type": "string", +"value": "={{ $('Get fields from source email').item.json.metadata['reply-to'].match(/<([^>]+)>/)[1] ?? $('Get fields from source email').item.json.from.match(/<([^>]+)>/)[1] }}" +} +] +} +}, +"typeVersion": 3.4 +}, +{ +"id": "ca868672-85bd-4e2e-b2c6-6c6c69b78b24", +"name": "Sticky Note", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-580, +-560 +], +"parameters": { +"width": 493.9330818092735, +"height": 695.2489786026621, +"content": "## Workflow Description:\nThis n8n workflow automates the drafting of email replies for Fastmail using OpenAI's GPT-4 model. Here’s the overall process:\n\n1. **Email Monitoring**: The workflow continuously monitors a specified IMAP inbox for new, unread emails.\n2. **Email Data Extraction**: When a new email is detected, it extracts relevant details such as the sender, subject, email body, and metadata.\n3. **AI Response Generation**: The extracted email content is sent to OpenAI's GPT-4, which generates a personalized draft response.\n4. **Get Fastmail Session and Mailbox IDs**: Connects to the Fastmail API to retrieve necessary session details and mailbox IDs.\n5. **Draft Identification**: Identifies the \"Drafts\" folder in the mailbox.\n6. **Draft Preparation**: Compiles all the necessary information to create the draft, including the generated response, original email details, and specified recipient.\n7. **Draft Uploading**: Uploads the prepared draft email to the \"Drafts\" folder in the Fastmail mailbox." +}, +"typeVersion": 1 +}, +{ +"id": "c4273cc2-1ac2-43f4-bcd1-7f42d3109373", +"name": "Sticky Note1", +"type": "n8n-nodes-base.stickyNote", +"position": [ +-40, +-560 +], +"parameters": { +"color": 3, +"width": 722.928660826031, +"height": 285.5319148936168, +"content": "## Prerequisites:\n1. **IMAP Email Account**: You need to configure an IMAP email account in n8n to monitor incoming emails.\n2. **Fastmail API Credentials**: A Fastmail account with JMAP API enabled. You should set up HTTP Header authentication in n8n with your Fastmail API credentials.\n3. **OpenAI API Key**: An API key from OpenAI to access GPT-4. Make sure to configure the OpenAI credentials in n8n." +}, +"typeVersion": 1 +} +], +"pinData": {}, +"connections": { +"OpenAI": { +"main": [ +[ +{ +"node": "Session", +"type": "main", +"index": 0 +} +] +] +}, +"Session": { +"main": [ +[ +{ +"node": "Get Mailbox IDs", +"type": "main", +"index": 0 +} +] +] +}, +"Split Out": { +"main": [ +[ +{ +"node": "Filter for drafts folder", +"type": "main", +"index": 0 +} +] +] +}, +"Get Mailbox IDs": { +"main": [ +[ +{ +"node": "Split Out", +"type": "main", +"index": 0 +} +] +] +}, +"Email Trigger (IMAP)": { +"main": [ +[ +{ +"node": "Get fields from source email", +"type": "main", +"index": 0 +} +] +] +}, +"Filter for drafts folder": { +"main": [ +[ +{ +"node": "gather data for draft email", +"type": "main", +"index": 0 +} +] +] +}, +"gather data for draft email": { +"main": [ +[ +{ +"node": "upload draft email", +"type": "main", +"index": 0 +} +] +] +}, +"Get fields from source email": { +"main": [ +[ +{ +"node": "OpenAI", +"type": "main", +"index": 0 +} +] +] +} +} +} \ No newline at end of file