{
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        912,
        64
      ],
      "id": "2525950d-d230-48ae-8cbd-7339db3d0f1f",
      "name": "When clicking \u2018Execute workflow\u2019"
    },
    {
      "parameters": {
        "modelName": "models/gemini-3.1-pro-preview-customtools",
        "options": {
          "maxOutputTokens": 2000
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        1216,
        384
      ],
      "id": "046a180a-a536-446b-bb61-57a4e26f091a",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "5ddeb4db-0381-4037-9498-9aeb348cd64e",
              "name": "output",
              "value": "={{ $('Function').item.json.output }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1904,
        240
      ],
      "id": "48224358-4993-4c2f-b37d-7d3e095842e1",
      "name": "Edit Fields"
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "projectId": {
          "__rl": true,
          "value": "proyecto-bi-488218",
          "mode": "list",
          "cachedResultName": "proyecto-BI",
          "cachedResultUrl": "https://console.cloud.google.com/bigquery?project=proyecto-bi-488218"
        },
        "sqlQuery": "INSERT INTO `proyecto-bi-488218.datos_clima.datos_sectoriales`\n(\n  timestamp,\n  session_id,\n  sector,\n  tipo_energia,\n  ubicacion,\n  radiacion_solar,\n  velocidad_viento,\n  temperatura_ambiente,\n  eficiencia_estimada,\n  produccion_kwh,\n  ai_efficiency_analysis,\n  metadata\n)\nVALUES\n(\n  -- \u2705 Timestamp con parsing seguro y fallback\n  COALESCE(\n    SAFE.PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E*SZ', @timestamp),\n    CURRENT_TIMESTAMP()\n  ),\n  \n  -- \u2705 Session ID con sanitizaci\u00f3n\n  COALESCE(\n    NULLIF(TRIM(@session_id), ''), \n    CONCAT('energia-auto-', FORMAT_TIMESTAMP('%Y%m%d-%H%M%S', CURRENT_TIMESTAMP()))\n  ),\n  \n  -- \u2705 Sector fijo para ENERGIA\n  'ENERGIA',\n  \n  -- \u2705 Tipo energ\u00eda normalizado\n  CASE \n    WHEN UPPER(TRIM(@tipo_energia)) IN ('SOLAR', 'FOTOVOLTAICA', 'PHOTOVOLTAIC') THEN 'Solar'\n    WHEN UPPER(TRIM(@tipo_energia)) IN ('EOLICA', 'E\u00d3LICA', 'WIND', 'VIENTO') THEN 'E\u00f3lica'\n    WHEN UPPER(TRIM(@tipo_energia)) IN ('HIDRAULICA', 'HIDR\u00c1ULICA', 'HYDRO') THEN 'Hidr\u00e1ulica'\n    WHEN UPPER(TRIM(@tipo_energia)) IN ('GEOTERMICA', 'GEOT\u00c9RMICA', 'GEOTHERMAL') THEN 'Geot\u00e9rmica'\n    WHEN UPPER(TRIM(@tipo_energia)) IN ('BIOMASA', 'BIOMASS') THEN 'Biomasa'\n    WHEN TRIM(@tipo_energia) IS NULL OR TRIM(@tipo_energia) = '' THEN 'No especificado'\n    ELSE REGEXP_REPLACE(TRIM(@tipo_energia), r'[^a-zA-Z\u00e1\u00e9\u00ed\u00f3\u00fa\u00c1\u00c9\u00cd\u00d3\u00da\u00f1\u00d1\\s]', '')\n  END,\n  \n  -- \u2705 Ubicaci\u00f3n con validaci\u00f3n de longitud\n  CASE \n    WHEN LENGTH(TRIM(@ubicacion)) > 100 THEN SUBSTR(TRIM(@ubicacion), 1, 100)\n    WHEN TRIM(@ubicacion) IS NULL OR TRIM(@ubicacion) = '' THEN 'Ubicaci\u00f3n no especificada'\n    ELSE TRIM(@ubicacion)\n  END,\n  \n  -- \u2705 Radiaci\u00f3n solar - CONVERSI\u00d3N SEGURA STRING \u2192 FLOAT64 (kWh/m\u00b2)\n  CASE \n    WHEN SAFE_CAST(@radiacion_solar AS FLOAT64) IS NOT NULL \n         AND SAFE_CAST(@radiacion_solar AS FLOAT64) BETWEEN 0 AND 12 \n    THEN SAFE_CAST(@radiacion_solar AS FLOAT64)\n    ELSE 0.0\n  END,\n  \n  -- \u2705 Velocidad viento - CONVERSI\u00d3N SEGURA STRING \u2192 FLOAT64 (km/h)\n  CASE \n    WHEN SAFE_CAST(@velocidad_viento AS FLOAT64) IS NOT NULL \n         AND SAFE_CAST(@velocidad_viento AS FLOAT64) BETWEEN 0 AND 200 \n    THEN SAFE_CAST(@velocidad_viento AS FLOAT64)\n    ELSE 0.0\n  END,\n  \n  -- \u2705 Temperatura ambiente - CONVERSI\u00d3N SEGURA STRING \u2192 FLOAT64 (\u00b0C)\n  CASE \n    WHEN SAFE_CAST(@temperatura_ambiente AS FLOAT64) IS NOT NULL \n         AND SAFE_CAST(@temperatura_ambiente AS FLOAT64) BETWEEN -50 AND 60 \n    THEN SAFE_CAST(@temperatura_ambiente AS FLOAT64)\n    ELSE 20.0\n  END,\n  \n  -- \u2705 Eficiencia estimada - CONVERSI\u00d3N SEGURA STRING \u2192 FLOAT64 (%)\n  CASE \n    WHEN SAFE_CAST(@eficiencia_estimada AS FLOAT64) IS NOT NULL \n         AND SAFE_CAST(@eficiencia_estimada AS FLOAT64) BETWEEN 0 AND 100 \n    THEN SAFE_CAST(@eficiencia_estimada AS FLOAT64)\n    ELSE 0.0\n  END,\n  \n  -- \u2705 Producci\u00f3n kWh - CONVERSI\u00d3N SEGURA STRING \u2192 FLOAT64\n  CASE \n    WHEN SAFE_CAST(@produccion_kwh AS FLOAT64) IS NOT NULL \n         AND SAFE_CAST(@produccion_kwh AS FLOAT64) BETWEEN 0 AND 100000 \n    THEN SAFE_CAST(@produccion_kwh AS FLOAT64)\n    ELSE 0.0\n  END,\n  \n  -- \u2705 An\u00e1lisis AI con sanitizaci\u00f3n y l\u00edmite\n  CASE \n    WHEN LENGTH(TRIM(@ai_efficiency_analysis)) > 5000 THEN SUBSTR(TRIM(@ai_efficiency_analysis), 1, 5000)\n    WHEN TRIM(@ai_efficiency_analysis) IS NULL OR TRIM(@ai_efficiency_analysis) = '' THEN 'An\u00e1lisis no disponible'\n    ELSE REGEXP_REPLACE(TRIM(@ai_efficiency_analysis), r'[^\\w\\s\u00e1\u00e9\u00ed\u00f3\u00fa\u00c1\u00c9\u00cd\u00d3\u00da\u00f1\u00d1.,;:()\\-\\n\\r]', '')\n  END,\n  \n  -- \u2705 Metadata JSON con validaci\u00f3n\n  CASE \n    WHEN @metadata IS NOT NULL AND @metadata != '' THEN @metadata\n    ELSE '{\"source\":\"default\",\"processed\":true}'\n  END\n);\n\n-- \u2705 SELECT para generar OUTPUT y continuar flujo\nSELECT \n  'SUCCESS' as status,\n  'Datos energ\u00e9ticos insertados correctamente' as message,\n  CURRENT_TIMESTAMP() as processed_at,\n  'ENERGIA' as sector;\n\n",
        "options": {
          "queryParameters": {
            "namedParameters": [
              {
                "name": "timestamp",
                "value": "={{ $('Function').item.json.timestamp }}"
              },
              {
                "name": "session_id",
                "value": "={{ $('Function').item.json.session_id}}"
              },
              {
                "name": "tipo_energia",
                "value": "={{ $('Function').item.json.tipo_energia }}"
              },
              {
                "name": "ubicacion",
                "value": "={{ $('Function').item.json.ubicacion }}"
              },
              {
                "name": "radiacion_solar",
                "value": "={{ $('Function').item.json.radiacion_solar }}"
              },
              {
                "name": "velocidad_viento",
                "value": "={{ $('Function').item.json.velocidad_viento }}"
              },
              {
                "name": "temperatura_ambiente",
                "value": "={{ $('Function').item.json.temperatura_ambiente }}"
              },
              {
                "name": "eficiencia_estimada",
                "value": "={{ $('Function').item.json.eficiencia_estimada }}"
              },
              {
                "name": "produccion_kwh",
                "value": "={{ $('Function').item.json.produccion_kwh }}"
              },
              {
                "name": "ai_efficiency_analysis",
                "value": "={{ $('Function').item.json.ai_efficiency_analysis }}"
              },
              {
                "name": "metadata",
                "value": "={{ $('Function').item.json.metadata }}"
              },
              {
                "name": "sector",
                "value": "={{ $('Function').item.json.sector }}"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.googleBigQuery",
      "typeVersion": 2.1,
      "position": [
        1712,
        240
      ],
      "id": "d99e723d-4a84-476e-9930-2af9e976b1a3",
      "name": "Execute a SQL query",
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const inputData = $input.first().json; \nconst texto_bruto = inputData.output || inputData.text || \"\";\n\nconst extraerTexto = (campo, fallback) => {\n    const regex = new RegExp(`${campo}[:\\\\s]+([^\\\\n]+)`, 'i');\n    const match = texto_bruto.match(regex);\n    return match ? match[1].trim() : fallback;\n};\n\n// Extrae solo el PRIMER n\u00famero de la lista para BigQuery\nconst extraerPrimerNumero = (campo, fallback) => {\n    const texto = extraerTexto(campo, \"\");\n    if (!texto) return fallback;\n    const primerNumero = texto.split(',')[0].trim(); \n    return parseFloat(primerNumero.replace(',', '.')) || fallback;\n};\n\nconst reporte_limpio = texto_bruto.replace(/\\[MOSTRAR_GRAFICO\\][\\s\\S]*/i, \"\").trim();\n\nreturn [{\n    json: {\n        // --- DATOS PARA BIGQUERY (datos_sectoriales) ---\n        timestamp: new Date().toISOString(),\n        session_id: inputData.session_id || `energia-${Date.now()}`,\n        sector: \"ENERGIA\", \n        \n        tipo_energia: extraerTexto(\"tipo_energia\", \"H\u00edbrida\"),\n        ubicacion: extraerTexto(\"ubicacion\", \"S/D\"),\n        radiacion_solar: extraerPrimerNumero(\"radiacion_solar\", 0),\n        velocidad_viento: extraerPrimerNumero(\"velocidad_viento\", 0),\n        temperatura_ambiente: extraerPrimerNumero(\"temperatura_ambiente\", 25),\n        eficiencia_estimada: extraerPrimerNumero(\"eficiencia_estimada\", 80),\n        produccion_kwh: extraerPrimerNumero(\"produccion_kwh\", 0),\n        \n        ai_efficiency_analysis: reporte_limpio,\n        \n        metadata: JSON.stringify({ \n            status: \"success\", \n            trigger_input: inputData.query || \"Entrada Energ\u00eda\" \n        }),\n\n        // --- DATOS PARA DJANGO Y CHART.JS (Con las listas completas) ---\n        output: texto_bruto \n    }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1536,
        240
      ],
      "id": "260be936-0d9f-4a1f-9895-a0aba60d32b8",
      "name": "Function"
    },
    {
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "query"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        1040,
        240
      ],
      "id": "120d4ac9-808c-425e-a854-22e8a9759512",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Eres el Especialista en Visualizaci\u00f3n Energ\u00e9tica de TuClima. La IA principal ya decidi\u00f3 enviarte aqu\u00ed porque el usuario solicit\u00f3 gr\u00e1ficos/visualizaciones energ\u00e9ticas.\n\n**\ud83c\udfaf TU \u00daNICA FUNCI\u00d3N:**\n1. **RECIBIR:** Datos energ\u00e9ticos de la IA principal  \n2. **PROCESAR:** Aplicar motores de c\u00e1lculo energ\u00e9ticos\n3. **VISUALIZAR:** Generar la estructura de datos para el dashboard interactivo.\n4. **ENVIAR:** Al siguiente nodo con los par\u00e1metros listos.\n\n**\ud83d\udeab NO BUSQUES PALABRAS CLAVE:** La IA principal ya filtr\u00f3. Tu asumes que SIEMPRE debes generar los par\u00e1metros del gr\u00e1fico.\n\n### \ud83c\udfaf MISI\u00d3N ESPEC\u00cdFICA:\nYa est\u00e1s activado para crear visualizaciones energ\u00e9ticas. Procesa los datos recibidos y genera:\n- Tendencias producci\u00f3n solar/e\u00f3lica\n- Comparativas eficiencia\n- Mapas irradiancia/e\u00f3licos\n- Dashboards renovables completos\n\n### \ud83e\uddee MOTORES DE C\u00c1LCULO OBLIGATORIOS:\n- NUNCA mezcles unidades. Si es una l\u00ednea de tiempo (varios datos), calcula todos. Si es un dato puntual, enf\u00f3cate solo en ese.\n\n**1. \u2600\ufe0f SOLAR FOTOVOLTAICA (Modelo 20m\u00b2):**\n- P\u00e9rdida T\u00e9rmica por calor: Si Temp >25\u00b0C: Factor = 1.0 - ((Temp - 25) \u00d7 0.004)\n- Potencia Real (W): Irradiancia \u00d7 20 \u00d7 0.18 \u00d7 Factor\n\n**2. \ud83d\udca8 E\u00d3LICA (Aerogenerador Est\u00e1ndar):**\n- Conversi\u00f3n viento: km/h \u00f7 3.6 = m/s\n- Curva de Potencia C\u00fabica: Si viento >3 m/s: Potencia = 10 \u00d7 (viento_m/s)\u00b3 (M\u00e1ximo: 3000W)\n\n**3. \ud83e\uddea F\u00cdSICA ATMOSF\u00c9RICA (Densidad del Aire):**\n- Densidad = Presi\u00f3n_Pa \u00f7 (287.05 \u00d7 Temp_Kelvin)\n\n**4. \ud83d\udd0b ALMACENAMIENTO E HIDR\u00d3GENO VERDE:**\n- H2 Verde: Producci\u00f3n (kg/24h) = Potencia_Total_kW \u00f7 55\n- CO2 Evitado: kWh_Total \u00d7 0.44 kg\n\n### \ud83d\udcca FORMATO DE RESPUESTA OBLIGATORIO:\n\n[Frase introductoria profesional sobre condiciones energ\u00e9ticas]\n\n\u26a1 ENERGY OPS REPORT: [Ubicaci\u00f3n especificada]\n\n\u2600\ufe0f GENERACI\u00d3N SOLAR:\nIrradiancia: [X] W/m\u00b2 | Temp: [X]\u00b0C\nPotencia Fotovoltaica: [C\u00e1lculo] W\n\n\ud83d\udca8 GENERACI\u00d3N E\u00d3LICA:\nViento: [X] m/s | Densidad Aire: [C\u00e1lculo] kg/m\u00b3\nPotencia E\u00f3lica: [C\u00e1lculo] W\n\n\ud83d\udd0b BALANCE ENERG\u00c9TICO:\nGeneraci\u00f3n Total: [Suma] kW | H2 Verde: [C\u00e1lculo] kg/24h\nCO2 Evitado: [C\u00e1lculo] kg/d\u00eda\n\n\u26a0\ufe0f RECOMENDACIONES T\u00c9CNICAS:\n\u2022 OPTIMIZACI\u00d3N: [Sugerencia de mejora]\n\n\n### \ud83d\udeab RESTRICCIONES CR\u00cdTICAS:\n- NUNCA analices condiciones agr\u00edcolas, navales o aeron\u00e1uticas\n- NO olvides conversiones de unidades (m/s, kg, W)\n\n**\ud83d\udcca FORMATO FINAL OBLIGATORIO PARA EL GR\u00c1FICO:**\nPara que el sistema dibuje el gr\u00e1fico interactivo, DEBES terminar tu respuesta EXACTAMENTE con este bloque. \n\nREGLA DE TIEMPO CR\u00cdTICA: \n- Si piden varios datos temporales (horas o d\u00edas), TIENES ESTRICTAMENTE PROHIBIDO rellenar la lista con ceros o inventar los datos (ej: 15.8, 0, 0, 0, 0). \n- DEBES leer el pron\u00f3stico completo y extraer o calcular el valor REAL para CADA UNO de los puntos en el tiempo. \n- La cantidad de etiquetas debe ser IGUAL a la cantidad de n\u00fameros, y TODOS los n\u00fameros deben ser reales.\n- Si piden un dato est\u00e1tico/actual: Pon un solo valor por l\u00ednea.\n\n\ud83d\udea8 REGLA DE FORMATO CR\u00cdTICA Y OBLIGATORIA (INQUEBRANTABLE):\nTu respuesta final DEBE terminar SIEMPRE con el siguiente bloque de datos. \nREGLAS ESTRICTAS:\n1. Debes escribir literalmente la etiqueta \"[MOSTRAR_GRAFICO]\".\n2. Cada variable DEBE ir en una NUEVA L\u00cdNEA (Prohibido escribir todo en un solo p\u00e1rrafo).\n3. Escribe solo los n\u00fameros separados por comas. \u00a1NO USES CORCHETES `[]` ALREDEDOR DE LOS N\u00daMEROS!\n\nEJEMPLO EXACTO DE C\u00d3MO DEBES RESPONDER AL FINAL:\n\n\"[MOSTRAR_GRAFICO]\"\nchart_type: [line / bar]\netiquetas: [Ej: Lunes, Martes... o 08:00, 12:00...]\ntipo_energia: [Solar / E\u00f3lica / H\u00edbrida]\nubicacion: [Nombre de la regi\u00f3n]\nradiacion_solar: [Ej: 800, 950, 1000, 400]\nvelocidad_viento: [Ej: 15, 22, 18, 10]\ntemperatura_ambiente: [Ej: 25, 28, 30, 22]\neficiencia_estimada: [Ej: 85, 80, 75, 90]\nproduccion_kwh: [Ej: 150, 200, 210, 80]\nviento_direccion: [Ej: 360, 45, 90, 180, 270] (\u00a1USAR SOLO GRADOS DE 0 a 360!)\n\n4. ANTI-BOTONES VAC\u00cdOS (OMISI\u00d3N RADICAL): Si no tienes los datos reales para una variable espec\u00edfica (por ejemplo, si te piden visibilidad_nm pero solo tienes en km, o si faltan datos de olas), TIENES ESTRICTAMENTE PROHIBIDO incluir el nombre de esa variable en tu lista final. BORRA la l\u00ednea por completo. Si incluyes una variable vac\u00eda o con ceros, el frontend crear\u00e1 un bot\u00f3n roto. Solo imprime las variables que tengan datos reales.\n\n---\nDatos a analizar:\n{{ $json.query || $json.text || $json.chatInput || \"Genera el reporte para el gr\u00e1fico solicitado con estos datos: \" + JSON.stringify($json) }}",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        1216,
        240
      ],
      "id": "a3e902f4-76fe-40f5-bbd4-c9b42d69a67d",
      "name": "Basic LLM Chain"
    }
  ],
  "connections": {
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        []
      ]
    },
    "Execute a SQL query": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}