[Vorlage] - Dashboard-Chat
Dies ist ein Automatisierungsworkflow mit 30 Nodes. Hauptsächlich werden N8n, Set, Code, Merge, Webhook und andere Nodes verwendet. KI-Modell nutzt Dashboard: Verfolgen von Token-Metriken und Kosten für LLM-Workflows
- •HTTP Webhook-Endpunkt (wird von n8n automatisch generiert)
- •OpenAI API Key
Verwendete Nodes (30)
Kategorie
{
"id": "Yu2P4qvlbmpPT3mg",
"meta": {
"instanceId": "b35269c8495db354f1459fb10ec8f343e34cd6c71fb24a004bb668ccda72b4e6",
"templateCredsSetupCompleted": true
},
"name": "[Template] - Dashboard Chat",
"tags": [],
"nodes": [
{
"id": "85c930e9-cb8a-47ad-8082-5ae97c945b4b",
"name": "Wenn Chat-Nachricht empfangen",
"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": "KI-Agent",
"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": "Einfacher Speicher",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-48,
1456
],
"parameters": {},
"typeVersion": 1.3
},
{
"id": "522553ba-e4eb-42d9-ae80-d6de88577792",
"name": "Haftnotiz1",
"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 Chat-Modell",
"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": "Ausführungs-ID abrufen",
"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": "Modell-/Token-Info",
"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": "Zeile einfügen2",
"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": "Ausführung abrufen",
"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": "Zeitplan-Trigger",
"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": "Zeile(n) abrufen",
"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": "Zeile(n) aktualisieren",
"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": "Felder bearbeiten",
"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": "Zeile einfügen1",
"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": "Haftnotiz",
"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": "Zeile(n) abrufen1",
"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": "Felder bearbeiten1",
"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": "Über Elemente iterieren",
"type": "n8n-nodes-base.splitInBatches",
"position": [
128,
1872
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "451c7483-b793-47d9-869b-695bea8771ab",
"name": "Keine Operation, nichts tun",
"type": "n8n-nodes-base.noOp",
"position": [
352,
1680
],
"parameters": {},
"typeVersion": 1
},
{
"id": "e9c3fa27-22b9-42f5-bf51-e51f78abbe94",
"name": "Haftnotiz2",
"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": "Zeile(n) abrufen3",
"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": "Zusammenführen1",
"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": "Code in 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": "Haftnotiz3",
"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": "Keine Operation, nichts tun1",
"type": "n8n-nodes-base.noOp",
"position": [
272,
1264
],
"parameters": {},
"typeVersion": 1
},
{
"id": "10c02d77-5179-44a5-a219-213921b41377",
"name": "Code in 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": "Auf Webhook antworten",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
496,
992
],
"parameters": {
"options": {},
"respondWith": "binary"
},
"typeVersion": 1.4
},
{
"id": "b2f02fbb-2604-4f60-9449-6a8fa76ee670",
"name": "Haftnotiz4",
"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": "Haftnotiz5",
"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
}
]
]
}
}
}Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Experte
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
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
Diesen Workflow teilen