Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {
- "nodes": [
- {
- "parameters": {
- "url": "https://raw.githubusercontent.com/Xavi1995/models_pricing/refs/heads/main/prices",
- "options": {
- "response": {
- "response": {
- "responseFormat": "json"
- }
- }
- }
- },
- "type": "n8n-nodes-base.httpRequest",
- "typeVersion": 4.2,
- "position": [
- 0,
- 0
- ],
- "id": "be640f98-e0e1-48ad-973f-f2676e1ba4dc",
- "name": "get_model_prices"
- },
- {
- "parameters": {
- "options": {
- "reset": false
- }
- },
- "type": "n8n-nodes-base.splitInBatches",
- "typeVersion": 3,
- "position": [
- 160,
- 660
- ],
- "id": "c68fb8bf-3280-4f4a-a23c-1d7afec7a028",
- "name": "Loop Over Items"
- },
- {
- "parameters": {
- "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nreturn $input.first().json.sub_workflows"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- -100,
- 660
- ],
- "id": "0d60033d-95a2-49db-a25b-0218da3d9739",
- "name": "Code2"
- },
- {
- "parameters": {
- "conditions": {
- "options": {
- "caseSensitive": true,
- "leftValue": "",
- "typeValidation": "strict",
- "version": 2
- },
- "conditions": [
- {
- "id": "ab2b0724-8418-4e58-b6c3-0b91ae2498da",
- "leftValue": "={{ $json.sub_workflows }}",
- "rightValue": "",
- "operator": {
- "type": "array",
- "operation": "exists",
- "singleValue": true
- }
- },
- {
- "id": "7f008679-ae34-4f6f-86ab-15f50d013607",
- "leftValue": "={{ $json.sub_workflows }}",
- "rightValue": "",
- "operator": {
- "type": "array",
- "operation": "notEmpty",
- "singleValue": true
- }
- }
- ],
- "combinator": "and"
- },
- "options": {}
- },
- "type": "n8n-nodes-base.if",
- "typeVersion": 2.2,
- "position": [
- 900,
- 1160
- ],
- "id": "055f1835-74de-4104-ba13-8ef4987c5b4b",
- "name": "If2"
- },
- {
- "parameters": {
- "jsCode": "const prices = $input.first().json\nconst aiNodes = $('has_ai_node').first().json.ai_nodes\nconst aiNodesInfo = []\nconst nodesData = $('get_execution_info').first().json.data.resultData.runData\nconst nodeWorkflowData = $('get_execution_info').first().json.workflowData.nodes\n\n\nfor(let i = 0; i < aiNodes.length; i++) {\n const aiNode = aiNodes[i]\n const nodeData = nodesData[aiNode.node_name]\n for(let y = 0; y < nodeWorkflowData.length ; y ++) {\n if(aiNode.node_name == nodeWorkflowData[y].name) {\n aiNodesInfo.push(getAiNodesInfo(aiNode, nodeWorkflowData[y], nodeData))\n }\n }\n}\n\nfunction getAiNodesInfo(node, workflowData, nodeData){\n if(node.model_used == null) {\n return {\n \"name\" : node.node_name,\n \"type\" : workflowData.type,\n \"execution_time\" : nodeData[0].executionTime\n }\n } else {\n return {\n \"name\" : node.node_name,\n \"type\" : workflowData.type,\n \"execution_time\" : nodeData[0].executionTime,\n \"ai_details\" : {\n \"model_used\" : node.model_used,\n \"completion_tokens\" : node.completion_tokens,\n \"prompt_tokens\" : node.prompt_tokens,\n \"total_tokens\" : node.total_tokens,\n \"cost_execution\" : getExecutionCost(node)\n }\n }\n }\n}\n\nfunction getExecutionCost(node){\n const completionTokens = node.completion_tokens\n const promptTokens = node.prompt_tokens\n let price = {}\n \n const model = node.model_used;\n if(model == 'deepseek-chat' || model == 'deepseek-reasoner') {\n const now = new Date($('get_execution_info').first().json.startedAt)\n const currentHour = now.getUTCHours()\n const currentMinute = now.getUTCMinutes()\n\n const totalMinutes = currentHour * 60 + currentMinute\n\n const startThreshold = 0 * 60 + 30\n const endThreshold = 16 * 60 + 30\n \n if(totalMinutes >= startThreshold && totalMinutes < endThreshold) {\n price = prices[`${model}-standard`]\n } else {\n price = prices[`${model}-discount`]\n }\n } else {\n price = prices[model];\n }\n if(price == null) {\n return 'Price not available';\n } else {\n const nodePrice = (completionTokens / 1000) * price.completion + (promptTokens / 1000) * price.prompt;\n if(nodePrice >= 0.01) {\n return `$${nodePrice.toFixed(2)}`;\n } else if(nodePrice >= 0.0001){\n return `$${nodePrice.toFixed(4)}`;\n } else {\n return `$${nodePrice.toFixed(8)}`\n } \n } \n}\n\nconst output = aiNodesInfo\n\nreturn {\n \"ai_nodes\" : output\n}"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 240,
- 0
- ],
- "id": "30fb7088-25d3-42b7-96cd-18f6942c5121",
- "name": "get_ai_nodes_info"
- },
- {
- "parameters": {
- "mode": "combine",
- "combineBy": "combineByPosition",
- "options": {}
- },
- "type": "n8n-nodes-base.merge",
- "typeVersion": 3.1,
- "position": [
- 400,
- 300
- ],
- "id": "805e4501-fc71-4eb2-98da-54e4d5114b89",
- "name": "Merge"
- },
- {
- "parameters": {
- "url": "=https://xavicascoll.app.n8n.cloud/api/v1/executions/{{ $json.execution_id }}",
- "sendQuery": true,
- "specifyQuery": "json",
- "jsonQuery": "{\n \"includeData\" : true\n}",
- "sendHeaders": true,
- "specifyHeaders": "json",
- "jsonHeaders": "{\n \"X-N8N-API-KEY\" : \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiYzAyNzRkMy03YWYyLTQzZjktYTU4NS1mY2M0ODQ3NDdjYzkiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzQzODQ2NDE3LCJleHAiOjE3NDYzOTYwMDB9.7fm0EcDsC7DikCxLWPS5HYp80jPPK2RpOMpQje-7t3o\",\n \"Accept\" : \"application/json\"\n}",
- "options": {}
- },
- "type": "n8n-nodes-base.httpRequest",
- "typeVersion": 4.2,
- "position": [
- 340,
- 920
- ],
- "id": "d7be0b01-8756-495f-8fab-e638181477c8",
- "name": "HTTP Request2"
- },
- {
- "parameters": {
- "jsCode": "const input = $input.first().json;\nconst data = input.data;\nconst workflowInfo = input.workflowData;\nlet nodes = []\nlet nonAiNodes = []\nlet subworkflowNodes = []\nlet aiNodes = []\n\ngetNodesInfo(data)\n\nconst workFlowData = {\n \"nombre\" : workflowInfo.name,\n \"fecha_ejecucion\" : formatDate(input.startedAt),\n \"duracion\" : getExecutionDuration(input.startedAt, input.stoppedAt),\n \"ai_nodes\" : aiNodes,\n \"normal_nodes\" : nonAiNodes,\n \"sub_workflows\" : subworkflowNodes\n \n}\n\n\nfunction getNodesInfo(data) {\n let nodesCount = 0\n \n const object = Object.keys(data.resultData.runData);\n object.map((node) => {\n if( data.resultData.runData[node][0].executionStatus == 'success') {\n nodesCount += 1;\n nodes.push(node)\n \n }\n })\n\n for (let i = 0; i < nodes.length; i++) {\n const element = nodes[i];\n \n getTypeNode(element)\n \n }\n}\n\nfunction getTypeNode(node){\n for (let index = 0; index < $input.first().json.workflowData.nodes.length; index++) {\n const element = $input.first().json.workflowData.nodes[index];\n if(element.name == node) {\n if(element.type.includes('lmChat')) {\n // AI Node\n const nodeTokenInfo = $input.first().json.data.resultData.runData[element.name][0].data.ai_languageModel[0][0].json.tokenUsage\n const modelUsed = $input.first().json.data.resultData.runData[element.name][0].inputOverride.ai_languageModel[0][0].json.options.model\n aiNodes.push({\n \"node_name\" : node,\n \"model_used\" : modelUsed,\n \"completion_tokens\" : nodeTokenInfo.completionTokens,\n \"prompt_tokens\" : nodeTokenInfo.promptTokens,\n \"total_tokens\" : nodeTokenInfo.totalTokens\n })\n } else if( element.type.includes('agent')) {\n aiNodes.push({\n \"node_name\" : node,\n \"executionTime\" : $input.first().json.data.resultData.runData[element.name][0].executionTime\n })\n } \n \n else if(element.type.includes('toolWorkflow') || element.type.includes('executeWorkflow') && !element.type.includes('executeWorkflowTrigger')) {\n let nodeObject = {}\n const runDataNode = $input.first().json.data.resultData.runData[element.name][0].metadata.subExecution\n nodeObject[\"nombre\"] = node\n nodeObject[\"execution_id\"] = runDataNode.executionId\n nodeObject[\"workflow_id\"] = runDataNode.workflowId\n subworkflowNodes.push(nodeObject)\n } else if(element.type.includes('executeWorkflowTrigger')){\n break\n }\n else {\n // Non AI Workflow\n nonAiNodes.push(node)\n }\n } \n }\n\n}\n\nfunction formatDate(date){\n const dateO = new Date(date);\n\n const day = String(dateO.getUTCDate()).padStart(2, '0');\n const month = String(dateO.getUTCMonth() + 1).padStart(2, '0');\n const year = dateO.getUTCFullYear();\n\n const hours = String(dateO.getUTCHours()).padStart(2, '0');\n const minutes = String(dateO.getUTCMinutes()).padStart(2, '0');\n const seconds = String(dateO.getUTCSeconds()).padStart(2, '0');\n\n return `${day}/${month}/${year} - ${hours}:${minutes}:${seconds}`;\n}\nfunction getExecutionDuration(started, ended) {\n const startDate = new Date(started)\n const endDate = new Date(ended)\n const durationMS = endDate - startDate\n return durationMS / 1000;\n}\n\n\nreturn workFlowData\n\n"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 540,
- 920
- ],
- "id": "bb4340ad-74a6-457f-b578-5623eeda9897",
- "name": "Code5"
- },
- {
- "parameters": {},
- "type": "n8n-nodes-base.merge",
- "typeVersion": 3.1,
- "position": [
- 880,
- 320
- ],
- "id": "94f9af63-3c65-4b72-bb77-03bdf19aca38",
- "name": "Merge2"
- },
- {
- "parameters": {
- "conditions": {
- "options": {
- "caseSensitive": true,
- "leftValue": "",
- "typeValidation": "strict",
- "version": 2
- },
- "conditions": [
- {
- "id": "a8e9a937-7e5b-4145-aabe-71c7077045bd",
- "leftValue": "={{ $json.ai_nodes[0] }}",
- "rightValue": "",
- "operator": {
- "type": "object",
- "operation": "exists",
- "singleValue": true
- }
- },
- {
- "id": "98db7a1a-3af3-465a-813d-1a17416b02c3",
- "leftValue": "={{ $json.ai_nodes[0] }}",
- "rightValue": "",
- "operator": {
- "type": "object",
- "operation": "notEmpty",
- "singleValue": true
- }
- }
- ],
- "combinator": "and"
- },
- "options": {}
- },
- "type": "n8n-nodes-base.if",
- "typeVersion": 2.2,
- "position": [
- 700,
- 760
- ],
- "id": "d92efab1-d565-4ee6-8649-c90b1dba1df3",
- "name": "If3"
- },
- {
- "parameters": {
- "jsCode": "const normal_nodes = $input.first().json.normal_nodes\nconst nodes_runData = $('HTTP Request2').first().json.data.resultData.runData\nconst workflowData = $('HTTP Request2').first().json.workflowData.nodes\nconst executedNodes = []\nconst nonAiNodes = []\ngetExecutedNodesWorkFlowData()\nfunction getExecutedNodesWorkFlowData(){\n for(let y = 0; y < normal_nodes.length ; y ++) {\n const nodeName = normal_nodes[y]\n const workflowDataNode = workflowData.find((element, index) => element.name == nodeName)\n let runDataNode = {}\n for(const key in nodes_runData) {\n if (key === nodeName) {\n runDataNode = nodes_runData[key][0]\n break\n }\n }\n nonAiNodes.push({\n \"name\" : nodeName,\n \"type\" : workflowDataNode.type,\n \"execution_time\" : runDataNode.executionTime\n })\n } \n}\n\n\nreturn {\n \"non_ai_nodes\" : nonAiNodes\n}"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 900,
- 920
- ],
- "id": "68b31f5f-c55f-4d84-81af-77266103a95d",
- "name": "Code3"
- },
- {
- "parameters": {
- "url": "https://raw.githubusercontent.com/Xavi1995/models_pricing/refs/heads/main/prices",
- "options": {
- "response": {
- "response": {
- "responseFormat": "json"
- }
- }
- }
- },
- "type": "n8n-nodes-base.httpRequest",
- "typeVersion": 4.2,
- "position": [
- 1020,
- 740
- ],
- "id": "230ce152-ff64-4a37-ad69-407efa3125e0",
- "name": "get_model_prices1"
- },
- {
- "parameters": {
- "jsCode": "const prices = $input.first().json\nconst aiNodes = $('If3').first().json.ai_nodes\nconst aiNodesInfo = []\nconst nodesData = $('HTTP Request2').first().json.data.resultData.runData\nconst nodeWorkflowData = $('HTTP Request2').first().json.workflowData.nodes\n\n\nfor(let i = 0; i < aiNodes.length; i++) {\n const aiNode = aiNodes[i]\n const nodeData = nodesData[aiNode.node_name]\n for(let y = 0; y < nodeWorkflowData.length ; y ++) {\n if(aiNode.node_name == nodeWorkflowData[y].name) {\n aiNodesInfo.push(getAiNodesInfo(aiNode, nodeWorkflowData[y], nodeData))\n }\n }\n}\n\nfunction getAiNodesInfo(node, workflowData, nodeData){\n if(node.model_used == null) {\n return {\n \"name\" : node.node_name,\n \"type\" : workflowData.type,\n \"execution_time\" : nodeData[0].executionTime\n }\n } else {\n return {\n \"name\" : node.node_name,\n \"type\" : workflowData.type,\n \"execution_time\" : nodeData[0].executionTime,\n \"ai_details\" : {\n \"model_used\" : node.model_used,\n \"completion_tokens\" : node.completion_tokens,\n \"prompt_tokens\" : node.prompt_tokens,\n \"total_tokens\" : node.total_tokens,\n \"cost_execution\" : getExecutionCost(node)\n }\n }\n }\n}\n\nfunction getExecutionCost(node){\n const completionTokens = node.completion_tokens\n const promptTokens = node.prompt_tokens\n let price = {}\n \n const model = node.model_used;\n if(model == 'deepseek-chat' || model == 'deepseek-reasoner') {\n const now = new Date($('get_execution_info').first().json.startedAt)\n const currentHour = now.getUTCHours()\n const currentMinute = now.getUTCMinutes()\n\n const totalMinutes = currentHour * 60 + currentMinute\n\n const startThreshold = 0 * 60 + 30\n const endThreshold = 16 * 60 + 30\n \n if(totalMinutes >= startThreshold && totalMinutes < endThreshold) {\n price = prices[`${model}-standard`]\n } else {\n price = prices[`${model}-discount`]\n }\n } else {\n price = prices[model];\n }\n const nodePrice = (completionTokens / 1000) * price.completion + (promptTokens / 1000) * price.prompt;\n if(nodePrice >= 0.01) {\n return `$${nodePrice.toFixed(2)}`;\n } else if(nodePrice >= 0.0001){\n return `$${nodePrice.toFixed(4)}`;\n } else {\n return `$${nodePrice.toFixed(8)}`\n }\n \n \n}\n\nconst output = aiNodesInfo\n\nreturn {\n \"ai_nodes\" : output\n}"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 1280,
- 740
- ],
- "id": "e05f8040-41b6-4bff-b7db-83cbafc4a856",
- "name": "get_ai_nodes_info1"
- },
- {
- "parameters": {
- "mode": "combine",
- "combineBy": "combineByPosition",
- "options": {
- "includeUnpaired": true
- }
- },
- "type": "n8n-nodes-base.merge",
- "typeVersion": 3.1,
- "position": [
- 1500,
- 900
- ],
- "id": "de73497a-cc00-41ff-97be-3a88ff013287",
- "name": "Merge1",
- "alwaysOutputData": true
- },
- {
- "parameters": {
- "jsCode": "const input = $input.first().json\nconst output = {}\n\noutput[\"workflow_name\"] = $('Code5').first().json.nombre\noutput[\"workflow_id\"] = $('HTTP Request2').first().json.workflowId\noutput[\"execution_id\"] = $('HTTP Request2').first().json.id\noutput[\"finished\"] = $('HTTP Request2').first().json.finished\noutput[\"execution_status\"] = $('HTTP Request2').first().json.status\noutput[\"execution_date\"] = $('Code5').first().json.fecha_ejecucion\noutput[\"execution_duration\"] = $('Code5').first().json.duracion\nif($input.first().json.ai_nodes != null) {\n output[\"total_cost\"] = getTotalCost($input.first().json.ai_nodes)\n}\noutput[\"nodes\"] = input\n\nfunction getTotalCost(aiNodes) {\n let totalCost = 0.0\n for(let i=0 ; i < aiNodes.length; i++) {\n const aiNode = aiNodes[i]\n\n if(aiNode.ai_details != null) {\n let aiNodeCost\n aiNodeCost = aiNode.ai_details.cost_execution.replace('$', '')\n totalCost += parseFloat(aiNodeCost)\n }\n }\n\n return totalCost\n}\n\nreturn output"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 1680,
- 900
- ],
- "id": "7334d5de-5bd8-44c7-a44e-e447c149f4f6",
- "name": "Code6"
- },
- {
- "parameters": {
- "aggregate": "aggregateAllItemData",
- "destinationFieldName": "",
- "options": {}
- },
- "type": "n8n-nodes-base.aggregate",
- "typeVersion": 1,
- "position": [
- 360,
- 500
- ],
- "id": "3304ef9b-8b59-4542-b37d-1b58ebf1cf63",
- "name": "Aggregate"
- },
- {
- "parameters": {
- "jsCode": "const input = $input.first().json;\nconst data = input.data;\nconst workflowInfo = input.workflowData;\nlet nodes = []\nlet nonAiNodes = []\nlet subworkflowNodes = []\nlet aiNodes = []\n\ngetNodesInfo(data)\n\nconst workFlowData = {\n \"nombre\" : workflowInfo.name,\n \"fecha_ejecucion\" : formatDate(input.startedAt),\n \"duracion\" : getExecutionDuration(input.startedAt, input.stoppedAt),\n \"ai_nodes\" : aiNodes,\n \"normal_nodes\" : nonAiNodes,\n \"sub_workflows\" : subworkflowNodes\n \n}\n\n\nfunction getNodesInfo(data) {\n let nodesCount = 0\n \n const object = Object.keys(data.resultData.runData);\n object.map((node) => {\n if( data.resultData.runData[node][0].executionStatus == 'success') {\n nodesCount += 1;\n nodes.push(node)\n \n }\n })\n\n for (let i = 0; i < nodes.length; i++) {\n const element = nodes[i];\n \n getTypeNode(element)\n \n }\n}\n\nfunction getTypeNode(node){\n for (let index = 0; index < $input.first().json.workflowData.nodes.length; index++) {\n const element = $input.first().json.workflowData.nodes[index];\n if(element.name == node) {\n \n if(element.type.includes('lmChat')) {\n var nodeTokenInfo\n var modelUsed\n // AI Node\n if(element.type.includes('Gemini') || element.type.includes('gemini')) {\n nodeTokenInfo = $input.first().json.data.resultData.runData[element.name][0].data.ai_languageModel[0][0].json.tokenUsageEstimate\n modelUsed = $input.first().json.data.resultData.runData[element.name][0].inputOverride.ai_languageModel[0][0].json.options.model_name\n } else {\n modelUsed = $input.first().json.data.resultData.runData[element.name][0].inputOverride.ai_languageModel[0][0].json.options.model\n nodeTokenInfo = $input.first().json.data.resultData.runData[element.name][0].data.ai_languageModel[0][0].json.tokenUsage\n }\n \n aiNodes.push({\n \"node_name\" : node,\n \"model_used\" : modelUsed,\n \"completion_tokens\" : nodeTokenInfo.completionTokens,\n \"prompt_tokens\" : nodeTokenInfo.promptTokens,\n \"total_tokens\" : nodeTokenInfo.totalTokens\n })\n } else if( element.type.includes('agent')) {\n aiNodes.push({\n \"node_name\" : node,\n \"executionTime\" : $input.first().json.data.resultData.runData[element.name][0].executionTime\n })\n } \n \n else if(element.type.includes('toolWorkflow') || element.type.includes('executeWorkflow')&& !element.type.includes('executeWorkflowTrigger')) {\n let nodeObject = {}\n const runDataNode = $input.first().json.data.resultData.runData[element.name][0].metadata.subExecution\n nodeObject[\"nombre\"] = node\n nodeObject[\"execution_id\"] = runDataNode.executionId\n nodeObject[\"workflow_id\"] = runDataNode.workflowId\n subworkflowNodes.push(nodeObject)\n } \n else {\n // Non AI Workflow\n nonAiNodes.push(node)\n }\n } \n }\n\n}\n\nfunction formatDate(date){\n const dateO = new Date(date);\n\n const day = String(dateO.getUTCDate()).padStart(2, '0');\n const month = String(dateO.getUTCMonth() + 1).padStart(2, '0');\n const year = dateO.getUTCFullYear();\n\n const hours = String(dateO.getUTCHours()).padStart(2, '0');\n const minutes = String(dateO.getUTCMinutes()).padStart(2, '0');\n const seconds = String(dateO.getUTCSeconds()).padStart(2, '0');\n\n return `${day}/${month}/${year} - ${hours}:${minutes}:${seconds}`;\n}\nfunction getExecutionDuration(started, ended) {\n const startDate = new Date(started)\n const endDate = new Date(ended)\n const durationMS = endDate - startDate\n return durationMS / 1000;\n}\n\n\nreturn workFlowData\n\n"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- -560,
- 320
- ],
- "id": "f0f66afb-f63f-4aa0-8b52-261dd8445a87",
- "name": "node_by_type"
- },
- {
- "parameters": {
- "conditions": {
- "options": {
- "caseSensitive": true,
- "leftValue": "",
- "typeValidation": "strict",
- "version": 2
- },
- "conditions": [
- {
- "id": "a8e9a937-7e5b-4145-aabe-71c7077045bd",
- "leftValue": "={{ $json.ai_nodes[0] }}",
- "rightValue": "",
- "operator": {
- "type": "object",
- "operation": "exists",
- "singleValue": true
- }
- },
- {
- "id": "98db7a1a-3af3-465a-813d-1a17416b02c3",
- "leftValue": "={{ $json.ai_nodes[0] }}",
- "rightValue": "",
- "operator": {
- "type": "object",
- "operation": "notEmpty",
- "singleValue": true
- }
- }
- ],
- "combinator": "and"
- },
- "options": {}
- },
- "type": "n8n-nodes-base.if",
- "typeVersion": 2.2,
- "position": [
- -320,
- 20
- ],
- "id": "216f9ba8-8c89-4f51-b332-e63056011b36",
- "name": "has_ai_node"
- },
- {
- "parameters": {
- "conditions": {
- "options": {
- "caseSensitive": true,
- "leftValue": "",
- "typeValidation": "strict",
- "version": 2
- },
- "conditions": [
- {
- "id": "293cacaf-64ca-429f-a21e-548967e6f5d1",
- "leftValue": "={{ $json.sub_workflows }}",
- "rightValue": "",
- "operator": {
- "type": "array",
- "operation": "exists",
- "singleValue": true
- }
- },
- {
- "id": "7ef27dab-d33b-4107-bb8f-839b58b5d8db",
- "leftValue": "={{ $json.sub_workflows }}",
- "rightValue": "",
- "operator": {
- "type": "array",
- "operation": "notEmpty",
- "singleValue": true
- }
- }
- ],
- "combinator": "and"
- },
- "options": {}
- },
- "type": "n8n-nodes-base.if",
- "typeVersion": 2.2,
- "position": [
- -400,
- 680
- ],
- "id": "6081decd-c820-481f-85d1-ccfbfba4338d",
- "name": "has_sub_workflows"
- },
- {
- "parameters": {
- "jsCode": "const normal_nodes = $input.first().json.normal_nodes\nconst nodes_runData = $('get_execution_info').first().json.data.resultData.runData\nconst workflowData = $('get_execution_info').first().json.workflowData.nodes\nconst executedNodes = []\nconst nonAiNodes = []\ngetExecutedNodesWorkFlowData()\nfunction getExecutedNodesWorkFlowData(){\n for(let y = 0; y < normal_nodes.length ; y ++) {\n const nodeName = normal_nodes[y]\n const workflowDataNode = workflowData.find((element, index) => element.name == nodeName)\n let runDataNode = {}\n for(const key in nodes_runData) {\n if (key === nodeName) {\n runDataNode = nodes_runData[key][0]\n break\n }\n }\n nonAiNodes.push({\n \"name\" : nodeName,\n \"type\" : workflowDataNode.type,\n \"execution_time\" : runDataNode.executionTime\n })\n } \n}\n\n\nreturn {\n \"non_ai_nodes\" : nonAiNodes\n}"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 0,
- 320
- ],
- "id": "1a263f3b-d8c6-4acc-9676-dae127aca106",
- "name": "non_ai_nodes_info"
- },
- {
- "parameters": {
- "jsCode": "const input = $input.first().json\nconst output = {}\n\noutput[\"workflow_name\"] = $('node_by_type').first().json.nombre\noutput[\"workflow_id\"] = $('get_execution_info').first().json.workflowId\noutput[\"execution_id\"] = $('get_execution_info').first().json.id\noutput[\"finished\"] = $('get_execution_info').first().json.finished\noutput[\"execution_status\"] = $('get_execution_info').first().json.status\noutput[\"execution_date\"] = $('node_by_type').first().json.fecha_ejecucion\noutput[\"execution_duration\"] = $('node_by_type').first().json.duracion\nif($input.first().json.ai_nodes != null) {\n output[\"total_cost\"] = getTotalCost($input.first().json.ai_nodes)\n}\noutput[\"nodes\"] = input\n\n\n\nfunction getTotalCost(aiNodes) {\n let totalCost = 0.0\n for(let i=0 ; i < aiNodes.length; i++) {\n const aiNode = aiNodes[i]\n\n if(aiNode.ai_details != null) {\n let aiNodeCost\n aiNodeCost = aiNode.ai_details.cost_execution.replace('$', '')\n totalCost += parseFloat(aiNodeCost)\n }\n }\n\n return totalCost\n}\n\nreturn output"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 580,
- 300
- ],
- "id": "4d39d802-411b-4a90-bf64-f8b8e9970d8a",
- "name": "clean_data"
- },
- {
- "parameters": {
- "jsCode": "const input = $input\nconst output = input.first().json\nconst subworkflows = input.last().json\n\nfor(const key in output) {\n if(key == \"sub_workflows\") {\n var sub_workflows = $input.first().json\n output[\"sub_workflows\"] = sub_workflows \n }\n}\n\noutput[\"total_cost\"] = getTotalWorkflowCost()\noutput[\"sub_workflows\"] = getSubWorkflows()\n\nfunction getSubWorkflows(){\n if($input.all().length > 1) {\n return $input.last().json\n } \n}\n \n\nfunction getTotalWorkflowCost(){\n let totalCost = 0.0\n let sub_workflow_total_cost = 0.0\n \n \n if(sub_workflows != null) {\n for(let i = 0; i < sub_workflows[\"\"].length ; i++) {\n const subWorkflow = sub_workflows[\"\"][i]\n if(subWorkflow.total_cost != null) {\n sub_workflow_total_cost += subWorkflow.total_cost \n }\n }\n }\n if(output.total_cost != null) {\n totalCost = output.total_cost\n }\n \n if(totalCost >= 0.01) {\n return `$${totalCost.toFixed(2)}`;\n } else if(totalCost >= 0.0001){\n return `$${totalCost.toFixed(4)}`;\n } else {\n return `$${totalCost.toFixed(8)}`\n }\n\n \n}\nreturn output\n"
- },
- "type": "n8n-nodes-base.code",
- "typeVersion": 2,
- "position": [
- 1120,
- 320
- ],
- "id": "3bae76ca-1445-495a-abc1-aa95860c99da",
- "name": "output_json"
- },
- {
- "parameters": {
- "operation": "toJson",
- "options": {}
- },
- "type": "n8n-nodes-base.convertToFile",
- "typeVersion": 1.1,
- "position": [
- 1340,
- 320
- ],
- "id": "5df5608e-de55-4186-a225-2d4cfeb37ab5",
- "name": "get_json_file"
- },
- {
- "parameters": {
- "resource": "execution",
- "operation": "get",
- "executionId": "={{ $json['Execution ID'] }}",
- "options": {
- "activeWorkflows": true
- },
- "requestOptions": {}
- },
- "type": "n8n-nodes-base.n8n",
- "typeVersion": 1,
- "position": [
- -740,
- 320
- ],
- "id": "54fcefa2-7b0c-4897-8231-09b6cdf55827",
- "name": "get_execution_info",
- "credentials": {
- "n8nApi": {
- "id": "7ZkDCy01RhiM5MZT",
- "name": "n8n account"
- }
- }
- },
- {
- "parameters": {
- "command": "cd /tmp\npython3 /tmp/report_generator_script.py /tmp/file.json\n"
- },
- "type": "n8n-nodes-base.executeCommand",
- "typeVersion": 1,
- "position": [
- 1760,
- 320
- ],
- "id": "a7512663-e773-4be7-b44b-361c3a5695ff",
- "name": "Execute Command"
- },
- {
- "parameters": {
- "operation": "write",
- "fileName": "=/tmp/file.json",
- "options": {
- "append": false
- }
- },
- "type": "n8n-nodes-base.readWriteFile",
- "typeVersion": 1,
- "position": [
- 1540,
- 320
- ],
- "id": "e474265f-21e0-4af3-bfa9-95e8017d2734",
- "name": "Write Files to Disk"
- },
- {
- "parameters": {
- "formTitle": "Workflow Auditor",
- "formDescription": "Enter a workflow execution ID to get a report.",
- "formFields": {
- "values": [
- {
- "fieldLabel": "Execution ID",
- "fieldType": "number",
- "placeholder": "12345",
- "requiredField": true
- }
- ]
- },
- "options": {
- "path": "beepboop"
- }
- },
- "type": "n8n-nodes-base.formTrigger",
- "typeVersion": 2.2,
- "position": [
- -960,
- 320
- ],
- "id": "683f70d6-9edc-44da-b2ed-1d80625f78d0",
- "name": "On form submission",
- "webhookId": "6ad3c538-ac7e-486e-8f74-b7849f44ed33"
- },
- {
- "parameters": {
- "operation": "completion",
- "respondWith": "returnBinary",
- "completionTitle": "Done",
- "completionMessage": "done",
- "options": {}
- },
- "type": "n8n-nodes-base.form",
- "typeVersion": 1,
- "position": [
- 2200,
- 320
- ],
- "id": "61e272c7-4594-470e-89a9-2588af8d2ac2",
- "name": "Form",
- "webhookId": "b526c67c-32ef-488c-b99a-479d755f2595"
- },
- {
- "parameters": {
- "fileSelector": "/tmp/workflow_report.pdf",
- "options": {}
- },
- "type": "n8n-nodes-base.readWriteFile",
- "typeVersion": 1,
- "position": [
- 1980,
- 320
- ],
- "id": "05d1e123-6ea9-40e9-b449-dc0765064d29",
- "name": "Read Report from Disk"
- }
- ],
- "connections": {
- "get_model_prices": {
- "main": [
- [
- {
- "node": "get_ai_nodes_info",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Loop Over Items": {
- "main": [
- [
- {
- "node": "Aggregate",
- "type": "main",
- "index": 0
- }
- ],
- [
- {
- "node": "HTTP Request2",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Code2": {
- "main": [
- [
- {
- "node": "Loop Over Items",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "get_ai_nodes_info": {
- "main": [
- [
- {
- "node": "Merge",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Merge": {
- "main": [
- [
- {
- "node": "clean_data",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "HTTP Request2": {
- "main": [
- [
- {
- "node": "Code5",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Code5": {
- "main": [
- [
- {
- "node": "If2",
- "type": "main",
- "index": 0
- },
- {
- "node": "If3",
- "type": "main",
- "index": 0
- },
- {
- "node": "Code3",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Merge2": {
- "main": [
- [
- {
- "node": "output_json",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "If3": {
- "main": [
- [
- {
- "node": "get_model_prices1",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Code3": {
- "main": [
- [
- {
- "node": "Merge1",
- "type": "main",
- "index": 1
- }
- ]
- ]
- },
- "get_model_prices1": {
- "main": [
- [
- {
- "node": "get_ai_nodes_info1",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "get_ai_nodes_info1": {
- "main": [
- [
- {
- "node": "Merge1",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Merge1": {
- "main": [
- [
- {
- "node": "Code6",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Code6": {
- "main": [
- [
- {
- "node": "Loop Over Items",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Aggregate": {
- "main": [
- [
- {
- "node": "Merge2",
- "type": "main",
- "index": 1
- }
- ]
- ]
- },
- "node_by_type": {
- "main": [
- [
- {
- "node": "has_ai_node",
- "type": "main",
- "index": 0
- },
- {
- "node": "non_ai_nodes_info",
- "type": "main",
- "index": 0
- },
- {
- "node": "has_sub_workflows",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "has_ai_node": {
- "main": [
- [
- {
- "node": "get_model_prices",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "has_sub_workflows": {
- "main": [
- [
- {
- "node": "Code2",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "non_ai_nodes_info": {
- "main": [
- [
- {
- "node": "Merge",
- "type": "main",
- "index": 1
- }
- ]
- ]
- },
- "clean_data": {
- "main": [
- [
- {
- "node": "Merge2",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "output_json": {
- "main": [
- [
- {
- "node": "get_json_file",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "get_json_file": {
- "main": [
- [
- {
- "node": "Write Files to Disk",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "get_execution_info": {
- "main": [
- [
- {
- "node": "node_by_type",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Execute Command": {
- "main": [
- [
- {
- "node": "Read Report from Disk",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Write Files to Disk": {
- "main": [
- [
- {
- "node": "Execute Command",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "On form submission": {
- "main": [
- [
- {
- "node": "get_execution_info",
- "type": "main",
- "index": 0
- }
- ]
- ]
- },
- "Read Report from Disk": {
- "main": [
- [
- {
- "node": "Form",
- "type": "main",
- "index": 0
- }
- ]
- ]
- }
- },
- "pinData": {},
- "meta": {
- "templateCredsSetupCompleted": true,
- "instanceId": "244bb51ba30d6d9051ed76fcc82ed11719af55cd3f23b418fae148137cfe5048"
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment