fix: resolve MariaDB collation error by switching from mysql-connector to PyMySQL
- Replace mysql-connector-python with PyMySQL driver for better MariaDB compatibility - PyMySQL handles utf8mb4_0900_ai_ci collation properly without errors - Update Dockerfile.sql-executor to install PyMySQL and psycopg2-binary - Refactor sql-query-executor.py to use PyMySQL API (pymysql.connect, DictCursor) - Verified sql-executor service with SELECT, INSERT, UPDATE operations on Freescout DB - Add n8n workflow definitions: workflow-a-http.json and workflow-b-http.json * Workflow A: Polls unprocessed conversations, analyzes with LiteLLM, saves suggestions * Workflow B: Polls approved suggestions, executes Baramundi jobs or email replies - Update compose.yaml with sql-executor service configuration and dependencies All SQL operations now execute successfully against MariaDB 11.3.2
This commit is contained in:
337
n8n-workflows/workflow-b-http.json
Normal file
337
n8n-workflows/workflow-b-http.json
Normal file
@@ -0,0 +1,337 @@
|
||||
{
|
||||
"name": "Workflow B - Approval & Execution (HTTP)",
|
||||
"description": "Poll for approved AI suggestions and execute them (Baramundi jobs or email replies)",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "uuid-trigger-b",
|
||||
"name": "Trigger",
|
||||
"type": "n8n-nodes-base.cron",
|
||||
"typeVersion": 1,
|
||||
"position": [250, 200],
|
||||
"parameters": {
|
||||
"cronExpression": "*/2 * * * *"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-get-approved",
|
||||
"name": "Get Approved 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, ccf.value as ai_suggestion FROM conversations c JOIN conversation_custom_field ccf ON c.id = ccf.conversation_id WHERE ccf.custom_field_id = 7 AND ccf.value = 'APPROVED' LIMIT 10\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-split-approved",
|
||||
"name": "Split Results",
|
||||
"type": "n8n-nodes-base.splitInBatches",
|
||||
"typeVersion": 3,
|
||||
"position": [650, 200],
|
||||
"parameters": {
|
||||
"batchSize": 1,
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-extract-approved",
|
||||
"name": "Extract & Parse Suggestion",
|
||||
"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": "customer_email",
|
||||
"value": "={{ $json.customer_email }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "ai_suggestion_raw",
|
||||
"value": "={{ typeof $json.ai_suggestion === 'string' ? $json.ai_suggestion : JSON.stringify($json.ai_suggestion) }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "ai_suggestion",
|
||||
"value": "={{ typeof $json.ai_suggestion === 'string' ? JSON.parse($json.ai_suggestion) : $json.ai_suggestion }}",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"name": "solution_type",
|
||||
"value": "={{ $json.ai_suggestion.lösung_typ || 'UNKNOWN' }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-decide-solution",
|
||||
"name": "Decide Solution Type",
|
||||
"type": "n8n-nodes-base.switch",
|
||||
"typeVersion": 1,
|
||||
"position": [1050, 200],
|
||||
"parameters": {
|
||||
"options": [
|
||||
{
|
||||
"condition": "equal",
|
||||
"value1": "={{ $json.solution_type }}",
|
||||
"value2": "BARAMUNDI_JOB"
|
||||
},
|
||||
{
|
||||
"condition": "equal",
|
||||
"value1": "={{ $json.solution_type }}",
|
||||
"value2": "AUTOMATISCHE_ANTWORT"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-execute-baramundi",
|
||||
"name": "Execute Baramundi Job",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4,
|
||||
"position": [1250, 50],
|
||||
"parameters": {
|
||||
"url": "https://baramundi-api.example.com/api/jobs",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer YOUR_BARAMUNDI_TOKEN"
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "{\"job_name\":\"{{$json.ai_suggestion.baramundi_job}}\",\"ticket_id\":{{$json.ticket_id}},\"target_system\":\"IT\",\"description\":\"{{$json.subject}}\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-send-email",
|
||||
"name": "Send Email Reply",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4,
|
||||
"position": [1250, 150],
|
||||
"parameters": {
|
||||
"url": "http://host.docker.internal:4000/query/freescout",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "{\"query\":\"INSERT INTO threads (conversation_id, customer_id, user_id, type, status, body, created_at, updated_at) VALUES ({{$json.ticket_id}}, (SELECT customer_id FROM conversations WHERE id = {{$json.ticket_id}} LIMIT 1), NULL, 'customer', 'active', '{{$json.ai_suggestion.antwort_text | replace(\\\"'\\\", \\\"''\\\")}}', NOW(), NOW())\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-mark-escalation",
|
||||
"name": "Mark for Manual Review",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3,
|
||||
"position": [1250, 270],
|
||||
"parameters": {
|
||||
"options": {},
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"name": "action",
|
||||
"value": "Manual escalation required",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-update-status",
|
||||
"name": "Update Status to EXECUTED",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4,
|
||||
"position": [1450, 200],
|
||||
"parameters": {
|
||||
"url": "http://host.docker.internal:4000/query/freescout",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "{\"query\":\"UPDATE conversation_custom_field SET value = 'EXECUTED' WHERE conversation_id = {{$json.ticket_id}} AND custom_field_id = 7\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-trigger-workflow-c",
|
||||
"name": "Trigger Workflow C (KB Update)",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4,
|
||||
"position": [1650, 200],
|
||||
"parameters": {
|
||||
"url": "https://n8n.fft-it.de/webhook/workflow-c",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "{\"ticket_id\":{{$json.ticket_id}},\"subject\":\"{{$json.subject}}\",\"problem\":\"{{$json.subject}}\",\"solution\":\"{{$json.ai_suggestion.antwort_text}}\",\"category\":\"{{$json.ai_suggestion.kategorie}}\",\"solution_type\":\"{{$json.solution_type}}\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uuid-log-audit",
|
||||
"name": "Log to PostgreSQL",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4,
|
||||
"position": [1850, 200],
|
||||
"parameters": {
|
||||
"url": "http://host.docker.internal:4000/query/audit",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "{\"query\":\"INSERT INTO workflow_executions (workflow_name, ticket_id, status, execution_time_ms, created_at) VALUES ('Workflow B - Approval Execution', {{$json.ticket_id}}, 'SUCCESS', 0, NOW())\"}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Trigger": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get Approved Conversations",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get Approved Conversations": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Split Results",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Split Results": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract & Parse Suggestion",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract & Parse Suggestion": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decide Solution Type",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Decide Solution Type": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Baramundi Job",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Send Email Reply",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Mark for Manual Review",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Baramundi Job": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Update Status to EXECUTED",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Send Email Reply": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Update Status to EXECUTED",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Mark for Manual Review": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Update Status to EXECUTED",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Update Status to EXECUTED": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Trigger Workflow C (KB Update)",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Trigger Workflow C (KB Update)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Log to PostgreSQL",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"errorHandler": "continueOnError"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user