diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index 0e36e4c..f1ddcc2 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -75,6 +75,8 @@ services: - ../data/n8n:/home/node/.n8n - ../local-files:/files - ../imports:/imports + extra_hosts: + - "host.docker.internal:host-gateway" depends_on: postgres: condition: service_healthy @@ -108,6 +110,8 @@ services: volumes: - ../data/n8n:/home/node/.n8n - ../local-files:/files + extra_hosts: + - "host.docker.internal:host-gateway" depends_on: - n8n networks: diff --git a/imports/workflows/ollama-chat-cleanup.json b/imports/workflows/ollama-chat-cleanup.json new file mode 100644 index 0000000..5c59c89 --- /dev/null +++ b/imports/workflows/ollama-chat-cleanup.json @@ -0,0 +1,53 @@ +{ + "id": "1002", + "name": "Chatbot Session Cleanup (TTL 2h)", + "nodes": [ + { + "parameters": { + "rule": { + "interval": [{ "field": "hours", "hoursInterval": 1 }] + } + }, + "id": "node-sc-001", + "name": "Jede Stunde", + "type": "n8n-nodes-base.scheduleTrigger", + "typeVersion": 1.2, + "position": [100, 300] + }, + { + "parameters": { + "operation": "executeQuery", + "query": "DELETE FROM chat_sessions WHERE updated_at < NOW() - INTERVAL '2 hours' RETURNING session_id", + "additionalFields": {} + }, + "id": "node-pg-003", + "name": "Delete Expired Sessions", + "type": "n8n-nodes-base.postgres", + "typeVersion": 2.5, + "position": [300, 300], + "credentials": { + "postgres": { + "id": "SETUP_REQUIRED", + "name": "n8n PostgreSQL" + } + } + }, + { + "parameters": { + "jsCode": "const deleted = $input.all().map(i => i.json.session_id).filter(Boolean);\nconsole.log(`[Cleanup] ${deleted.length} Session(s) gelöscht:`, deleted);\nreturn [{ json: { deleted_count: deleted.length, deleted_sessions: deleted } }];" + }, + "id": "node-cd-004", + "name": "Log Result", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [500, 300] + } + ], + "connections": { + "Jede Stunde": { "main": [[{ "node": "Delete Expired Sessions", "type": "main", "index": 0 }]] }, + "Delete Expired Sessions": { "main": [[{ "node": "Log Result", "type": "main", "index": 0 }]] } + }, + "active": false, + "settings": { "executionOrder": "v1" }, + "tags": [] +} diff --git a/imports/workflows/ollama-chat-delete.json b/imports/workflows/ollama-chat-delete.json new file mode 100644 index 0000000..82f9b50 --- /dev/null +++ b/imports/workflows/ollama-chat-delete.json @@ -0,0 +1,59 @@ +{ + "id": "1003", + "name": "Chatbot Session löschen", + "nodes": [ + { + "parameters": { + "httpMethod": "DELETE", + "path": "chat-session", + "responseMode": "responseNode", + "options": {} + }, + "id": "node-wh-002", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 2, + "position": [100, 300], + "webhookId": "ollama-chat-delete" + }, + { + "parameters": { + "operation": "executeQuery", + "query": "DELETE FROM chat_sessions WHERE session_id = $1 RETURNING session_id", + "additionalFields": { + "queryParams": "={{ JSON.stringify([$json.body.session_id]) }}" + } + }, + "id": "node-pg-004", + "name": "Delete Session", + "type": "n8n-nodes-base.postgres", + "typeVersion": 2.5, + "position": [300, 300], + "credentials": { + "postgres": { + "id": "SETUP_REQUIRED", + "name": "n8n PostgreSQL" + } + } + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ JSON.stringify({ deleted: $input.first().json.session_id != null, session_id: $('Webhook').first().json.body.session_id }) }}", + "options": {} + }, + "id": "node-rw-002", + "name": "Respond", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [500, 300] + } + ], + "connections": { + "Webhook": { "main": [[{ "node": "Delete Session", "type": "main", "index": 0 }]] }, + "Delete Session": { "main": [[{ "node": "Respond", "type": "main", "index": 0 }]] } + }, + "active": false, + "settings": { "executionOrder": "v1" }, + "tags": [] +} diff --git a/imports/workflows/ollama-chatbot.json b/imports/workflows/ollama-chatbot.json new file mode 100644 index 0000000..64dfa38 --- /dev/null +++ b/imports/workflows/ollama-chatbot.json @@ -0,0 +1,130 @@ +{ + "id": "1001", + "name": "Lokaler KI-Chatbot (Ollama)", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "chat", + "responseMode": "responseNode", + "options": {} + }, + "id": "node-wh-001", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 2, + "position": [100, 300], + "webhookId": "ollama-chat-webhook" + }, + { + "parameters": { + "jsCode": "const body = $input.first().json.body;\nif (!body?.message) throw new Error('Kein \"message\"-Feld im Request-Body');\nreturn [{ json: {\n session_id: body.session_id || Math.random().toString(36).slice(2, 18),\n message: body.message,\n model: body.model || 'qwen3:8b'\n}}];" + }, + "id": "node-cd-001", + "name": "Prepare", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [300, 300] + }, + { + "parameters": { + "operation": "executeQuery", + "query": "SELECT messages FROM chat_sessions WHERE session_id = $1", + "additionalFields": { + "queryParams": "={{ JSON.stringify([$json.session_id]) }}" + } + }, + "id": "node-pg-001", + "name": "Load History", + "type": "n8n-nodes-base.postgres", + "typeVersion": 2.5, + "position": [500, 300], + "credentials": { + "postgres": { + "id": "SETUP_REQUIRED", + "name": "n8n PostgreSQL" + } + } + }, + { + "parameters": { + "jsCode": "const prep = $('Prepare').first().json;\nconst row = $input.first()?.json;\nconst history = Array.isArray(row?.messages) ? row.messages : [];\nconst messages = [...history, { role: 'user', content: prep.message }];\nreturn [{ json: { session_id: prep.session_id, model: prep.model, messages } }];" + }, + "id": "node-cd-002", + "name": "Build Messages", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [700, 300] + }, + { + "parameters": { + "method": "POST", + "url": "http://host.docker.internal:11434/api/chat", + "sendBody": true, + "contentType": "json", + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ model: $json.model, messages: $json.messages, stream: false }) }}", + "options": { "timeout": 120000 } + }, + "id": "node-hr-001", + "name": "Ollama Chat", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [900, 300] + }, + { + "parameters": { + "jsCode": "const build = $('Build Messages').first().json;\nconst resp = $input.first().json;\nconst answer = resp.message.content;\nconst updatedMessages = [...build.messages, { role: 'assistant', content: answer }];\nreturn [{ json: { session_id: build.session_id, messages: updatedMessages, answer, model: resp.model } }];" + }, + "id": "node-cd-003", + "name": "Append Response", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [1100, 300] + }, + { + "parameters": { + "operation": "executeQuery", + "query": "INSERT INTO chat_sessions (session_id, messages, updated_at) VALUES ($1, $2::jsonb, NOW()) ON CONFLICT (session_id) DO UPDATE SET messages = $2::jsonb, updated_at = NOW()", + "additionalFields": { + "queryParams": "={{ JSON.stringify([$json.session_id, JSON.stringify($json.messages)]) }}" + } + }, + "id": "node-pg-002", + "name": "Save History", + "type": "n8n-nodes-base.postgres", + "typeVersion": 2.5, + "position": [1300, 300], + "credentials": { + "postgres": { + "id": "SETUP_REQUIRED", + "name": "n8n PostgreSQL" + } + } + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ JSON.stringify({ session_id: $('Append Response').first().json.session_id, answer: $('Append Response').first().json.answer, model: $('Append Response').first().json.model }) }}", + "options": {} + }, + "id": "node-rw-001", + "name": "Respond", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [1500, 300] + } + ], + "connections": { + "Webhook": { "main": [[{ "node": "Prepare", "type": "main", "index": 0 }]] }, + "Prepare": { "main": [[{ "node": "Load History", "type": "main", "index": 0 }]] }, + "Load History": { "main": [[{ "node": "Build Messages", "type": "main", "index": 0 }]] }, + "Build Messages": { "main": [[{ "node": "Ollama Chat", "type": "main", "index": 0 }]] }, + "Ollama Chat": { "main": [[{ "node": "Append Response", "type": "main", "index": 0 }]] }, + "Append Response": { "main": [[{ "node": "Save History", "type": "main", "index": 0 }]] }, + "Save History": { "main": [[{ "node": "Respond", "type": "main", "index": 0 }]] } + }, + "active": false, + "settings": { "executionOrder": "v1" }, + "tags": [] +}