{ "name": "Telegram Assistant - Receiver", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "8f3f59db-aaa5-4762-9416-94be04131fd2", "options": {} }, "id": "telegram-trigger-1", "name": "Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 1, "position": [ 240, 300 ], "webhookId": "8f3f59db-aaa5-4762-9416-94be04131fd2" }, { "parameters": { "conditions": { "string": [ { "value1": "={{$json.message?.text || ''}}", "operation": "startsWith", "value2": "/" } ] } }, "id": "check-command-1", "name": "Check if Command", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ 460, 300 ] }, { "parameters": { "chatId": "={{ $json.message.chat.id }}", "text": "=Command received: {{ $json.message.text }}\n\nProcessing...", "additionalFields": {} }, "id": "send-ack-1", "name": "Send Acknowledgment", "type": "n8n-nodes-base.telegram", "typeVersion": 1, "position": [ 680, 200 ], "credentials": { "telegramApi": { "id": "6Rim8odDFpQoHxCM", "name": "mortimer" } } }, { "parameters": { "mode": "runOnceForEachItem", "jsCode": "// Extract command and parameters\nconst text = $input.item.json.message?.text || '';\nconst chatId = $input.item.json.message?.chat?.id;\nconst messageId = $input.item.json.message?.message_id;\nconst userId = $input.item.json.message?.from?.id;\nconst username = $input.item.json.message?.from?.username || 'unknown';\n\n// Parse command\nconst parts = text.trim().split(/\\s+/);\nconst command = parts[0].toLowerCase();\nconst args = parts.slice(1).join(' ');\n\nreturn {\n command: command,\n args: args,\n chatId: chatId,\n messageId: messageId,\n userId: userId,\n username: username,\n originalText: text\n};" }, "id": "parse-command-1", "name": "Parse Command", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 900, 200 ] }, { "parameters": { "mode": "runOnceForEachItem", "jsCode": "// Extract natural language message\nconst text = $input.item.json.message?.text || '';\nconst chatId = $input.item.json.message?.chat?.id;\nconst messageId = $input.item.json.message?.message_id;\nconst userId = $input.item.json.message?.from?.id;\nconst username = $input.item.json.message?.from?.username || 'unknown';\n\nreturn {\n chatId: chatId,\n messageId: messageId,\n userId: userId,\n username: username,\n originalText: text\n};" }, "id": "parse-natural-language-1", "name": "Parse Natural Language", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 680, 400 ] }, { "parameters": { "method": "POST", "url": "https://api.openai.com/v1/chat/completions", "authentication": "predefinedCredentialType", "nodeCredentialType": "openAiApi", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "=Bearer {{ $credentials.openai_api_key }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"Analyze user intent and classify into one of these categories. Return ONLY valid JSON with no additional text:\\n\\n1. 'deck_add' - User wants to create a task/card in Nextcloud Deck\\n Examples: 'add a deck called cleaning', 'create task review reports', 'remind me to call mom tomorrow'\\n Extract: {intent: 'deck_add', task: 'task description', duedate: 'YYYY-MM-DD or null'}\\n\\n2. 'email_search' - User wants to search emails\\n Examples: 'find my train ticket', 'search for invoice', 'show emails from last week'\\n Extract: {intent: 'email_search', query: 'search terms'}\\n\\n3. 'general_chat' - General questions, conversation\\n Examples: 'what's the weather', 'explain quantum physics', 'tell me a joke'\\n Extract: {intent: 'general_chat', question: 'full question'}\\n\\nFor dates like 'today', 'tomorrow', 'next week', calculate from today: {{ $now.toFormat('yyyy-MM-dd') }}.\\nFor German: 'morgen' = tomorrow, 'übermorgen' = day after tomorrow.\\n\\nReturn JSON format: {\\\"intent\\\": \\\"category\\\", ...extracted_data}\"\n },\n {\n \"role\": \"user\",\n \"content\": \"{{ $json.originalText }}\"\n }\n ],\n \"temperature\": 0.3,\n \"max_tokens\": 150\n}", "options": {} }, "id": "ai-classify-intent-1", "name": "AI Classify Intent", "type": "n8n-nodes-base.httpRequest", "typeVersion": 3, "position": [ 900, 400 ], "credentials": { "httpHeaderAuth": { "id": "openai_api_key", "name": "OpenAI API Key" } } }, { "parameters": { "mode": "runOnceForEachItem", "jsCode": "// Parse AI classification result\nconst aiResponse = $input.item.json.choices[0].message.content;\nconst chatId = $input.item.json.chatId;\nconst userId = $input.item.json.userId;\nconst username = $input.item.json.username;\nconst originalText = $input.item.json.originalText;\n\nlet classification;\ntry {\n classification = JSON.parse(aiResponse);\n} catch (e) {\n // Fallback to general chat if parsing fails\n classification = {\n intent: 'general_chat',\n question: originalText\n };\n}\n\n// Map intent to command format for router\nlet command, args;\n\nswitch (classification.intent) {\n case 'deck_add':\n command = '/deck';\n args = 'add ' + (classification.task || originalText);\n break;\n case 'email_search':\n command = '/email';\n args = 'search ' + (classification.query || originalText);\n break;\n case 'general_chat':\n default:\n command = '/ask';\n args = classification.question || originalText;\n break;\n}\n\nreturn {\n command: command,\n args: args,\n chatId: chatId,\n userId: userId,\n username: username,\n originalText: originalText,\n classifiedIntent: classification.intent\n};" }, "id": "format-as-command-1", "name": "Format as Command", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1120, 400 ] }, { "parameters": { "method": "POST", "url": "=https://flow.egonetix.de/webhook/telegram-router-direct", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify($json) }}", "options": { "response": { "response": { "neverError": true } } } }, "id": "call-router-natural-1", "name": "Call Router (Natural Language)", "type": "n8n-nodes-base.httpRequest", "typeVersion": 3, "position": [ 1340, 400 ] }, { "parameters": { "method": "POST", "url": "=https://flow.egonetix.de/webhook/telegram-router-direct", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify($json) }}", "options": { "response": { "response": { "neverError": true } } } }, "id": "call-router-1", "name": "Call Router Workflow", "type": "n8n-nodes-base.httpRequest", "typeVersion": 3, "position": [ 1120, 200 ] } ], "connections": { "Webhook": { "main": [ [ { "node": "Check if Command", "type": "main", "index": 0 } ] ] }, "Check if Command": { "main": [ [ { "node": "Send Acknowledgment", "type": "main", "index": 0 } ], [ { "node": "Parse Natural Language", "type": "main", "index": 0 } ] ] }, "Parse Natural Language": { "main": [ [ { "node": "AI Classify Intent", "type": "main", "index": 0 } ] ] }, "AI Classify Intent": { "main": [ [ { "node": "Format as Command", "type": "main", "index": 0 } ] ] }, "Format as Command": { "main": [ [ { "node": "Call Router (Natural Language)", "type": "main", "index": 0 } ] ] }, "Send Acknowledgment": { "main": [ [ { "node": "Parse Command", "type": "main", "index": 0 } ] ] }, "Parse Command": { "main": [ [ { "node": "Call Router Workflow", "type": "main", "index": 0 } ] ] } }, "settings": {} }