{
  "id": "MQmMLg34LuvMsRan",
  "meta": {
    "templateId": "806",
    "templateCredsSetupCompleted": true
  },
  "name": "Weather prediction in 3 cities",
  "tags": [],
  "nodes": [
    {
      "id": "45a9c8c7-b596-4f48-baf8-09a46e4004df",
      "name": "JS - Validate JSON from LLM",
      "type": "n8n-nodes-base.code",
      "position": [
        1824,
        16
      ],
      "parameters": {
        "jsCode": "function extractRaw(o) {\n  if (typeof o === 'string') return o;\n  const m = o.message || o.messages || o;\n  if (typeof m?.content === 'string') return m.content;\n  if (Array.isArray(m?.content)) {\n    const first = m.content[0];\n    if (typeof first?.text?.value === 'string') return first.text.value;\n    if (typeof first?.text === 'string') return first.text;\n  }\n  if (Array.isArray(m)) {\n    const c = m[0]?.content;\n    if (typeof c === 'string') return c;\n    if (Array.isArray(c)) {\n      const first = c[0];\n      if (typeof first?.text?.value === 'string') return first.text.value;\n      if (typeof first?.text === 'string') return first.text;\n    }\n  }\n  return JSON.stringify(o);\n}\nfunction tryParseJSON(s) {\n  if (!s || typeof s !== 'string') return null;\n  try { return JSON.parse(s); } catch {}\n  const start = s.indexOf('{');\n  const end = s.lastIndexOf('}');\n  if (start >= 0 && end > start) {\n    const candidate = s.slice(start, end + 1);\n    try { return JSON.parse(candidate); } catch {}\n  }\n  return null;\n}\n\nconst raw = extractRaw($json);\nconst parsed = tryParseJSON(raw);\n\nif (parsed && parsed.subject && parsed.html) {\n  return [{ subject: parsed.subject, html: parsed.html, ok: true }];\n} else {\n  return [{ ok: false, reason: 'bad_json', raw }];\n}\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f837e628-3bac-4d22-afef-32ba3df0c016",
      "name": "GMAIL - Send Weather Briefing",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1712,
        352
      ],
      "parameters": {
        "sendTo": "<<user@example.com>>",
        "message": "={{ $('LLM - AI Weather Briefing Composer').item.json.message.content.html }}",
        "options": {},
        "subject": "={{ $('LLM - AI Weather Briefing Composer').item.json.message.content.subject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "b6c7d8b2-0a69-472d-b508-3453eadeea4b",
      "name": "JS - Bundle Cities for LLM",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        96
      ],
      "parameters": {
        "jsCode": "// Pack all incoming items into one payload for the LLM.\nconst cities = items.map(i => ({\n  city: i.json.city,\n  country: i.json.country,\n  summaries: i.json.summaries\n}));\nreturn [{ cities }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e4a3a918-3b48-44ba-a463-3d77786fdc9a",
      "name": "JS - Build Daily Summaries (5 days)",
      "type": "n8n-nodes-base.code",
      "position": [
        1216,
        288
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// We need to get the asked city from Pick Lat/Lon node\n// Since we can't use $items() reliably, we'll store it differently\n\n// The OpenWeatherMap response has city.name which is the API's name\n// But we need the original asked city name\n// Check if we have it in the input, otherwise fall back to API name\nconst apiCityName = $json.city?.name || 'City';\nconst apiCountry = $json.city?.country || '';\nconst tzOffset = $json.city?.timezone || 0; // seconds\nconst data = $json.list || [];\nconst units = 'metric';\n\n// Use the API city name for now - we'll fix this in the next step\nconst city = apiCityName;\nconst country = apiCountry;\n\nfunction toLocalDateStr(dt) {\n  // dt is unix seconds; shift by city timezone\n  const d = new Date((dt + tzOffset) * 1000);\n  return d.toISOString().slice(0,10); // YYYY-MM-DD\n}\n\n// Group by day\nconst days = {};\nfor (const p of data) {\n  const day = toLocalDateStr(p.dt);\n  if (!days[day]) days[day] = { points: [] };\n  days[day].points.push(p);\n}\n\n// Aggregate per day\nconst daySummaries = Object.entries(days).map(([date, obj]) => {\n  const pts = obj.points;\n\n  const temps = pts.map(p => p.main.temp);\n  const min = Math.min(...temps);\n  const max = Math.max(...temps);\n\n  // wind\n  const windMax = Math.max(...pts.map(p => (p.wind?.gust ?? p.wind?.speed ?? 0)));\n\n  // rain total (mm)\n  const rain = pts.reduce((acc, p) => acc + (p.rain?.['3h'] || 0), 0);\n\n  // pop average (precip probability 0..1)\n  const popAvg = pts.reduce((a,p)=>a+(p.pop||0),0) / (pts.length || 1);\n\n  // humidity average\n  const humAvg = pts.reduce((a,p)=>a+(p.main?.humidity||0),0) / (pts.length || 1);\n\n  // dominant condition by frequency\n  const counts = {};\n  for (const p of pts) {\n    const desc = (p.weather?.[0]?.main || 'Other');\n    counts[desc] = (counts[desc] || 0) + 1;\n  }\n  const dominant = Object.entries(counts).sort((a,b)=>b[1]-a[1])[0]?.[0] || 'Other';\n\n  return {\n    date,\n    min_temp: Number(min.toFixed(1)),\n    max_temp: Number(max.toFixed(1)),\n    dominant_condition: dominant,\n    rain_mm: Number(rain.toFixed(1)),\n    precip_prob_avg: Number((popAvg*100).toFixed(0)),\n    wind_max: Number(windMax.toFixed(1)),\n    humidity_avg: Number(humAvg.toFixed(0)),\n    unit_temp: units === 'metric' ? '\u00b0C' : '\u00b0F',\n    unit_wind: units === 'metric' ? 'm/s' : 'mph'\n  };\n}).sort((a,b)=>a.date.localeCompare(b.date));\n\n// keep only next 5 days\nconst next5 = daySummaries.slice(0,5);\n\nreturn {\n  city,\n  country,\n  timezone_offset_seconds: tzOffset,\n  summaries: next5\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0a824d7f-d3d3-4c8e-b782-36d5c94191ae",
      "name": "OpenWeatherMap (OWM) - 5 Day Forecast (by City)",
      "type": "n8n-nodes-base.openWeatherMap",
      "position": [
        1024,
        80
      ],
      "parameters": {
        "cityName": "={{ $json.asked_city }}",
        "operation": "5DayForecast"
      },
      "credentials": {
        "openWeatherMapApi": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 1
    },
    {
      "id": "2ad3a2e8-3605-4203-a113-44fe99c34e66",
      "name": "JS - Pick Lat/Lon",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        288
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const asked = $json.city || null;\nconst location = $json.body?.[0] || $json.body;\n\nif (!location || !location.lat || !location.lon) {\n  throw new Error('No valid geocoding results for: ' + asked);\n}\n\nreturn {\n  asked_city: asked,\n  city_from_api: location.name || asked,\n  country: location.country || null,\n  lat: location.lat,\n  lon: location.lon\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "e6202cc9-8516-4c12-beea-1c3dca68dc8a",
      "name": "SET - Carry Asked City to Forecast",
      "type": "n8n-nodes-base.set",
      "position": [
        832,
        288
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2c7d6017-02ca-4e76-ab6e-000707eea2ab",
              "name": "asked_city",
              "type": "string",
              "value": "={{ $json.asked_city }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d2f43ed1-2f4a-476b-8e38-4277ce72e786",
      "name": "MERGE - Pair Cities",
      "type": "n8n-nodes-base.merge",
      "position": [
        464,
        288
      ],
      "parameters": {
        "mode": "combine",
        "options": {
          "includeUnpaired": false
        },
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "5dd95724-b5fe-4230-87b4-4554f1dc74ea",
      "name": "HTTP - OWM Geocoding",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        224,
        32
      ],
      "parameters": {
        "url": "https://api.openweathermap.org/geo/1.0/direct\n",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "=={{ encodeURIComponent($json.city) }}"
            },
            {
              "name": "limit",
              "value": "1"
            },
            {
              "name": "appid",
              "value": "<<YOUR_API_KEY>>"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d574f191-aed1-472c-80e0-96f22ef14480",
      "name": "JS - Normalize City Inputs",
      "type": "n8n-nodes-base.code",
      "position": [
        16,
        304
      ],
      "parameters": {
        "jsCode": "// Collect only city names from the form payload\n// Filter out metadata fields like submittedAt and formMode\nconst cities = [];\n\nfor (const [key, value] of Object.entries($json)) {\n  // Exclude known metadata fields\n  if (key === 'submittedAt' || key === 'formMode') {\n    continue;\n  }\n  \n  // Include all other string values that are not empty\n  if (typeof value === 'string' && value.trim()) {\n    cities.push(value.trim());\n  }\n}\n\n// Limit to 3 cities and create one item per city\nreturn cities.slice(0, 3).map(c => ({ city: c }));"
      },
      "typeVersion": 2
    },
    {
      "id": "11ec0415-f62f-4e61-8416-7468c235e2b7",
      "name": "TRIGGER - Input City Names",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -160,
        304
      ],
      "parameters": {
        "options": {},
        "formTitle": "Weather predictor demo task",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Enter City Name 1",
              "placeholder": "eg: Hyderabad",
              "requiredField": true
            },
            {
              "fieldLabel": "Enter City Name 2",
              "placeholder": "eg: Bangalore",
              "requiredField": true
            },
            {
              "fieldLabel": "Enter City Name 3",
              "placeholder": "Chennai",
              "requiredField": true
            }
          ]
        },
        "formDescription": "It provides the weather prediction of 3 cities and provide general tips and precuations"
      },
      "typeVersion": 2.3
    },
    {
      "id": "7b1dfae5-be7d-4d76-9f6c-3bf3bc0eb271",
      "name": "LLM - AI Weather Briefing Composer",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1520,
        16
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "=You are an expert meteorologist creating professional weather briefings. Return STRICT JSON with keys: subject, html. Use clear, actionable language. No conversational text outside the JSON.\n\n"
            },
            {
              "content": "=You are an expert meteorologist creating professional weather briefings. Return STRICT JSON with keys: subject, html. Use clear, actionable language. No conversational text outside the JSON.\n```\n\n## **Revised User Prompt:**\n```\nCreate a professional 5-day weather forecast email for EACH city in this JSON:\n{{ JSON.stringify($json.cities) }}\n\nREQUIREMENTS:\n\n\ud83d\udccb Structure:\n- Start with a friendly greeting and brief intro\n- For each city, use H2 with \"\ud83c\udf24\ufe0f City \u2014 Country\"\n- HTML table with these columns: Date | Temp Range | Conditions | Rain(mm) | Precip(%) | Wind(m/s) | General Tips | Precautions\n- Add a concluding paragraph with travel/planning tips across all cities\n\n\ud83c\udfa8 Styling (use inline CSS):\n- Header row: background #4A90E2 (blue), white text, bold, font-size: 14px\n- Borders: 1px solid #DEE2E6 on all cells\n- Padding: 10px in cells\n- Font: Arial, sans-serif, font-size: 13px\n- Center-align all table content\n- Table width: 100%, border-collapse: collapse\n\n\ud83c\udf08 CONDITION-BASED ROW COLORS (apply to entire row based on dominant_condition):\n- \"Clear\": background-color: #FFFACD (light yellow)\n- \"Clouds\": background-color: #ADD8E6 (light blue)\n- \"Rain\": background-color: #FFB6C6 (light red/pink)\n- Extremely sunny (max_temp \u2265 35\u00b0C AND condition is \"Clear\"): background-color: #FFBF00 (amber)\n- Default (other conditions): background-color: #FFFFFF (white)\n\n\ud83d\udcca Content Guidelines:\n- Date: Format as \"YYYY-MM-DD (Day)\" - e.g., \"2025-10-19 (Sun)\"\n- Temp Range: Show as \"Min\u00b0C / Max\u00b0C\" (e.g., \"24\u00b0 / 32\u00b0\")\n- Conditions: Add weather emoji + condition name:\n  - Clear: \u2600\ufe0f Clear\n  - Clouds: \u2601\ufe0f Clouds\n  - Rain: \ud83c\udf27\ufe0f Rain\n  - Thunderstorm: \u26c8\ufe0f Thunderstorm\n- Rain: Show mm value\n- Precip%: Show percentage value\n- Wind: Show m/s value\n- General Tips: Brief everyday advice (e.g., \"Stay hydrated\", \"Dress lightly\")\n- Precautions: Specific safety warnings (detailed below)\n\n\u26a0\ufe0f PRECAUTIONS Column Content (show relevant warnings only, or \"None\" if weather is safe):\n- Heavy rain (rain_mm \u2265 10 OR precip_prob_avg \u2265 70): \"\u26a0\ufe0f Heavy rain expected. Carry umbrella, avoid travel if possible. Expect waterlogging.\"\n- Moderate rain (rain_mm \u2265 5 AND < 10 OR precip_prob_avg \u2265 50 AND < 70): \"\u2614 Rain likely. Carry rain gear, drive carefully.\"\n- Extreme heat (max_temp \u2265 35\u00b0C): \"\ud83c\udf21\ufe0f HEAT ALERT: Stay indoors during peak hours (12-4 PM). Drink 3+ liters water. Risk of heat stroke.\"\n- High heat (max_temp \u2265 32\u00b0C AND < 35\u00b0C): \"\u2600\ufe0f Very hot. Limit outdoor activities. Use sunscreen SPF 50+.\"\n- High wind (wind_max \u2265 10 m/s): \"\ud83d\udca8 Strong winds expected. Secure loose objects. Avoid outdoor hoardings.\"\n- Thunderstorms (if \"Thunderstorm\" in conditions): \"\u26c8\ufe0f STORM WARNING: Stay indoors. Unplug electronics. Avoid water bodies.\"\n- Multiple conditions: Combine warnings separated by \" | \"\n- Safe weather: \"None\" or \"\u2705 Safe weather conditions\"\n\n\ud83d\udca1 GENERAL TIPS Column Content (positive, practical daily advice):\n- Clear & pleasant (max < 32\u00b0C): \"Great for outdoor activities\"\n- Clear & hot (max \u2265 32\u00b0C): \"Stay hydrated, use sun protection\"\n- Clouds: \"Comfortable weather, good for sightseeing\"\n- Light rain: \"Keep umbrella handy\"\n- Heavy rain: \"Plan indoor activities\"\n- Windy: \"Secure loose items\"\n\n\ud83d\udcdd Email Subject:\nCreate an engaging subject that highlights the most significant weather event:\n- If any day has rain_mm \u2265 10: \"\u26a0\ufe0f Heavy Rain Alert: [City Names] | 5-Day Forecast\"\n- If any day has max_temp \u2265 35\u00b0C: \"\ud83c\udf21\ufe0f Heat Wave Alert: [City Names] | 5-Day Forecast\"\n- If all days are clear: \"\u2600\ufe0f Sunny Week Ahead: [City Names] | 5-Day Forecast\"\n- Otherwise: \"5-Day Weather Forecast: [City Names]\"\n\n\ud83c\udfaf Conclusion Paragraph:\nInclude:\n- Overall weather pattern across all cities\n- Best days for outdoor activities/travel\n- Most important safety advisory if any extreme weather\n- Friendly closing line\n\nCRITICAL: Apply the condition-based background color to the ENTIRE ROW (all cells in that row), not just the Conditions column.\n\nReturn ONLY valid JSON:\n{\"subject\":\"...\",\"html\":\"...\"}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "07e5c472-3d02-4579-a1ef-77bd8ea44bf5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -816,
        -512
      ],
      "parameters": {
        "width": 608,
        "height": 1056,
        "content": "# Try Out\n\n## Overview\n### This workflow automates weather forecast delivery by collecting city names, fetching 5-day forecasts from OpenWeatherMap, and generating professionally formatted HTML emails using GPT-4. The AI creates condition-based color-coded reports with safety precautions and sends them via Gmail.\n\n## How It Works\nA form trigger collects up to three city names, which are geocoded via OpenWeatherMap API to retrieve coordinates and 5-day forecasts.\n\nJavaScript nodes process the raw weather data into daily summaries, calculating temperature ranges, precipitation levels, wind speeds, and dominant weather conditions.\n\nGPT-4 then generates professionally formatted HTML emails with condition-based color coding: The AI intelligently adds contextual safety warnings for heavy rain, extreme heat, high winds, and thunderstorms.\n\nA validation node ensures proper JSON formatting before Gmail sends the final briefing.\n\n## Use Cases\n\n\u2022 Field ops & construction crew briefings\n\u2022 Travel planning and itinerary preparation\n\u2022 Outdoor event planning & coordination\n\u2022 Logistics and transportation route planning\n\u2022 Real estate property viewing scheduling\n\u2022 Sports and recreational activity planning\n\n## Setup Requirements\n\nOpenWeatherMap API credentials\nOpenAI API key\nGmail OAuth2 authentication\n\n## Need Help?\nJoin the Discord or ask in the Forum!\nREADME file available at https://tinyurl.com/MulticityWeatherForecast"
      },
      "typeVersion": 1
    },
    {
      "id": "39f8510b-c1a3-44b7-97bd-fe491bd72d15",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        -160
      ],
      "parameters": {
        "color": 4,
        "width": 208,
        "height": 656,
        "content": "## Geocoding (OWM)\n### Resolve each city to lat/lon using OpenWeather Geocoding API."
      },
      "typeVersion": 1
    },
    {
      "id": "746f1466-187a-421b-8160-b4a982dd02a8",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        96
      ],
      "parameters": {
        "color": 6,
        "width": 560,
        "height": 400,
        "content": "## Pairing Cities \u2194 Coordinates\n### Align normalized city with its geocode (by position) and select asked_city, country, lat, lon."
      },
      "typeVersion": 1
    },
    {
      "id": "fd98f570-9beb-4cb7-9de3-eb1fb2599a33",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        976,
        -144
      ],
      "parameters": {
        "color": 3,
        "width": 208,
        "height": 640,
        "content": "## Forecast Retrieval\n### Pull 5-day forecast per city by coordinates."
      },
      "typeVersion": 1
    },
    {
      "id": "7864bbf7-eeab-43a6-ab00-7d1786a5f414",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        -144
      ],
      "parameters": {
        "color": 2,
        "width": 576,
        "height": 352,
        "content": "## LLM AI Weather Briefing\n### Ask LLM to produce subject + HTML for an email; validate/extract the result."
      },
      "typeVersion": 1
    },
    {
      "id": "8ac37160-d037-42a3-8900-c70f326c5901",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        -144
      ],
      "parameters": {
        "color": 4,
        "height": 640,
        "content": "## Summarization & Packaging\n### Convert raw OWM output into per-day tables & guidance; bundle all cities into one payload."
      },
      "typeVersion": 1
    },
    {
      "id": "fe07b361-deae-4f13-b3a7-d85804d5d7a7",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        224
      ],
      "parameters": {
        "color": 6,
        "width": 576,
        "height": 288,
        "content": "## Delivery \n### Send the formatted briefing to the recipient(s)."
      },
      "typeVersion": 1
    },
    {
      "id": "0d440118-543a-44ca-bdc1-03187c110850",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -192,
        112
      ],
      "parameters": {
        "color": 5,
        "width": 352,
        "height": 384,
        "content": "## Input & Normalization\n### Collect 3 city names from the form and normalize (trim, title-case, dedupe)."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "dd0565ff-6b0c-4003-a4a6-fd5579f32295",
  "connections": {
    "JS - Pick Lat/Lon": {
      "main": [
        [
          {
            "node": "SET - Carry Asked City to Forecast",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MERGE - Pair Cities": {
      "main": [
        [
          {
            "node": "JS - Pick Lat/Lon",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP - OWM Geocoding": {
      "main": [
        [
          {
            "node": "MERGE - Pair Cities",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Bundle Cities for LLM": {
      "main": [
        [
          {
            "node": "LLM - AI Weather Briefing Composer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Normalize City Inputs": {
      "main": [
        [
          {
            "node": "HTTP - OWM Geocoding",
            "type": "main",
            "index": 0
          },
          {
            "node": "MERGE - Pair Cities",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "TRIGGER - Input City Names": {
      "main": [
        [
          {
            "node": "JS - Normalize City Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Validate JSON from LLM": {
      "main": [
        [
          {
            "node": "GMAIL - Send Weather Briefing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM - AI Weather Briefing Composer": {
      "main": [
        [
          {
            "node": "JS - Validate JSON from LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SET - Carry Asked City to Forecast": {
      "main": [
        [
          {
            "node": "OpenWeatherMap (OWM) - 5 Day Forecast (by City)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Build Daily Summaries (5 days)": {
      "main": [
        [
          {
            "node": "JS - Bundle Cities for LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenWeatherMap (OWM) - 5 Day Forecast (by City)": {
      "main": [
        [
          {
            "node": "JS - Build Daily Summaries (5 days)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}