{ "name": "Workflow A - Mail Processing (HTTP)", "description": "Fetch unprocessed conversations from Freescout, analyze with AI, save suggestions", "nodes": [ { "id": "uuid-trigger-1", "name": "Trigger", "type": "n8n-nodes-base.cron", "typeVersion": 1, "position": [250, 200], "parameters": { "cronExpression": "*/5 * * * *" } }, { "id": "uuid-get-conversations", "name": "Get Unprocessed Conversations", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [450, 200], "parameters": { "url": "http://host.docker.internal:4000/query/freescout", "method": "POST", "headers": { "Content-Type": "application/json" }, "sendBody": true, "specifyBody": "json", "jsonBody": "{\"query\":\"SELECT c.id, c.number, c.subject, c.customer_email, c.status, GROUP_CONCAT(t.body SEPARATOR ',') as threads_text FROM conversations c LEFT JOIN threads t ON c.id = t.conversation_id LEFT JOIN conversation_custom_field ccf ON c.id = ccf.conversation_id AND ccf.custom_field_id = 8 WHERE c.status = 1 AND ccf.id IS NULL GROUP BY c.id LIMIT 20\"}" } }, { "id": "uuid-split-results", "name": "Split Results", "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [650, 200], "parameters": { "batchSize": 1, "options": { "basePath": "data" } } }, { "id": "uuid-extract-data", "name": "Extract Conversation Data", "type": "n8n-nodes-base.set", "typeVersion": 3, "position": [850, 200], "parameters": { "options": {}, "assignments": { "assignments": [ { "name": "ticket_id", "value": "={{ $json.id }}", "type": "number" }, { "name": "ticket_number", "value": "={{ $json.number }}", "type": "number" }, { "name": "subject", "value": "={{ $json.subject }}", "type": "string" }, { "name": "problem_text", "value": "={{ ($json.threads_text || 'No description provided').substring(0, 2000) }}", "type": "string" }, { "name": "customer_email", "value": "={{ $json.customer_email }}", "type": "string" } ] } } }, { "id": "uuid-llm-analyze", "name": "LiteLLM AI Analysis", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [850, 200], "parameters": { "url": "http://llm.eks-ai.apps.asgard.eks-lnx.fft-it.de/v1/chat/completions", "method": "POST", "headers": { "Content-Type": "application/json" }, "sendBody": true, "specifyBody": "json", "jsonBody": "{\"model\":\"gpt-oss_120b_128k-gpu\",\"messages\":[{\"role\":\"system\",\"content\":\"Du bist ein IT-Support-Assistent. Analysiere das folgende IT-Support-Ticket und gib eine strukturierte JSON-Antwort mit folgenden Feldern: kategorie (z.B. Hardware, Software, Netzwerk, Zugriff), lösung_typ (BARAMUNDI_JOB, AUTOMATISCHE_ANTWORT, oder ESKALATION), vertrauen (Dezimal zwischen 0.0 und 1.0 - wie sicher bist du bei dieser Lösung), baramundi_job (Name des Jobs falls BARAMUNDI_JOB), antwort_text (Die Antwort an den Nutzer), begründung (Kurze Erklärung deiner Analyse)\"},{\"role\":\"user\",\"content\":\"Ticket-Nummer: {{$json.ticket_number}}\\nBetreff: {{$json.subject}}\\nProblembeschreibung:\\n{{$json.problem_text}}\\n\\nBitte antworte NUR mit gültiger JSON in dieser Struktur: {\\\"kategorie\\\": \\\"...\\\", \\\"lösung_typ\\\": \\\"...\\\", \\\"vertrauen\\\": 0.75, \\\"baramundi_job\\\": \\\"...\\\", \\\"antwort_text\\\": \\\"...\\\", \\\"begründung\\\": \\\"...\\\"}\"}],\"temperature\":0.7,\"max_tokens\":1000}" } }, { "id": "uuid-parse-response", "name": "Parse AI Response", "type": "n8n-nodes-base.set", "typeVersion": 3, "position": [1050, 200], "parameters": { "options": {}, "assignments": { "assignments": [ { "name": "response_text", "value": "={{ $json.choices?.[0]?.message?.content || '{}' }}", "type": "string" }, { "name": "ai_response", "value": "={{ typeof $json.response_text === 'string' ? JSON.parse($json.response_text) : $json.response_text }}", "type": "object" }, { "name": "vertrauen", "value": "={{ $json.ai_response?.vertrauen || 0.5 }}", "type": "number" } ] } } }, { "id": "uuid-check-confidence", "name": "Check Confidence >= 0.6", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [1250, 200], "parameters": { "conditions": { "options": { "caseSensitive": true, "extractValue": false }, "combinator": "and", "conditions": [ { "id": "condition_1", "leftValue": "={{ $json.vertrauen }}", "rightValue": 0.6, "operator": { "name": "filter.operator.gte", "value": ">=" } } ] } } }, { "id": "uuid-save-to-db", "name": "Save Suggestion to Freescout DB", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [1450, 100], "parameters": { "url": "http://host.docker.internal:4000/query/freescout", "method": "POST", "headers": { "Content-Type": "application/json" }, "sendBody": true, "specifyBody": "json", "jsonBody": "{\"query\":\"INSERT INTO conversation_custom_field (conversation_id, custom_field_id, value) VALUES ({{$json.ticket_id}}, 6, '{{$json.ai_response | json.stringify}}') ON DUPLICATE KEY UPDATE value = VALUES(value); INSERT INTO conversation_custom_field (conversation_id, custom_field_id, value) VALUES ({{$json.ticket_id}}, 7, 'PENDING') ON DUPLICATE KEY UPDATE value = VALUES(value); INSERT INTO conversation_custom_field (conversation_id, custom_field_id, value) VALUES ({{$json.ticket_id}}, 8, '1') ON DUPLICATE KEY UPDATE value = VALUES(value);\"}" } }, { "id": "uuid-no-action", "name": "Skip - Low Confidence", "type": "n8n-nodes-base.set", "typeVersion": 3, "position": [1450, 350], "parameters": { "options": {}, "assignments": { "assignments": [ { "name": "skipped", "value": true, "type": "boolean" }, { "name": "reason", "value": "Confidence {{$json.vertrauen}} < 0.6", "type": "string" } ] } } } ], "connections": { "Trigger": { "main": [ [ { "node": "Get Unprocessed Conversations", "index": 0 } ] ] }, "Get Unprocessed Conversations": { "main": [ [ { "node": "Split Results", "index": 0 } ] ] }, "Split Results": { "main": [ [ { "node": "Extract Conversation Data", "index": 0 } ] ] }, "Extract Conversation Data": { "main": [ [ { "node": "LiteLLM AI Analysis", "index": 0 } ] ] }, "LiteLLM AI Analysis": { "main": [ [ { "node": "Parse AI Response", "index": 0 } ] ] }, "Parse AI Response": { "main": [ [ { "node": "Check Confidence >= 0.6", "index": 0 } ] ] }, "Check Confidence >= 0.6": { "main": [ [ { "node": "Save Suggestion to Freescout DB", "index": 0 } ], [ { "node": "Skip - Low Confidence", "index": 0 } ] ] } }, "active": false, "settings": { "errorHandler": "continueOnError" } }