feat: Chatbot-Workflows mit Ollama-Memory und Session-Management
- docker-compose: extra_hosts für host.docker.internal (Ollama-Zugang) - ollama-chatbot: Gesprächsverlauf per session_id in PostgreSQL - ollama-chat-cleanup: stündliche TTL-Bereinigung (2h Inaktivität) - ollama-chat-delete: DELETE /webhook/chat-session Endpoint Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
897b1ccf3d
commit
60143b8061
4 changed files with 246 additions and 0 deletions
53
imports/workflows/ollama-chat-cleanup.json
Normal file
53
imports/workflows/ollama-chat-cleanup.json
Normal file
|
|
@ -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": []
|
||||
}
|
||||
59
imports/workflows/ollama-chat-delete.json
Normal file
59
imports/workflows/ollama-chat-delete.json
Normal file
|
|
@ -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": []
|
||||
}
|
||||
130
imports/workflows/ollama-chatbot.json
Normal file
130
imports/workflows/ollama-chatbot.json
Normal file
|
|
@ -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": []
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue