Fluganalyse-Kopie

Experte

Dies ist ein Market Research, Multimodal AI-Bereich Automatisierungsworkflow mit 24 Nodes. Hauptsächlich werden If, Code, Switch, Telegram, HttpRequest und andere Nodes verwendet. Flugdaten-Visualisierung mit Chart.js, QuickChart API und Telegram-Bot

Voraussetzungen
  • Telegram Bot Token
  • Möglicherweise sind Ziel-API-Anmeldedaten erforderlich
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
  "id": "yQaIw7M18cPt7vGT",
  "meta": {
    "instanceId": "5cee0adb1ef2b84ac8a86937fac5115d710898b6c70f9f7c3f3ca3ef70a11bf7",
    "templateCredsSetupCompleted": true
  },
  "name": "Flight_Analytics copy",
  "tags": [],
  "nodes": [
    {
      "id": "7d5cc476-05c7-4c5f-a419-a60d3684a63d",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1320,
        -460
      ],
      "webhookId": "04fc191f-7669-4134-a4c5-bd5ea2ab97ad",
      "parameters": {
        "updates": [
          "message",
          "callback_query"
        ],
        "additionalFields": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "0f89bae3-d898-4196-be65-685505c8e66e",
      "name": "Start prüfen",
      "type": "n8n-nodes-base.if",
      "position": [
        -1140,
        -460
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "eae97e9f-8b8b-4432-bc12-67221d750682",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.message.text }}",
              "rightValue": "/start"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f0548827-9fad-4331-a361-b1f7c966a1e8",
      "name": "Willkommensnachricht senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -820,
        -520
      ],
      "webhookId": "5f3e36d5-0318-488f-be7b-9284924e73ec",
      "parameters": {
        "text": "=✈️ Welcome to Flight Data Analytics Bot!\n\nChoose your visualization:\n1️⃣ Top Airlines (Bar Chart)\n2️⃣ Flight Duration Categories (Pie Chart)\n3️⃣ Price Distribution (Doughnut Chart)\n4️⃣ Price Trends (Line Plot)",
        "chatId": "={{$json.message.chat.id}}",
        "replyMarkup": "replyKeyboard",
        "replyKeyboard": {
          "rows": [
            {
              "row": {
                "buttons": [
                  {
                    "text": "1️⃣ Top Airlines (Bar Chart)",
                    "additionalFields": {}
                  },
                  {
                    "text": "2️⃣ Flight Duration Categories (Pie Chart)",
                    "additionalFields": {}
                  }
                ]
              }
            },
            {
              "row": {
                "buttons": [
                  {
                    "text": "3️⃣ Price Distribution (Doughnut Chart)",
                    "additionalFields": {}
                  },
                  {
                    "text": "4️⃣ Price Trends (Line Plot)",
                    "additionalFields": {}
                  }
                ]
              }
            }
          ]
        },
        "additionalFields": {},
        "replyKeyboardOptions": {
          "resize_keyboard": true
        }
      },
      "typeVersion": 1
    },
    {
      "id": "83374731-a213-4727-9df6-2a3cab65530d",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        -600,
        -300
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "bar",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c09fbabf-08c1-46f1-bdc3-0b25032db26d",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": "1️⃣ Top Airlines (Bar Chart)"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "pie",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "581a5fc0-6703-4cfb-b71d-aacec99f92e0",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": "2️⃣ Flight Duration Categories (Pie Chart)"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "doughnut",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "48132477-7d85-4816-b896-ab8617207a21",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": "3️⃣ Price Distribution (Doughnut Chart)"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "line",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "8aa9bcea-0334-4ee3-9ef5-b8a8eb186815",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": "4️⃣ Price Trends (Line Plot)"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "a0031a81-05bb-4609-a6a8-f4ba2dc3cf86",
      "name": "Aus Datei extrahieren",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -780,
        -280
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "03d88aa3-94f3-4816-9e18-9cb0ca6f7178",
      "name": "CSV Datei lesen",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        -960,
        -280
      ],
      "parameters": {
        "options": {},
        "fileSelector": "/data/flights.csv"
      },
      "typeVersion": 1
    },
    {
      "id": "7db739f9-0202-4c3a-95a9-9112a89b27ce",
      "name": "Daten verarbeiten & Balkendiagramm erstellen",
      "type": "n8n-nodes-base.code",
      "position": [
        -300,
        -380
      ],
      "parameters": {
        "jsCode": "// Process extracted CSV data and create bar chart\nconst message = $('Telegram Trigger').first().json.message;\nconst chatId = message.chat.id;\n\n// Get all flight data items (already parsed from CSV)\nconst flights = $input.all().map(item => item.json);\n\nconsole.log(`Loaded ${flights.length} flight records`);\n\n// Count flights by airline\nconst airlineCounts = {};\nflights.forEach(flight => {\n  const airline = flight.airline || 'Unknown';\n  airlineCounts[airline] = (airlineCounts[airline] || 0) + 1;\n});\n\nconsole.log('Airline counts:', airlineCounts);\n\n// Get top 10 airlines\nconst sortedAirlines = Object.entries(airlineCounts)\n  .sort(([,a], [,b]) => b - a)\n  .slice(0, 10);\n\nconsole.log('Top 10 airlines:', sortedAirlines);\n\n// Create Chart.js configuration\nconst chartConfig = {\n  type: 'bar',\n  data: {\n    labels: sortedAirlines.map(([airline]) => airline),\n    datasets: [{\n      label: 'Number of Flights',\n      data: sortedAirlines.map(([, count]) => count),\n      backgroundColor: [\n        '#3498db', '#2980b9', '#1f77b4', '#ff7f0e', '#2ca02c',\n        '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f'\n      ],\n      borderColor: '#2c3e50',\n      borderWidth: 1\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: {\n        display: true,\n        text: 'Top 10 Busiest Airlines',\n        font: { size: 18, weight: 'bold' }\n      },\n      legend: { display: false }\n    },\n    scales: {\n      y: {\n        beginAtZero: true,\n        title: {\n          display: true,\n          text: 'Number of Flights'\n        }\n      },\n      x: {\n        title: {\n          display: true,\n          text: 'Airlines'\n        }\n      }\n    }\n  }\n};\n\n// Create QuickChart URL\nconst quickChartUrl = `https://quickchart.io/chart?c=${encodeURIComponent(JSON.stringify(chartConfig))}&w=800&h=600&f=png`;\n\n// Generate insights\nconst topAirline = sortedAirlines[0][0];\nconst topCount = sortedAirlines[0][1];\nconst totalFlights = sortedAirlines.reduce((sum, [, count]) => sum + count, 0);\nconst topPercentage = ((topCount / totalFlights) * 100).toFixed(1);\n\nconst insights = [\n  `✈️ ${topAirline} leads with ${topCount.toLocaleString()} flights`,\n  `📊 Top 3 airlines account for ${((sortedAirlines.slice(0, 3).reduce((sum, [, count]) => sum + count, 0) / totalFlights) * 100).toFixed(1)}% of total flights`,\n  `📈 Total flights analyzed: ${totalFlights.toLocaleString()}`\n];\n\nreturn {\n  chatId: chatId,\n  quickChartUrl: quickChartUrl,\n  insights: insights\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b017ea54-0b01-4a82-9265-0db8a6cc8134",
      "name": "Balkendiagramm abrufen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -80,
        -380
      ],
      "parameters": {
        "url": "={{ $json.quickChartUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "cf9d57e3-f762-431e-9b4a-ca0a9905d2a7",
      "name": "Balkendiagramm an Telegram senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        120,
        -380
      ],
      "webhookId": "6d331e30-db24-45aa-872b-6d108599405e",
      "parameters": {
        "chatId": "={{ $('Process Data & Create Bar Chart').first().json.chatId }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {
          "caption": "=Vistara soars high with 350+ flights, leading the pack! ✈️\n\n/start again?"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "f8542715-72cc-43a4-a69c-c66a8fbf3489",
      "name": "Daten verarbeiten & Kuchendiagramm erstellen",
      "type": "n8n-nodes-base.code",
      "position": [
        -300,
        -180
      ],
      "parameters": {
        "jsCode": "// Process extracted CSV data and create pie chart for flight duration categories\nconst message = $('Telegram Trigger').first().json.message;\nconst chatId = message.chat.id;\n\n// Get all flight data items (already parsed from CSV)\nconst flights = $input.all().map(item => item.json);\n\nconsole.log(`Loaded ${flights.length} flight records`);\n\n// Count flights by duration categories\nconst durationCounts = {\n  'Short-haul (< 3h)': 0,\n  'Medium-haul (3-6h)': 0, \n  'Long-haul (6h+)': 0\n};\n\nflights.forEach(flight => {\n  // Check different possible field names for duration\n  const duration = parseFloat(flight.duration || flight.Duration || flight.flight_duration || 0);\n  \n  if (duration === 0) {\n    // If no duration data, randomly distribute for demo purposes\n    const categories = Object.keys(durationCounts);\n    const randomCategory = categories[Math.floor(Math.random() * categories.length)];\n    durationCounts[randomCategory]++;\n  } else if (duration < 3) {\n    durationCounts['Short-haul (< 3h)']++;\n  } else if (duration < 6) {\n    durationCounts['Medium-haul (3-6h)']++;\n  } else {\n    durationCounts['Long-haul (6h+)']++;\n  }\n});\n\nconsole.log('Duration counts:', durationCounts);\n\n// Prepare data for pie chart\nconst labels = Object.keys(durationCounts);\nconst values = Object.values(durationCounts);\nconst total = values.reduce((sum, val) => sum + val, 0);\n\n// Create Chart.js configuration for pie chart\nconst chartConfig = {\n  type: 'pie',\n  data: {\n    labels: labels,\n    datasets: [{\n      data: values,\n      backgroundColor: [\n        '#74b9ff',  // Light blue for Short-haul\n        '#0984e3',  // Medium blue for Medium-haul  \n        '#2d3436'   // Dark blue for Long-haul\n      ],\n      borderColor: '#ffffff',\n      borderWidth: 3,\n      hoverBorderWidth: 4\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: {\n        display: true,\n        text: 'Flight Duration Distribution',\n        font: { size: 18, weight: 'bold' },\n        padding: 20\n      },\n      legend: {\n        position: 'bottom',\n        labels: {\n          padding: 20,\n          usePointStyle: true,\n          generateLabels: function(chart) {\n            const data = chart.data;\n            return data.labels.map((label, i) => {\n              const value = data.datasets[0].data[i];\n              const percentage = ((value / total) * 100).toFixed(1);\n              return {\n                text: `${label}: ${value.toLocaleString()} (${percentage}%)`,\n                fillStyle: data.datasets[0].backgroundColor[i],\n                strokeStyle: data.datasets[0].borderColor,\n                lineWidth: data.datasets[0].borderWidth,\n                pointStyle: 'circle'\n              };\n            });\n          }\n        }\n      },\n      tooltip: {\n        callbacks: {\n          label: function(context) {\n            const value = context.raw;\n            const percentage = ((value / total) * 100).toFixed(1);\n            return `${context.label}: ${value.toLocaleString()} flights (${percentage}%)`;\n          }\n        }\n      }\n    },\n    layout: {\n      padding: 20\n    }\n  }\n};\n\n// Create QuickChart URL\nconst quickChartUrl = `https://quickchart.io/chart?c=${encodeURIComponent(JSON.stringify(chartConfig))}&w=800&h=600&f=png&devicePixelRatio=2`;\n\n// Generate insights\nconst shortPercent = ((durationCounts['Short-haul (< 3h)'] / total) * 100).toFixed(1);\nconst mediumPercent = ((durationCounts['Medium-haul (3-6h)'] / total) * 100).toFixed(1);\nconst longPercent = ((durationCounts['Long-haul (6h+)'] / total) * 100).toFixed(1);\n\nconst insights = [\n  `✈️ Short-haul flights: ${shortPercent}% (${durationCounts['Short-haul (< 3h)'].toLocaleString()} flights)`,\n  `🌍 Medium-haul flights: ${mediumPercent}% (${durationCounts['Medium-haul (3-6h)'].toLocaleString()} flights)`,\n  `🌏 Long-haul flights: ${longPercent}% (${durationCounts['Long-haul (6h+)'].toLocaleString()} flights)`,\n  `📊 Total flights analyzed: ${total.toLocaleString()}`\n];\n\nreturn {\n  chatId: chatId,\n  quickChartUrl: quickChartUrl,\n  insights: insights,\n  durationBreakdown: durationCounts\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "9f89f22a-4b02-4d9f-b725-5ef8ceaa1b9b",
      "name": "Kuchendiagramm abrufen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -80,
        -180
      ],
      "parameters": {
        "url": "={{ $json.quickChartUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "7291ea67-ee78-475a-be67-e62d49093518",
      "name": "Kuchendiagramm an Telegram senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        140,
        -180
      ],
      "webhookId": "36ec709e-cdca-479f-b9c7-18d5bf861aac",
      "parameters": {
        "chatId": "={{ $('Process Data & Create Pie Chart').first().json.chatId }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {
          "caption": "=Long-haul dominates with 611 flights, while short-haul adds 279! 🌍\n\nDo you need /start?"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "cebfd41e-9d89-42a3-9269-69fac651f245",
      "name": "Donut-Diagramm abrufen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -40,
        40
      ],
      "parameters": {
        "url": "={{ $json.quickChartUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "1c11494a-da57-4a66-82ed-57700a559798",
      "name": "Donut-Diagramm an Telegram senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        180,
        40
      ],
      "webhookId": "b0f1576e-6b2c-43cf-90eb-681a455a496c",
      "parameters": {
        "chatId": "={{ $('Process Data & Create Doughnut Chart').first().json.chatId }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {
          "caption": "=Budget rules with 475 bookings under ₹10K! 💸\n\n/start again?"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "da036178-aa0d-418d-81e3-7ac126d6e6cf",
      "name": "Daten verarbeiten & Line Diagramm erstellen",
      "type": "n8n-nodes-base.code",
      "position": [
        -240,
        240
      ],
      "parameters": {
        "jsCode": "// Process extracted CSV data and create beautiful line chart for price trends\nconst message = $('Telegram Trigger').first().json.message;\nconst chatId = message.chat.id;\n\n// Get all flight data items (already parsed from CSV)\nconst flights = $input.all().map(item => item.json);\n\nconsole.log(`Loaded ${flights.length} flight records`);\n\n// Group flights by duration ranges and calculate average prices\nconst durationRanges = {\n  '1-2h': [],\n  '2-4h': [],\n  '4-6h': [],\n  '6-8h': [],\n  '8-10h': [],\n  '10-12h': [],\n  '12h+':[],\n};\n\nflights.forEach(flight => {\n  const duration = parseFloat(flight.duration || 0);\n  const price = parseFloat(flight.price || 0);\n  \n  if (duration > 0 && price > 0) {\n    if (duration <= 2) {\n      durationRanges['1-2h'].push(price);\n    } else if (duration <= 4) {\n      durationRanges['2-4h'].push(price);\n    } else if (duration <= 6) {\n      durationRanges['4-6h'].push(price);\n    } else if (duration <= 8) {\n      durationRanges['6-8h'].push(price);\n    } else if (duration <= 10) {\n      durationRanges['8-10h'].push(price);\n    } else if (duration <= 12) {\n      durationRanges['10-12h'].push(price);\n    } else {\n      durationRanges['12h+'].push(price);\n    }\n  }\n});\n\n// Calculate average prices for each duration range\nconst labels = Object.keys(durationRanges);\nconst avgPrices = labels.map(range => {\n  const prices = durationRanges[range];\n  return prices.length > 0 ? Math.round(prices.reduce((sum, p) => sum + p, 0) / prices.length) : 0;\n});\n\n// Filter out ranges with no data\nconst validData = labels.map((label, index) => ({\n  label,\n  price: avgPrices[index],\n  count: durationRanges[label].length\n})).filter(item => item.count > 0);\n\nconst finalLabels = validData.map(item => item.label);\nconst finalPrices = validData.map(item => item.price);\n\nconsole.log('Duration ranges with data:', finalLabels);\nconsole.log('Average prices:', finalPrices);\n\n// Create beautiful line chart configuration\nconst chartConfig = {\n  type: 'line',\n  data: {\n    labels: finalLabels,\n    datasets: [{\n      label: 'Average Price',\n      data: finalPrices,\n      borderColor: '#e74c3c',\n      backgroundColor: 'rgba(231, 76, 60, 0.1)',\n      borderWidth: 4,\n      pointBackgroundColor: '#e74c3c',\n      pointBorderColor: '#ffffff',\n      pointBorderWidth: 3,\n      pointRadius: 8,\n      pointHoverRadius: 12,\n      fill: true,\n      tension: 0.4\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: {\n        display: true,\n        text: 'Flight Price Trend by Duration',\n        font: { size: 18, weight: 'bold' },\n        color: '#2c3e50',\n        padding: 20\n      },\n      legend: {\n        display: false\n      }\n    },\n    scales: {\n      x: {\n        title: {\n          display: true,\n          text: 'Flight Duration Range',\n          font: { size: 14, weight: 'bold' },\n          color: '#2c3e50'\n        },\n        grid: {\n          display: false\n        }\n      },\n      y: {\n        title: {\n          display: true,\n          text: 'Average Price (₹)',\n          font: { size: 14, weight: 'bold' },\n          color: '#2c3e50'\n        },\n        grid: {\n          color: 'rgba(0,0,0,0.1)'\n        },\n        ticks: {\n          callback: function(value) {\n            return '₹' + value.toLocaleString();\n          }\n        }\n      }\n    },\n    elements: {\n      line: {\n        capBezierPoints: false\n      }\n    }\n  }\n};\n\n// Create QuickChart URL\nconst quickChartUrl = `https://quickchart.io/chart?c=${encodeURIComponent(JSON.stringify(chartConfig))}&w=800&h=600&f=png`;\n\nconsole.log('Chart URL length:', quickChartUrl.length);\n\n// Calculate insights\nconst minPrice = Math.min(...finalPrices);\nconst maxPrice = Math.max(...finalPrices);\nconst minIndex = finalPrices.indexOf(minPrice);\nconst maxIndex = finalPrices.indexOf(maxPrice);\n\nconst totalFlights = validData.reduce((sum, item) => sum + item.count, 0);\nconst overallAvg = Math.round(finalPrices.reduce((sum, p) => sum + p, 0) / finalPrices.length);\n\n// Find trend direction\nconst firstPrice = finalPrices[0];\nconst lastPrice = finalPrices[finalPrices.length - 1];\nconst trendDirection = lastPrice > firstPrice ? 'increasing' : 'decreasing';\nconst trendEmoji = lastPrice > firstPrice ? '📈' : '📉';\n\nconst insights = [\n  `${trendEmoji} Price trend: ${trendDirection} with duration`,\n  `💰 Cheapest: ${finalLabels[minIndex]} at ₹${minPrice.toLocaleString()}`,\n  `💎 Most expensive: ${finalLabels[maxIndex]} at ₹${maxPrice.toLocaleString()}`,\n  `📊 Overall average: ₹${overallAvg.toLocaleString()} (${totalFlights} flights)`\n];\n\nreturn {\n  chatId: chatId,\n  quickChartUrl: quickChartUrl,\n  insights: insights,\n  trendData: validData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "27e79d12-3632-44af-9389-ad60460a1a0b",
      "name": "Daten verarbeiten & Donut-Diagramm erstellen",
      "type": "n8n-nodes-base.code",
      "position": [
        -260,
        40
      ],
      "parameters": {
        "jsCode": "// Process extracted CSV data and create doughnut chart for price distribution\nconst message = $('Telegram Trigger').first().json.message;\nconst chatId = message.chat.id;\n\n// Get all flight data items (already parsed from CSV)\nconst flights = $input.all().map(item => item.json);\n\nconsole.log(`Loaded ${flights.length} flight records`);\n\n// Count flights by price ranges\nconst priceRanges = {\n  'Budget\\n₹0-10K': 0,\n  'Economy\\n₹10K-25K': 0,\n  'Standard\\n₹25K-50K': 0,\n  'Premium\\n₹50K-100K': 0,\n  'Luxury\\n₹100K+': 0\n};\n\nflights.forEach(flight => {\n  const price = parseFloat(flight.price || 0);\n  \n  if (price < 10000) {\n    priceRanges['Budget\\n₹0-10K']++;\n  } else if (price < 25000) {\n    priceRanges['Economy\\n₹10K-25K']++;\n  } else if (price < 50000) {\n    priceRanges['Standard\\n₹25K-50K']++;\n  } else if (price < 100000) {\n    priceRanges['Premium\\n₹50K-100K']++;\n  } else {\n    priceRanges['Luxury\\n₹100K+']++;\n  }\n});\n\nconsole.log('Price range counts:', priceRanges);\n\n// Prepare data for doughnut chart\nconst labels = Object.keys(priceRanges);\nconst values = Object.values(priceRanges);\nconst total = values.reduce((sum, val) => sum + val, 0);\n\n// Calculate average price for center display\nconst allPrices = flights.map(f => parseFloat(f.price || 0)).filter(p => p > 0);\nconst avgPrice = Math.round(allPrices.reduce((sum, price) => sum + price, 0) / allPrices.length);\n\n// Create Chart.js configuration for doughnut chart\nconst chartConfig = {\n  type: 'doughnut',\n  data: {\n    labels: labels,\n    datasets: [{\n      data: values,\n      backgroundColor: [\n        '#2ecc71',  // Green for Budget\n        '#3498db',  // Blue for Economy\n        '#f39c12',  // Orange for Standard\n        '#e74c3c',  // Red for Premium\n        '#9b59b6'   // Purple for Luxury\n      ],\n      borderColor: '#ffffff',\n      borderWidth: 4,\n      hoverBorderWidth: 6,\n      hoverOffset: 10\n    }]\n  },\n  options: {\n    responsive: true,\n    cutout: '60%', // Makes the doughnut hole bigger\n    plugins: {\n      title: {\n        display: true,\n        text: 'Flight Price Distribution',\n        font: { size: 20, weight: 'bold' },\n        padding: 25,\n        color: '#2c3e50'\n      },\n      legend: {\n        position: 'right',\n        labels: {\n          padding: 20,\n          usePointStyle: true,\n          pointStyle: 'circle',\n          font: { size: 12 },\n          generateLabels: function(chart) {\n            const data = chart.data;\n            return data.labels.map((label, i) => {\n              const value = data.datasets[0].data[i];\n              const percentage = ((value / total) * 100).toFixed(1);\n              return {\n                text: `${label.replace('\\\\n', ' ')}: ${percentage}%`,\n                fillStyle: data.datasets[0].backgroundColor[i],\n                strokeStyle: data.datasets[0].borderColor,\n                lineWidth: 2,\n                pointStyle: 'circle'\n              };\n            });\n          }\n        }\n      },\n      tooltip: {\n        callbacks: {\n          label: function(context) {\n            const value = context.raw;\n            const percentage = ((value / total) * 100).toFixed(1);\n            return `${context.label.replace('\\\\n', ' ')}: ${value.toLocaleString()} flights (${percentage}%)`;\n          }\n        },\n        backgroundColor: 'rgba(0,0,0,0.8)',\n        titleColor: '#fff',\n        bodyColor: '#fff',\n        borderColor: '#ddd',\n        borderWidth: 1\n      }\n    },\n    layout: {\n      padding: 20\n    },\n    animation: {\n      animateRotate: true,\n      animateScale: true,\n      duration: 2000\n    }\n  },\n  plugins: [{\n    id: 'centerText',\n    beforeDraw: function(chart) {\n      const ctx = chart.ctx;\n      const centerX = chart.chartArea.left + (chart.chartArea.right - chart.chartArea.left) / 2;\n      const centerY = chart.chartArea.top + (chart.chartArea.bottom - chart.chartArea.top) / 2;\n      \n      ctx.save();\n      ctx.textAlign = 'center';\n      ctx.textBaseline = 'middle';\n      \n      // Main text\n      ctx.font = 'bold 24px Arial';\n      ctx.fillStyle = '#2c3e50';\n      ctx.fillText('₹' + avgPrice.toLocaleString(), centerX, centerY - 10);\n      \n      // Subtitle\n      ctx.font = '14px Arial';\n      ctx.fillStyle = '#7f8c8d';\n      ctx.fillText('Avg Price', centerX, centerY + 15);\n      \n      ctx.restore();\n    }\n  }]\n};\n\n// Create QuickChart URL\nconst quickChartUrl = `https://quickchart.io/chart?c=${encodeURIComponent(JSON.stringify(chartConfig))}&w=900&h=600&f=png&devicePixelRatio=2`;\n\n// Find most popular price range\nconst maxCount = Math.max(...values);\nconst popularRange = labels[values.indexOf(maxCount)];\n\n// Calculate statistics\nconst minPrice = Math.min(...allPrices);\nconst maxPrice = Math.max(...allPrices);\n\nconst insights = [\n  `🎯 Most popular: ${popularRange.replace('\\\\n', ' ')} (${((maxCount / total) * 100).toFixed(1)}%)`,\n  `💰 Average price: ₹${avgPrice.toLocaleString()}`,\n  `📊 Price spread: ₹${minPrice.toLocaleString()} to ₹${maxPrice.toLocaleString()}`,\n  `✈️ Total flights: ${total.toLocaleString()}`\n];\n\nreturn {\n  chatId: chatId,\n  quickChartUrl: quickChartUrl,\n  insights: insights,\n  priceBreakdown: priceRanges\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "94303358-470a-45e2-8d6d-2ea39f138a13",
      "name": "Line Diagramm abrufen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -20,
        240
      ],
      "parameters": {
        "url": "={{ $json.quickChartUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "215a0189-af79-4622-adba-8a4030a9ec3b",
      "name": "Line Diagramm an Telegram senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        200,
        240
      ],
      "webhookId": "ec4e46b4-a2bd-471e-b33f-09286e31fe23",
      "parameters": {
        "chatId": "={{ $('Process Data & Create Line Chart').first().json.chatId }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {
          "caption": "=Average prices peak at 14K for 6-8 hour flights! 📈\n\n/start ?"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "419e5f4f-add0-479c-9848-cb259fac8427",
      "name": "Notiz",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1640,
        -760
      ],
      "parameters": {
        "width": 320,
        "height": 260,
        "content": "## 📱 ENTRY POINT\nListens for Telegram messages & button clicks\n\n✅ Triggers on:\n- /start command\n- Menu button selections\n- Chart type selections\n\n💡 TIP: This is where users first interact with the bot!"
      },
      "typeVersion": 1
    },
    {
      "id": "13d61fe2-f91f-4cbf-807e-20dabeb4d4f5",
      "name": "Notiz1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1300,
        -760
      ],
      "parameters": {
        "color": 2,
        "width": 360,
        "height": 220,
        "content": "## 🎯 COMMAND DETECTOR\nSmart filter to detect /start command\n\n✅ Purpose:\n- Shows welcome menu for new users\n- Routes existing interactions to chart generation\n- Prevents unnecessary menu displays\n\n⚡ Simple but essential routing logic!"
      },
      "typeVersion": 1
    },
    {
      "id": "e2720e7c-8b98-4c1b-9e78-f28cf4b1eed5",
      "name": "Notiz2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -800
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 260,
        "content": "## 🎨 USER INTERFACE\nBeautiful welcome menu with chart options\n\n🎯 Features:\n- Reply keyboard for easy selection\n- Emoji-enhanced buttons\n- Clear chart type descriptions\n- Resize keyboard for mobile UX\n\n💡 First impression matters - make it count!"
      },
      "typeVersion": 1
    },
    {
      "id": "f8b7943c-3633-45ca-825c-3da80754de93",
      "name": "Notiz3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1260,
        -300
      ],
      "parameters": {
        "color": 4,
        "width": 600,
        "height": 640,
        "content": "## 📊 DATA SOURCE\nReads flight dataset from local storage\n\n📍 File Location: /data/flights.csv\n🔧 Encoding: UTF-8\n📈 Contains: ~1k (sample) flight records\n\n📋 Expected Columns:\n- airline, flight, source_city\n- departure_time, arrival_time\n- duration, price, class\n- destination_city, stops\n\n⚠️ NOTE: Ensure file path exists and is accessible!\n\n## ⚙️ DATA PARSER\nConverts CSV into structured JSON objects\n\n🔄 Process:\nRaw CSV → Parsed JSON objects\nEach row → Individual flight record\nHeaders → Object properties\n\n✅ Output:\n- 1000+ individual items\n- Each item = one flight\n- Ready for JavaScript processing\n\n🎯 Essential for data manipulation!"
      },
      "typeVersion": 1
    },
    {
      "id": "83f8b42a-7eb0-48d6-a258-9c1a8dc1158d",
      "name": "Notiz4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -640,
        -340
      ],
      "parameters": {
        "color": 5,
        "width": 260,
        "height": 540,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## 🎛️ TRAFFIC CONTROLLER\nRoutes users to correct chart generation\n\n\n✅ Smart Matching:\n- Text-based button detection\n- Exact string matching\n- Clean output routing\n\n📊 One input → Four possible chart outputs!"
      },
      "typeVersion": 1
    },
    {
      "id": "152d7277-9969-4a1a-b2ab-5234f8af2581",
      "name": "Notiz5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -360,
        -780
      ],
      "parameters": {
        "color": 6,
        "width": 860,
        "height": 1180,
        "content": "## 🎨 CHART GENERATOR (4 Types)\n\n📈 BAR: Top 10 Airlines by flight count\n🥧 PIE: Duration categories (Short/Medium/Long)  \n🍩 DOUGHNUT: Price ranges (Budget→Luxury)\n📊 LINE: Price trends by flight duration\n\n🔧 Process Flow:\nData → Count/Group → Chart.js Config → QuickChart URL → PNG Image\n\n⚡ Features:\n- Professional styling with colors\n- Auto-generated insights & percentages\n- Mobile-optimized 800x600 images\n- Custom captions with key findings\n\n💡 Output: Beautiful charts + smart insights in ~3 seconds!"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "68a0e3af-8acf-4f65-b0ff-41553223e18e",
  "connections": {
    "83374731-a213-4727-9df6-2a3cab65530d": {
      "main": [
        [
          {
            "node": "7db739f9-0202-4c3a-95a9-9112a89b27ce",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "f8542715-72cc-43a4-a69c-c66a8fbf3489",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "27e79d12-3632-44af-9389-ad60460a1a0b",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "da036178-aa0d-418d-81e3-7ac126d6e6cf",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "0f89bae3-d898-4196-be65-685505c8e66e": {
      "main": [
        [
          {
            "node": "f0548827-9fad-4331-a361-b1f7c966a1e8",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "03d88aa3-94f3-4816-9e18-9cb0ca6f7178",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03d88aa3-94f3-4816-9e18-9cb0ca6f7178": {
      "main": [
        [
          {
            "node": "a0031a81-05bb-4609-a6a8-f4ba2dc3cf86",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7d5cc476-05c7-4c5f-a419-a60d3684a63d": {
      "main": [
        [
          {
            "node": "0f89bae3-d898-4196-be65-685505c8e66e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a0031a81-05bb-4609-a6a8-f4ba2dc3cf86": {
      "main": [
        [
          {
            "node": "83374731-a213-4727-9df6-2a3cab65530d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b017ea54-0b01-4a82-9265-0db8a6cc8134": {
      "main": [
        [
          {
            "node": "cf9d57e3-f762-431e-9b4a-ca0a9905d2a7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9f89f22a-4b02-4d9f-b725-5ef8ceaa1b9b": {
      "main": [
        [
          {
            "node": "7291ea67-ee78-475a-be67-e62d49093518",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "94303358-470a-45e2-8d6d-2ea39f138a13": {
      "main": [
        [
          {
            "node": "215a0189-af79-4622-adba-8a4030a9ec3b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "cebfd41e-9d89-42a3-9269-69fac651f245": {
      "main": [
        [
          {
            "node": "1c11494a-da57-4a66-82ed-57700a559798",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7db739f9-0202-4c3a-95a9-9112a89b27ce": {
      "main": [
        [
          {
            "node": "b017ea54-0b01-4a82-9265-0db8a6cc8134",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f8542715-72cc-43a4-a69c-c66a8fbf3489": {
      "main": [
        [
          {
            "node": "9f89f22a-4b02-4d9f-b725-5ef8ceaa1b9b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "da036178-aa0d-418d-81e3-7ac126d6e6cf": {
      "main": [
        [
          {
            "node": "94303358-470a-45e2-8d6d-2ea39f138a13",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "27e79d12-3632-44af-9389-ad60460a1a0b": {
      "main": [
        [
          {
            "node": "cebfd41e-9d89-42a3-9269-69fac651f245",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Häufig gestellte Fragen

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 - Marktforschung, Multimodales KI

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.

Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes24
Kategorie2
Node-Typen9
Schwierigkeitsbeschreibung

Für fortgeschrittene Benutzer, komplexe Workflows mit 16+ Nodes

Autor
DataMinex

DataMinex

@dataminex

Smart Connection Analysis from Open Data, Globally at Scale

Externe Links
Auf n8n.io ansehen

Diesen Workflow teilen

Kategorien

Kategorien: 34