8
n8n 한국어amn8n.com

[템플릿] - 대시보드 채팅

고급

이것은자동화 워크플로우로, 30개의 노드를 포함합니다.주로 N8n, Set, Code, Merge, Webhook 등의 노드를 사용하며. AI 모델 대시보드 사용: LLM 워크플로우의 토큰 지표 및 비용 추적

사전 요구사항
  • HTTP Webhook 엔드포인트(n8n이 자동으로 생성)
  • OpenAI API Key

카테고리

-
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
  "id": "Yu2P4qvlbmpPT3mg",
  "meta": {
    "instanceId": "b35269c8495db354f1459fb10ec8f343e34cd6c71fb24a004bb668ccda72b4e6",
    "templateCredsSetupCompleted": true
  },
  "name": "[Template] - Dashboard Chat",
  "tags": [],
  "nodes": [
    {
      "id": "85c930e9-cb8a-47ad-8082-5ae97c945b4b",
      "name": "채팅 메시지 수신 시",
      "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": "AI 에이전트",
      "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": "심플 메모리",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -48,
        1456
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "522553ba-e4eb-42d9-ae80-d6de88577792",
      "name": "스티키 노트1",
      "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 채팅 모델",
      "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": "실행 ID 가져오기",
      "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": "모델/토큰 정보",
      "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": "행 삽입2",
      "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": "실행 가져오기",
      "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": "스케줄 트리거",
      "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": "행 가져오기",
      "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": "행 업데이트",
      "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": "필드 편집",
      "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": "행 삽입1",
      "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": "스티키 노트",
      "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": "행 가져오기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": "필드 편집1",
      "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": "항목 반복",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        128,
        1872
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "451c7483-b793-47d9-869b-695bea8771ab",
      "name": "작업 없음, 아무것도 하지 않음",
      "type": "n8n-nodes-base.noOp",
      "position": [
        352,
        1680
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e9c3fa27-22b9-42f5-bf51-e51f78abbe94",
      "name": "스티키 노트2",
      "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": "웹훅",
      "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": "행 가져오기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": "병합1",
      "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": "자바스크립트 코드1",
      "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": "스티키 노트3",
      "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": "작업 없음, 아무것도 하지 않음1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        272,
        1264
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "10c02d77-5179-44a5-a219-213921b41377",
      "name": "자바스크립트 코드",
      "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": "웹훅 응답",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        496,
        992
      ],
      "parameters": {
        "options": {},
        "respondWith": "binary"
      },
      "typeVersion": 1.4
    },
    {
      "id": "b2f02fbb-2604-4f60-9449-6a8fa76ee670",
      "name": "스티키 노트4",
      "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": "스티키 노트5",
      "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
          }
        ]
      ]
    }
  }
}
자주 묻는 질문

이 워크플로우를 어떻게 사용하나요?

위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.

이 워크플로우는 어떤 시나리오에 적합한가요?

고급

유료인가요?

이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수30
카테고리-
노드 유형15
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

저자

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

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34