[Plantilla] - Chat de Panel de Control

Avanzado

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

Requisitos previos
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Clave de API de OpenAI

Categoría

-
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "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
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿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.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos30
Categoría-
Tipos de nodos15
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor

Growth engineer focused on AI, data automation, and custom integrations. Use to turn complex ideas into simple, and scalable workflows with solid infrastructure

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34