[Plantilla] - Chat de Panel de Control
Este es unautomatización que contiene 30 nodos.Utiliza principalmente nodos como N8n, Set, Code, Merge, Webhook. Modelo de IA utilizando un panel de control: rastrea métricas de tokens y costos de flujos de trabajo de LLM
- •Punto final de HTTP Webhook (n8n generará automáticamente)
- •Clave de API de OpenAI
Nodos utilizados (30)
Categoría
{
"id": "Yu2P4qvlbmpPT3mg",
"meta": {
"instanceId": "b35269c8495db354f1459fb10ec8f343e34cd6c71fb24a004bb668ccda72b4e6",
"templateCredsSetupCompleted": true
},
"name": "[Template] - Dashboard Chat",
"tags": [],
"nodes": [
{
"id": "85c930e9-cb8a-47ad-8082-5ae97c945b4b",
"name": "Cuando se recibe mensaje de chat",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-320,
1264
],
"webhookId": "09b95814-ef46-410f-adfb-7ef2683d499d",
"parameters": {
"public": true,
"options": {}
},
"typeVersion": 1.3
},
{
"id": "cbd8fb15-5cf0-4993-a5f5-c732496c3efe",
"name": "Agente de IA",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-96,
1264
],
"parameters": {
"text": "=Réponds à ce message : \n{{ $json.chatInput }}\n",
"options": {},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "e0decd9d-dc72-4283-815b-08f79b1b33b9",
"name": "Memoria Simple",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-48,
1456
],
"parameters": {},
"typeVersion": 1.3
},
{
"id": "522553ba-e4eb-42d9-ae80-d6de88577792",
"name": "Nota Adhesiva1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
1648
],
"parameters": {
"color": 3,
"width": 1968,
"height": 464,
"content": "## 🧠 Mini Workflow — Token Tracking\n"
},
"typeVersion": 1
},
{
"id": "0f270c23-7f82-49b4-8bbb-4362d12fcd60",
"name": "OpenAI Modelo de Chat",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-224,
1456
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "Eyt0iPqZCLeZxqlC",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "d36b0ff3-8367-4790-ae92-141df8205be1",
"name": "Obtener ID de Ejecución",
"type": "n8n-nodes-base.set",
"position": [
272,
1440
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "3677fb1a-e0b3-4468-bd10-6250ee768329",
"name": "id",
"type": "string",
"value": "={{$execution.id}}"
},
{
"id": "44775e78-8260-4316-a358-39b8b941313e",
"name": "model",
"type": "string",
"value": "={{$('OpenAI Chat Model').params.model}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6f390583-909a-4ecd-822e-12feb703ff30",
"name": "Información de Modelo/Token",
"type": "n8n-nodes-base.set",
"position": [
576,
1872
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "701dd054-2196-489d-8c9c-05d802ddf0d9",
"name": "model_name",
"type": "string",
"value": "={{ $('OpenAI Chat Model').params.model.value }}"
},
{
"id": "4ec60898-644f-46c4-9b14-a306c64c2da9",
"name": "completionTokens",
"type": "number",
"value": "={{ $json.data.resultData.runData['OpenAI Chat Model'][0].data.ai_languageModel[0][0].json.tokenUsage.completionTokens }}"
},
{
"id": "10c28ae4-4618-48c9-9787-63acd3fe66b3",
"name": "promptTokens",
"type": "number",
"value": "={{ $json.data.resultData.runData['OpenAI Chat Model'][0].data.ai_languageModel[0][0].json.tokenUsage.promptTokens }}"
},
{
"id": "41d5534d-dc94-4751-a233-446b039c3a43",
"name": "totalTokens",
"type": "number",
"value": "={{ $json.data.resultData.runData['OpenAI Chat Model'][0].data.ai_languageModel[0][0].json.tokenUsage.totalTokens }}"
},
{
"id": "ec0edb07-dabe-44fd-93df-a901838472c8",
"name": "executionId",
"type": "string",
"value": "={{ $json.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a47a978e-c1aa-4f98-89b4-e25294ff9d63",
"name": "Insertar fila2",
"type": "n8n-nodes-base.dataTable",
"position": [
496,
1440
],
"parameters": {
"columns": {
"value": {
"action": "={{ $('When chat message received').item.json.action }}",
"output": "={{ $('AI Agent').item.json.output }}",
"chatInput": "={{ $('When chat message received').item.json.chatInput }}",
"sessionId": "={{ $('When chat message received').item.json.sessionId }}",
"executionId": "={{ $json.id }}"
},
"schema": [
{
"id": "sessionId",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "sessionId",
"defaultMatch": false
},
{
"id": "action",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "action",
"defaultMatch": false
},
{
"id": "output",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "output",
"defaultMatch": false
},
{
"id": "chatInput",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "chatInput",
"defaultMatch": false
},
{
"id": "completionTokens",
"type": "number",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "completionTokens",
"defaultMatch": false
},
{
"id": "promptTokens",
"type": "number",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "promptTokens",
"defaultMatch": false
},
{
"id": "totalTokens",
"type": "number",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "totalTokens",
"defaultMatch": false
},
{
"id": "globalCost",
"type": "number",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "globalCost",
"defaultMatch": false
},
{
"id": "modelName",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "modelName",
"defaultMatch": false
},
{
"id": "executionId",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "executionId",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "GyHAqQLTtmZbynYI",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/GyHAqQLTtmZbynYI",
"cachedResultName": "Template - data"
}
},
"typeVersion": 1
},
{
"id": "7b0b70b9-5b36-4e36-b811-da21af4dbaae",
"name": "Obtener una ejecución",
"type": "n8n-nodes-base.n8n",
"position": [
352,
1872
],
"parameters": {
"options": {
"activeWorkflows": true
},
"resource": "execution",
"operation": "get",
"executionId": "={{ $json.executionId }}",
"requestOptions": {}
},
"credentials": {
"n8nApi": {
"id": "sqvLt8TzAknSm5NM",
"name": "n8n account 2"
}
},
"typeVersion": 1
},
{
"id": "cdd04485-cdbc-4015-85a1-fdd5c359f4f4",
"name": "Activador Programado",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-320,
1872
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 30
}
]
}
},
"typeVersion": 1.2
},
{
"id": "6552176e-15d3-4886-b8b8-f463d0c49e08",
"name": "Obtener fila(s)",
"type": "n8n-nodes-base.dataTable",
"position": [
-96,
1872
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "modelName",
"condition": "isEmpty"
}
]
},
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "GyHAqQLTtmZbynYI",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/GyHAqQLTtmZbynYI",
"cachedResultName": "Template - data"
}
},
"typeVersion": 1
},
{
"id": "ca373635-6cc4-44e1-b4f5-d44ed3d487b1",
"name": "Actualizar fila(s)",
"type": "n8n-nodes-base.dataTable",
"position": [
1376,
1856
],
"parameters": {
"columns": {
"value": {
"modelName": "={{ $json.model_name }}",
"globalCost": "={{ $json.globalCost }}",
"totalTokens": "={{ $json.promptTokens }}",
"promptTokens": "={{ $json.promptTokens }}",
"completionTokens": "={{ $json.completionTokens }}"
},
"schema": [
{
"id": "sessionId",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "sessionId",
"defaultMatch": false
},
{
"id": "action",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "action",
"defaultMatch": false
},
{
"id": "output",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "output",
"defaultMatch": false
},
{
"id": "chatInput",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "chatInput",
"defaultMatch": false
},
{
"id": "completionTokens",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "completionTokens",
"defaultMatch": false
},
{
"id": "promptTokens",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "promptTokens",
"defaultMatch": false
},
{
"id": "totalTokens",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "totalTokens",
"defaultMatch": false
},
{
"id": "globalCost",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "globalCost",
"defaultMatch": false
},
{
"id": "modelName",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "modelName",
"defaultMatch": false
},
{
"id": "executionId",
"type": "number",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "executionId",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"filters": {
"conditions": [
{
"keyName": "executionId",
"keyValue": "={{ $json.executionId }}"
}
]
},
"operation": "update",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "GyHAqQLTtmZbynYI",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/GyHAqQLTtmZbynYI",
"cachedResultName": "Template - data"
}
},
"typeVersion": 1
},
{
"id": "63788429-3fd4-423d-8b29-6b8d4101720e",
"name": "Editar Campos",
"type": "n8n-nodes-base.set",
"position": [
-128,
992
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "95f26c22-8da0-4d86-91f5-ee633cc72e98",
"name": "today",
"type": "string",
"value": "={{ $today }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a3372fa9-18a2-4152-891d-2e40faf0b31f",
"name": "Insertar fila1",
"type": "n8n-nodes-base.dataTable",
"position": [
-304,
2256
],
"parameters": {
"columns": {
"value": {
"name": "={{ $json.name }}",
"promptTokensPrice": "={{ $json.promptTokensPrice }}",
"completionTokensPrice": "={{ $json.completionTokensPrice }}"
},
"schema": [
{
"id": "name",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "name",
"defaultMatch": false
},
{
"id": "promptTokensPrice",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "promptTokensPrice",
"defaultMatch": false
},
{
"id": "completionTokensPrice",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "completionTokensPrice",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "5tsC5vulvGwYGS2g",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/5tsC5vulvGwYGS2g",
"cachedResultName": "Model - Price"
}
},
"typeVersion": 1
},
{
"id": "a61ae8a0-85a6-4e1f-b3ec-8f4248839816",
"name": "Nota Adhesiva",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
2144
],
"parameters": {
"color": 5,
"width": 544,
"height": 272,
"content": "## 📊 LLM Pricing Table for n8n\n\n\n"
},
"typeVersion": 1
},
{
"id": "c89ef6c5-8b35-45d3-8e21-b54125323bee",
"name": "Obtener fila(s)1",
"type": "n8n-nodes-base.dataTable",
"position": [
80,
992
],
"parameters": {
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "GyHAqQLTtmZbynYI",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/GyHAqQLTtmZbynYI",
"cachedResultName": "Template - data"
}
},
"typeVersion": 1
},
{
"id": "9f4069e9-1d31-455c-9d4c-782ff0857ba0",
"name": "Editar Campos1",
"type": "n8n-nodes-base.set",
"position": [
-80,
2256
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f52f1004-3bed-448b-9655-b6c61d238f57",
"name": "",
"type": "string",
"value": ""
}
]
}
},
"typeVersion": 3.4
},
{
"id": "c3c21917-4e60-4545-b524-2f5bb28789bf",
"name": "Iterar sobre Elementos",
"type": "n8n-nodes-base.splitInBatches",
"position": [
128,
1872
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "451c7483-b793-47d9-869b-695bea8771ab",
"name": "Sin Operación, no hacer nada",
"type": "n8n-nodes-base.noOp",
"position": [
352,
1680
],
"parameters": {},
"typeVersion": 1
},
{
"id": "e9c3fa27-22b9-42f5-bf51-e51f78abbe94",
"name": "Nota Adhesiva2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
912
],
"parameters": {
"color": 6,
"width": 1152,
"height": 256,
"content": "## Generate Dashboard"
},
"typeVersion": 1
},
{
"id": "a92b9155-33e0-4d53-8e48-7d6ccd48a433",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-320,
992
],
"webhookId": "176f23d4-71b3-41e0-9364-43bea6be01d3",
"parameters": {
"path": "176f23d4-71b3-41e0-9364-43bea6be01d3",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "3ce8907e-c978-4769-942a-806cd7182351",
"name": "Obtener fila(s)3",
"type": "n8n-nodes-base.dataTable",
"position": [
784,
1744
],
"parameters": {
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "5tsC5vulvGwYGS2g",
"cachedResultUrl": "/projects/E58XbkoO8SgET2Sl/datatables/5tsC5vulvGwYGS2g",
"cachedResultName": "Model - Price"
}
},
"typeVersion": 1
},
{
"id": "0d493cb2-d367-4eb7-968e-1b05e8e0dee5",
"name": "Combinar1",
"type": "n8n-nodes-base.merge",
"position": [
944,
1856
],
"parameters": {
"mode": "combine",
"options": {},
"advanced": true,
"mergeByFields": {
"values": [
{
"field1": "name",
"field2": "model_name"
}
]
}
},
"typeVersion": 3.2
},
{
"id": "4f7b3e8e-8b1b-4ccc-af0f-2371ca846d95",
"name": "Código en JavaScript1",
"type": "n8n-nodes-base.code",
"position": [
1152,
1856
],
"parameters": {
"jsCode": "// Parcours tous les items reçus\nreturn items.map(item => {\n // Récupération des valeurs depuis l'item\n const completionTokens = item.json.completionTokens || 0;\n const promptTokens = item.json.promptTokens || 0;\n const completionTokensPrice = item.json.completionTokensPrice || 0;\n const promptTokensPrice = item.json.promptTokensPrice || 0;\n\n // Calcul du coût global\n const globalCost = (completionTokens * completionTokensPrice) + (promptTokens * promptTokensPrice);\n\n // Retourner l'item avec globalCost ajouté\n return {\n json: {\n ...item.json,\n globalCost\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "a5c21eed-3dcf-4a38-a341-d8bc42aaaf22",
"name": "Nota Adhesiva3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
1200
],
"parameters": {
"color": 4,
"width": 1104,
"height": 416,
"content": "## Chat Example :\n\n\n"
},
"typeVersion": 1
},
{
"id": "07c09e80-88a2-443b-bd8a-59db83d8c0a1",
"name": "Sin Operación, no hacer nada1",
"type": "n8n-nodes-base.noOp",
"position": [
272,
1264
],
"parameters": {},
"typeVersion": 1
},
{
"id": "10c02d77-5179-44a5-a219-213921b41377",
"name": "Código en JavaScript",
"type": "n8n-nodes-base.code",
"position": [
288,
992
],
"parameters": {
"jsCode": "// === Calcul des KPI pour les conversations ===\nlet totalConversations = 0;\nlet totalCompletionTokens = 0;\nlet totalPromptTokens = 0;\nlet totalTokens = 0;\nlet totalCost = 0;\nlet sessions = new Set();\nlet modelUsage = {};\nlet conversationsParJour = [];\n\nfor (const item of items) {\n const data = item.json;\n\n totalConversations += 1;\n totalCompletionTokens += data.completionTokens || 0;\n totalPromptTokens += data.promptTokens || 0;\n totalTokens += data.totalTokens || 0;\n\n // Calcul du coût global si absent\n let globalCost = data.globalCost;\n if (globalCost === null || globalCost === undefined) {\n const completionTokensPrice = data.completionTokensPrice || 0;\n const promptTokensPrice = data.promptTokensPrice || 0;\n globalCost = (data.completionTokens || 0) * completionTokensPrice + (data.promptTokens || 0) * promptTokensPrice;\n }\n totalCost += globalCost;\n\n // Comptage des sessions uniques\n if (data.sessionId) sessions.add(data.sessionId);\n\n // Comptage messages par modèle\n const model = data.modelName || \"unknown\";\n if (!modelUsage[model]) modelUsage[model] = 0;\n modelUsage[model] += 1;\n\n // Tableau journalier\n if (data.createdAt) {\n const day = data.createdAt.split(\"T\")[0];\n let dayEntry = conversationsParJour.find(d => d.date === day);\n if (!dayEntry) {\n dayEntry = { date: day, count: 0, totalCost: 0, promptTokens: 0, completionTokens: 0 };\n conversationsParJour.push(dayEntry);\n }\n dayEntry.count += 1;\n dayEntry.totalCost += globalCost;\n dayEntry.promptTokens += data.promptTokens || 0;\n dayEntry.completionTokens += data.completionTokens || 0;\n }\n}\n\n// Tri par date\nconversationsParJour = conversationsParJour.sort((a, b) => a.date.localeCompare(b.date));\n\n// Moyennes\nconst avgTokensPerConversation = totalConversations > 0 ? (totalTokens / totalConversations).toFixed(2) : 0;\nconst avgCostPerConversation = totalConversations > 0 ? (totalCost / totalConversations).toFixed(6) : 0;\n\n// === Génération HTML ===\nconst html = `\n<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Dashboard Conversations</title>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\">\n<style>\n:root {\n --radius: 0.65rem;\n --background: #ffffff;\n --foreground: #000000;\n --card: #f8f9fa;\n --card-foreground: #000000;\n --primary: #3b82f6;\n --chart-conversations: #3b82f6;\n --chart-tokens-prompt: #3b82f6;\n --chart-tokens-completion: #10b981;\n --destructive: #ef4444;\n --muted: #9ca3af;\n --border: #e5e7eb;\n}\nbody.dark {\n --background: #0b142c;\n --foreground: #f1f5f9;\n --card: #1e293b;\n --card-foreground: #f1f5f9;\n --primary: #60a5fa;\n --chart-conversations: #60a5fa;\n --chart-tokens-prompt: #60a5fa;\n --chart-tokens-completion: #34d399;\n --destructive: #f87171;\n --muted: #64748b;\n --border: #334155;\n}\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n\n body {\n background: var(--background);\n color: var(--foreground);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n padding: 20px;\n transition: background-color 0.3s ease, color 0.3s ease;\n }\n\n .container {\n max-width: 1400px;\n margin: 0 auto;\n }\n\n .header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 40px;\n }\n\n .header h1 {\n font-size: 2.5rem;\n font-weight: 700;\n }\n\n .section-title-header {\n font-size: 2.5rem;\n font-weight: 600;\n margin-top: 40px;\n margin-bottom: 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .section-title-header i {\n color: var(--chart-topup);\n font-size: 2.5rem;\n }\n\n .section-title {\n font-size: 1.5rem;\n font-weight: 600;\n margin-top: 40px;\n margin-bottom: 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .section-title i {\n color: var(--primary);\n font-size: 1.75rem;\n }\n\n .kpi-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1rem;\n margin-bottom: 30px;\n }\n\n .kpi-card {\n background: var(--card);\n border-radius: 0.625rem;\n padding: 20px;\n border: 1px solid var(--border);\n transition: background-color 0.3s ease, border-color 0.3s ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n\n .kpi-value {\n font-size: 2rem;\n font-weight: 700;\n margin-bottom: 8px;\n color: var(--card-foreground);\n transition: color 0.3s ease;\n }\n\n .kpi-positive {\n color: var(--chart-investment);\n }\n\n .kpi-negative {\n color: var(--destructive);\n }\n\n .kpi-label {\n font-size: 0.875rem;\n color: var(--muted-foreground);\n transition: color 0.3s ease;\n }\n\n .charts-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n }\n\n .chart-container {\n background: var(--card);\n border-radius: 0.625rem;\n padding: 20px;\n border: 1px solid var(--border);\n transition: background-color 0.3s ease, border-color 0.3s ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n position: relative;\n height: 400px;\n }\n\n .chart-wrapper {\n position: relative;\n height: 100%;\n }\n\n .theme-toggle {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n }\n\n .toggle-switch {\n width: 48px;\n height: 24px;\n background: var(--border);\n border-radius: 12px;\n position: relative;\n cursor: pointer;\n transition: background-color 0.3s ease;\n }\n\n .toggle-switch::after {\n content: '';\n position: absolute;\n width: 20px;\n height: 20px;\n background: var(--card);\n border-radius: 50%;\n top: 2px;\n left: 2px;\n transition: transform 0.3s ease;\n box-shadow: 0 1px 3px rgba(0,0,0,0.3);\n }\n\n body.dark .toggle-switch::after {\n transform: translateX(24px);\n }\n\n @media (max-width: 768px) {\n .kpi-grid {\n grid-template-columns: 1fr;\n }\n .charts-grid {\n grid-template-columns: 1fr;\n }\n .header {\n flex-direction: column;\n gap: 20px;\n }\n }\n\n</style>\n</head>\n<body class=\"dark\">\n<div class=\"container\">\n <div class=\"header\">\n <h1><i class=\"fas fa-comments\"></i> Dashboard Conversations</h1>\n <div class=\"theme-toggle\" onclick=\"toggleTheme()\">\n <span>🌙</span>\n <div class=\"toggle-switch\"></div>\n <span>☀️</span>\n </div>\n </div>\n\n <div class=\"section-title\"><i class=\"fas fa-wallet\"></i> Statistiques Clés</div>\n <div class=\"kpi-grid\">\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-positive\">${totalConversations.toLocaleString('fr-FR')}</div>\n <div class=\"kpi-label\">Total Messages</div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-positive\">${sessions.size.toLocaleString('fr-FR')}</div>\n <div class=\"kpi-label\">Sessions uniques</div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-positive\">${totalTokens.toLocaleString('fr-FR')}</div>\n <div class=\"kpi-label\">Total Tokens</div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-positive\">${avgTokensPerConversation}</div>\n <div class=\"kpi-label\">Tokens moyens par message</div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-negative\">${totalCost.toFixed(6)} €</div>\n <div class=\"kpi-label\">Coût total</div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-value kpi-negative\">${avgCostPerConversation} €</div>\n <div class=\"kpi-label\">Coût moyen par message</div>\n </div>\n </div>\n\n <div class=\"section-title\"><i class=\"fas fa-chart-bar\"></i> Historique Journalier</div>\n <div class=\"charts-grid\">\n <div class=\"chart-container\"><div class=\"chart-wrapper\"><canvas id=\"conversationsChart\"></canvas></div></div>\n <div class=\"chart-container\"><div class=\"chart-wrapper\"><canvas id=\"tokensChart\"></canvas></div></div>\n </div>\n</div>\n\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js\"></script>\n<script>\nconst conversationsParJour = ${JSON.stringify(conversationsParJour)};\n\nlet charts = {};\n\nfunction getCSSVariable(varName){return getComputedStyle(document.documentElement).getPropertyValue(varName).trim();}\nfunction getThemeColors(){const isDark=document.body.classList.contains('dark'); return {textPrimary:isDark?'#f1f5f9':'#000', textSecondary:isDark?'#94a3b8':'#6b7280', gridColor:isDark?'rgba(148,163,184,0.1)':'rgba(0,0,0,0.1)', borderColor:isDark?'#475569':'#d1d5db', tooltip:isDark?'rgba(15,23,42,0.9)':'rgba(0,0,0,0.9)', chartColor:getCSSVariable('--chart-conversations'), chartPrompt:getCSSVariable('--chart-tokens-prompt'), chartCompletion:getCSSVariable('--chart-tokens-completion')}};\n\nfunction createChartOptions(label){\n const colors=getThemeColors();\n return {responsive:true, maintainAspectRatio:false, plugins:{title:{display:true,text:label,color:colors.textPrimary,font:{size:16,weight:'bold'},padding:20},legend:{display:true,position:'top'},tooltip:{backgroundColor:colors.tooltip,titleColor:'#ffffff',bodyColor:'#ffffff',borderColor:colors.borderColor,borderWidth:1,padding:12,displayColors:true}}, scales:{x:{grid:{display:true,color:colors.gridColor,drawBorder:false},ticks:{color:colors.textSecondary,font:{size:11}}},y:{grid:{display:true,color:colors.gridColor,drawBorder:false},ticks:{color:colors.textSecondary,font:{size:11}},beginAtZero:true}}};\n}\n\nfunction initCharts(){\n const colors=getThemeColors();\n const ctx=document.getElementById('conversationsChart').getContext('2d');\n charts.conversations=new Chart(ctx,{type:'bar',data:{labels:conversationsParJour.map(d=>new Date(d.date).toLocaleDateString('fr-FR',{day:'2-digit',month:'2-digit'})),datasets:[{label:'Nombre de messages',data:conversationsParJour.map(d=>d.count),backgroundColor:colors.chartColor,borderColor:colors.chartColor,borderWidth:0,borderRadius:6}]},options:createChartOptions('Messages journaliers')});\n\n // Graphique tokens empilé\n const ctxTokens=document.getElementById('tokensChart').getContext('2d');\n charts.tokens=new Chart(ctxTokens,{type:'bar',data:{labels:conversationsParJour.map(d=>new Date(d.date).toLocaleDateString('fr-FR',{day:'2-digit',month:'2-digit'})),datasets:[{label:'Prompt Tokens',data:conversationsParJour.map(d=>d.promptTokens),backgroundColor:colors.chartPrompt},{label:'Completion Tokens',data:conversationsParJour.map(d=>d.completionTokens),backgroundColor:colors.chartCompletion}]},options:{...createChartOptions('Tokens utilisés par jour'),scales:{x:{stacked:true,grid:{display:true,color:colors.gridColor,drawBorder:false},ticks:{color:colors.textSecondary,font:{size:11}}},y:{stacked:true,grid:{display:true,color:colors.gridColor,drawBorder:false},ticks:{color:colors.textSecondary,font:{size:11}},beginAtZero:true}}}});\n}\n\nfunction updateChartsTheme(){\n const colors=getThemeColors();\n if(charts.conversations){\n charts.conversations.data.datasets[0].backgroundColor=colors.chartColor;\n charts.conversations.data.datasets[0].borderColor=colors.chartColor;\n charts.conversations.options.plugins.title.color=colors.textPrimary;\n charts.conversations.options.scales.x.grid.color=colors.gridColor;\n charts.conversations.options.scales.x.ticks.color=colors.textSecondary;\n charts.conversations.options.scales.y.grid.color=colors.gridColor;\n charts.conversations.options.scales.y.ticks.color=colors.textSecondary;\n charts.conversations.options.plugins.tooltip.backgroundColor=colors.tooltip;\n charts.conversations.update();\n }\n if(charts.tokens){\n charts.tokens.data.datasets[0].backgroundColor=colors.chartPrompt;\n charts.tokens.data.datasets[1].backgroundColor=colors.chartCompletion;\n charts.tokens.options.plugins.title.color=colors.textPrimary;\n charts.tokens.options.scales.x.grid.color=colors.gridColor;\n charts.tokens.options.scales.x.ticks.color=colors.textSecondary;\n charts.tokens.options.scales.y.grid.color=colors.gridColor;\n charts.tokens.options.scales.y.ticks.color=colors.textSecondary;\n charts.tokens.options.plugins.tooltip.backgroundColor=colors.tooltip;\n charts.tokens.update();\n }\n}\n\nfunction toggleTheme(){document.body.classList.toggle('dark'); updateChartsTheme();}\ndocument.addEventListener('DOMContentLoaded',initCharts);\n</script>\n</body>\n</html>\n`;\n\n// Retourner le HTML en binaire pour la node n8n\nreturn [{ binary: { data: Buffer.from(html, 'utf8') } }];\n"
},
"typeVersion": 2
},
{
"id": "63aae3c1-6479-477f-a26b-85f3d589a6bc",
"name": "Responder a Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
496,
992
],
"parameters": {
"options": {},
"respondWith": "binary"
},
"typeVersion": 1.4
},
{
"id": "b2f02fbb-2604-4f60-9449-6a8fa76ee670",
"name": "Nota Adhesiva4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
912
],
"parameters": {
"width": 496,
"height": 352,
"content": "## 🤖 n8n AI Workflow Dashboard\n\n### This template helps you collect and visualize data from your AI workflows in a simple and interactive way.\n\n- Track messages, sessions, tokens, and costs for each model.\n- Interactive HTML dashboard with KPIs: messages, sessions, tokens, and costs.\n- Compatible with any AI Agent or RAG workflow in n8n.\n\n### Use this dashboard to monitor AI activity and usage metrics at a glance, and easily identify trends or anomalies in your workflows."
},
"typeVersion": 1
},
{
"id": "19d31dbb-e89e-40c6-853d-f898ebbe1122",
"name": "Nota Adhesiva5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
1296
],
"parameters": {
"width": 496,
"height": 464,
"content": "## ⚙️ Setup & Run\n\n### Follow these steps to get your workflow up and running in n8n:\n\n- Import the JSON workflow into your n8n instance.\n- Create the Model price and Messages tables.\n- Import token cost data for your LLM models (LLM Pricing).\n- Configure the “chat message” node according to your input channels.\n- Once messages are collected, the Token Tracking sub-workflow calculates token usage and costs.\n- Visualize the dashboard using the HTML response returned by the webhook.\n\n### After setup, your workflow will automatically track AI activity, compute costs, and provide a live dashboard to monitor all your KPIs."
},
"typeVersion": 1
}
],
"active": true,
"pinData": {
"Edit Fields1": [
{
"json": {
"name": "claude-4.5-sonnet",
"promptTokensPrice": 0.000003,
"completionTokensPrice": 0.000015
}
},
{
"json": {
"name": "claude-4.5-sonnet-extended-context",
"promptTokensPrice": 0.000006,
"completionTokensPrice": 0.0000225
}
},
{
"json": {
"name": "gpt-5",
"promptTokensPrice": 0.00000125,
"completionTokensPrice": 0.00001
}
},
{
"json": {
"name": "gpt-5-mini",
"promptTokensPrice": 2.5e-7,
"completionTokensPrice": 0.000002
}
},
{
"json": {
"name": "gpt-5-nano",
"promptTokensPrice": 5e-8,
"completionTokensPrice": 4e-7
}
},
{
"json": {
"name": "Gemini-2.5-Pro",
"promptTokensPrice": 0.00000125,
"completionTokensPrice": 0.00000125
}
},
{
"json": {
"name": "Gemini-1.5-Flash",
"promptTokensPrice": 7.5e-7,
"completionTokensPrice": 0.000003
}
},
{
"json": {
"name": "gpt-4o",
"promptTokensPrice": 0.0000025,
"completionTokensPrice": 0.00001
}
},
{
"json": {
"name": "gpt-4o-mini",
"promptTokensPrice": 1.5e-7,
"completionTokensPrice": 6e-7
}
},
{
"json": {
"name": "gpt-4.1-mini",
"promptTokensPrice": 4e-7,
"completionTokensPrice": 0.0000016
}
},
{
"json": {
"name": "gpt-4.1-nano",
"promptTokensPrice": 1e-7,
"completionTokensPrice": 4e-7
}
},
{
"json": {
"name": "o3-mini",
"promptTokensPrice": 0.0000011,
"completionTokensPrice": 0.0000044
}
},
{
"json": {
"name": "Gemini-2.0-Flash-Lite",
"promptTokensPrice": 7.5e-8,
"completionTokensPrice": 3e-7
}
},
{
"json": {
"name": "DeepSeek-V3",
"promptTokensPrice": 2.7e-7,
"completionTokensPrice": 0.0000011
}
},
{
"json": {
"name": "Claude-3.7-Sonnet",
"promptTokensPrice": 0.000003,
"completionTokensPrice": 0.000015
}
},
{
"json": {
"name": "gpt-oss-20b",
"promptTokensPrice": 3e-8,
"completionTokensPrice": 1.4e-7
}
}
]
},
"settings": {
"executionOrder": "v1"
},
"versionId": "d1513dc9-185a-4183-bdcd-531b250483c3",
"connections": {
"0d493cb2-d367-4eb7-968e-1b05e8e0dee5": {
"main": [
[
{
"node": "4f7b3e8e-8b1b-4ccc-af0f-2371ca846d95",
"type": "main",
"index": 0
}
]
]
},
"a92b9155-33e0-4d53-8e48-7d6ccd48a433": {
"main": [
[
{
"node": "63788429-3fd4-423d-8b29-6b8d4101720e",
"type": "main",
"index": 0
}
]
]
},
"cbd8fb15-5cf0-4993-a5f5-c732496c3efe": {
"main": [
[
{
"node": "07c09e80-88a2-443b-bd8a-59db83d8c0a1",
"type": "main",
"index": 0
},
{
"node": "d36b0ff3-8367-4790-ae92-141df8205be1",
"type": "main",
"index": 0
}
]
]
},
"6552176e-15d3-4886-b8b8-f463d0c49e08": {
"main": [
[
{
"node": "c3c21917-4e60-4545-b524-2f5bb28789bf",
"type": "main",
"index": 0
}
]
]
},
"63788429-3fd4-423d-8b29-6b8d4101720e": {
"main": [
[
{
"node": "c89ef6c5-8b35-45d3-8e21-b54125323bee",
"type": "main",
"index": 0
}
]
]
},
"c89ef6c5-8b35-45d3-8e21-b54125323bee": {
"main": [
[
{
"node": "10c02d77-5179-44a5-a219-213921b41377",
"type": "main",
"index": 0
}
]
]
},
"3ce8907e-c978-4769-942a-806cd7182351": {
"main": [
[
{
"node": "0d493cb2-d367-4eb7-968e-1b05e8e0dee5",
"type": "main",
"index": 0
}
]
]
},
"a3372fa9-18a2-4152-891d-2e40faf0b31f": {
"main": [
[
{
"node": "9f4069e9-1d31-455c-9d4c-782ff0857ba0",
"type": "main",
"index": 0
}
]
]
},
"e0decd9d-dc72-4283-815b-08f79b1b33b9": {
"ai_memory": [
[
{
"node": "cbd8fb15-5cf0-4993-a5f5-c732496c3efe",
"type": "ai_memory",
"index": 0
}
]
]
},
"ca373635-6cc4-44e1-b4f5-d44ed3d487b1": {
"main": [
[
{
"node": "c3c21917-4e60-4545-b524-2f5bb28789bf",
"type": "main",
"index": 0
}
]
]
},
"d36b0ff3-8367-4790-ae92-141df8205be1": {
"main": [
[
{
"node": "a47a978e-c1aa-4f98-89b4-e25294ff9d63",
"type": "main",
"index": 0
}
]
]
},
"c3c21917-4e60-4545-b524-2f5bb28789bf": {
"main": [
[
{
"node": "451c7483-b793-47d9-869b-695bea8771ab",
"type": "main",
"index": 0
}
],
[
{
"node": "7b0b70b9-5b36-4e36-b811-da21af4dbaae",
"type": "main",
"index": 0
}
]
]
},
"7b0b70b9-5b36-4e36-b811-da21af4dbaae": {
"main": [
[
{
"node": "6f390583-909a-4ecd-822e-12feb703ff30",
"type": "main",
"index": 0
}
]
]
},
"6f390583-909a-4ecd-822e-12feb703ff30": {
"main": [
[
{
"node": "3ce8907e-c978-4769-942a-806cd7182351",
"type": "main",
"index": 0
},
{
"node": "0d493cb2-d367-4eb7-968e-1b05e8e0dee5",
"type": "main",
"index": 1
}
]
]
},
"cdd04485-cdbc-4015-85a1-fdd5c359f4f4": {
"main": [
[
{
"node": "6552176e-15d3-4886-b8b8-f463d0c49e08",
"type": "main",
"index": 0
}
]
]
},
"0f270c23-7f82-49b4-8bbb-4362d12fcd60": {
"ai_languageModel": [
[
{
"node": "cbd8fb15-5cf0-4993-a5f5-c732496c3efe",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"10c02d77-5179-44a5-a219-213921b41377": {
"main": [
[
{
"node": "63aae3c1-6479-477f-a26b-85f3d589a6bc",
"type": "main",
"index": 0
}
]
]
},
"4f7b3e8e-8b1b-4ccc-af0f-2371ca846d95": {
"main": [
[
{
"node": "ca373635-6cc4-44e1-b4f5-d44ed3d487b1",
"type": "main",
"index": 0
}
]
]
},
"85c930e9-cb8a-47ad-8082-5ae97c945b4b": {
"main": [
[
{
"node": "cbd8fb15-5cf0-4993-a5f5-c732496c3efe",
"type": "main",
"index": 0
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Avanzado
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
Hugo
@hugo-miseryGrowth engineer focused on AI, data automation, and custom integrations. Use to turn complex ideas into simple, and scalable workflows with solid infrastructure
Compartir este flujo de trabajo