{
  "name": "Chatbot Webhook",
  "nodes": [
    {
      "parameters": {
        "keys": {
          "key": [
            {
              "currentKey": "output",
              "newKey": "=respuesta"
            }
          ]
        },
        "additionalOptions": {}
      },
      "type": "n8n-nodes-base.renameKeys",
      "typeVersion": 1,
      "position": [
        1632,
        1408
      ],
      "id": "d34ae610-82e4-4ff6-ba9f-7db95e519628",
      "name": "Rename Keys"
    },
    {
      "parameters": {
        "content": "## Crear mapa mental en base a mensaje",
        "height": 432,
        "width": 1152,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        1232
      ],
      "typeVersion": 1,
      "id": "f20a9fa1-0e9e-445f-bcc8-77a82aafde86",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { \"respuesta\": $json.respuesta } }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Access-Control-Allow-Origin",
                "value": "*"
              },
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        1856,
        1408
      ],
      "id": "28052080-1bd8-4f3e-853f-f7fccb8dd841",
      "name": "ResponderMapaMental"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        1264,
        1520
      ],
      "id": "ff701570-66a4-4292-b871-0298bc7c7015",
      "name": "Google Gemini Chat Model2",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Contexto: {{ $json.body.contexto }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "=Basado en el Contexto, genera SOLAMENTE una estructura de datos JSON para un mapa mental. El JSON debe tener la siguiente estructura:\n\n{\n  \"respuesta\": {\n    \"mensaje\": \"Aqu\u00ed tienes el mapa mental generado seg\u00fan tu contexto.\",\n    \"titulo\": \"[T\u00edtulo descriptivo del tema]\",\n    \"datos\": {\n      \"name\": \"Nombre del tema principal\",\n      \"children\": [\n        {\n          \"name\": \"Concepto principal 1\",\n          \"children\": [\n            {\"name\": \"Detalle 1A\"},\n            {\"name\": \"Detalle 1B\"}\n          ]\n        },\n        {\n          \"name\": \"Concepto principal 2\",\n          \"children\": [\n            {\"name\": \"Detalle 2A\"}\n          ]\n        }\n      ]\n    }\n  }\n}\n\nREGLAS ESTRICTAS:\n1. Tu respuesta debe ser \u00daNICAMENTE el c\u00f3digo JSON del mapa mental (el AI NO debe a\u00f1adir texto explicativo ni envolver el mapa en otras claves).\n2. NO incluyas ```json al principio ni ``` al final.\n3. NO agregues ning\u00fan texto explicativo.\n4. Aseg\u00farate que el JSON est\u00e9 bien formado.\n\nNOTA IMPORTANTE PARA EL FLUJO:\n- El texto de respuesta amistosa que ver\u00e1 el usuario ser\u00e1 agregado por el nodo RespondToWebhook. Ese texto ser\u00e1: \"Aqu\u00ed tienes el mapa mental generado seg\u00fan tu contexto.\" o algo del mismo estilo. Adem\u00e1s, debes generar un t\u00edtulo que describa el tema tratado en el mapa mental generado.Por favor **no** incluyas estos campos en tu salida; responde \u00fanicamente con el JSON del mapa mental."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 2.2,
      "position": [
        1280,
        1296
      ],
      "id": "1f2489e5-40b2-4775-8e4b-41d66f9ce54c",
      "name": "AI Agent4"
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"respuesta\": {\n    \"mensaje\": \"Aqu\u00ed tienes el mapa mental generado seg\u00fan tu contexto.\",\n    \"titulo\": \"El orden de las ideas\",\n    \"datos\": {\n      \"name\": \"Mapa Mental Principal\",\n      \"children\": [\n        {\n          \"name\": \"Idea Central 1\",\n          \"children\": [\n            { \"name\": \"Detalle A\" },\n            { \"name\": \"Detalle B\" }\n          ]\n        },\n        {\n          \"name\": \"Idea Central 2\",\n          \"children\": [\n            { \"name\": \"Detalle C\" }\n          ]\n        },\n        { \"name\": \"Idea Central 3\" }\n      ]\n    }\n  }\n}\n"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        1424,
        1520
      ],
      "id": "f45491ab-714f-4a8b-94a7-092fee7d512d",
      "name": "Structured Output Parser1"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "mapa-mental",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        1056,
        1408
      ],
      "id": "2ae678e4-ce66-44ab-80c7-5d5aeed56a67",
      "name": "Webhook Mental Map"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $json.body.conversation_id }}",
        "tableName": "n8n_chat_memory",
        "contextWindowLength": 15
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        1248,
        896
      ],
      "id": "5d10ac00-33de-49fe-8ebf-010946fdbd5a",
      "name": "Postgres Chat Memory",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "## Responder al usuario en el chatbot (streaming)",
        "height": 592,
        "width": 1152,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        624
      ],
      "typeVersion": 1,
      "id": "ec2df051-8a2b-4407-ad10-e7c24c110040",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.body.pregunta }}",
        "options": {
          "systemMessage": "=CONTEXTO INSTITUCIONAL:\nEres un asistente interno de la Vicerrector\u00eda de Administraci\u00f3n y Asuntos Econ\u00f3micos (VRAE) de la Universidad Cat\u00f3lica de Temuco. Apoyas a funcionarios en consultas operativas, procedimentales y normativas.\n\nDIRECCIONES QUE CONFORMAN LA VRAE:\n\u2022 Direcci\u00f3n de Cr\u00e9dito y Recaudaci\u00f3n (DCR)\n\u2022 Direcci\u00f3n de Desarrollo de Personas (DDPER)\n\u2022 Direcci\u00f3n de Inform\u00e1tica (DI)\n\u2022 Direcci\u00f3n de Campus y Servicios Generales (DCSG)\n\u2022 Direcci\u00f3n de Finanzas (DF)\n\nCONTEXTO DE DOCUMENTOS SELECCIONADOS:\n{{ $json.body.documentosSeleccionados.length > 0 ? \n'Has recibido ' + $json.body.documentosSeleccionados.length + ' documento(s) seleccionado(s): ' + \n$json.body.documentosSeleccionados.map(d => '- ' + d.title + ': ' + d.description).join('\\n')\n: \n'Sin documentos pre-seleccionados' }}\n\n\ud83c\udfaf INSTRUCCIONES OPERATIVAS:\n\n1. USO DE HERRAMIENTAS DE B\u00daSQUEDA:\n   - Usar \"Supabase Vector Store2\" para documentos seleccionados o info espec\u00edfica de procedimientos/normativas.\n   - Para info estructurada: b\u00fasquedas m\u00faltiples con t\u00e9rminos relacionados.\n   - Identificar \u00e1rea funcional y priorizar documentos de esa direcci\u00f3n.\n   - Si cruza \u00e1reas, buscar en ambas.\n\n2. ESTRATEGIA DE B\u00daSQUEDA OPERATIVA:\n   \n   PROCEDIMIENTOS:\n   - Buscar: [procedimiento] + [direcci\u00f3n] + \"flujo/pasos\"\n   - Buscar: \"responsables\" + [procedimiento]\n   - Buscar: \"requisitos/plazos\" + [procedimiento]\n   - Objetivo: Flujo completo con responsables, plazos, requisitos.\n   \n   NORMATIVAS/POL\u00cdTICAS:\n   - Buscar: [pol\u00edtica] + \"objetivos/alcance\"\n   - Buscar: [pol\u00edtica] + \"medidas/lineamientos\"\n   - Buscar: anexos/protocolos asociados.\n   - Objetivo: Marco normativo completo.\n   \n   BENEFICIOS/SERVICIOS:\n   - Buscar: [beneficio] + \"requisitos/funcionarios\"\n   - Buscar: \"c\u00f3mo solicitar\" + [beneficio]\n   - Buscar: formularios, plazos, contactos.\n   - Objetivo: Info accionable.\n   \n   SISTEMAS/HERRAMIENTAS:\n   - Buscar: [sistema] + \"acceso/manual\"\n   - Buscar: \"soporte\" + [sistema]\n   - Objetivo: Gu\u00eda pr\u00e1ctica.\n   \n   REGLA ANTI-FRAGMENTACI\u00d3N: \n   - Si info incompleta (ej: enumeraciones cortadas), buscar de nuevo.\n   - Validar completitud antes de responder.\n\n3. PRIORIZACI\u00d3N DE INFORMACI\u00d3N:\n   - 1ra: Documentos oficiales vigentes.\n   - 2da: Protocolos operativos.\n   - 3ra: Gu\u00edas/instructivos.\n   - Priorizar m\u00e1s reciente/jerarqu\u00eda si conflicto.\n\n4. FORMATO DE RESPUESTA EJECUTIVA Y AMIGABLE:\n   \n   APERTURA: Frase amigable confirmando consulta (ej: \"\u00a1Claro! Te ayudo con [tema]\").\n   \n   OPERATIVAS (\"\u00bfC\u00f3mo hago X?\"):\n   ```\n   \u00a1Claro! Te explico c\u00f3mo [acci\u00f3n]:\n   \n   PROCEDIMIENTO [NOMBRE]:\n   \n   REQUISITOS PREVIOS:\n   - [Lista]\n   \n   PASOS:\n   1. [Acci\u00f3n] \u2192 Responsable: [cargo/\u00e1rea] \u2192 Plazo: [tiempo]\n   \n   DOCUMENTOS NECESARIOS:\n   - [Lista]\n   \n   CONTACTO: [correo/extensi\u00f3n/\u00e1rea]\n   PLAZO TOTAL: [tiempo]\n   \n   \ud83d\udca1 TIP: [Consejo]\n   \n   \u00bfTe ayudo con algo m\u00e1s?\n   \n   Fuente: [Documento], [secci\u00f3n], [vigencia]\n   ```\n   \n   NORMATIVAS (\"\u00bfQu\u00e9 dice...?\"):\n   ```\n   Perfecto, aqu\u00ed est\u00e1 lo que dice la [pol\u00edtica]:\n   \n   [NOMBRE]:\n   \n   ALCANCE: [A qui\u00e9n aplica]\n   \n   ASPECTOS CLAVE:\n   \u2022 [Punto]\n   \n   RESPONSABILIDADES:\n   - [Actor]: [Funci\u00f3n]\n   \n   Si necesitas profundizar, preg\u00fantame.\n   \n   Fuente: [Documento], [vigencia]\n   ```\n   \n   BENEFICIOS (\"\u00bfTengo derecho...?\"):\n   ```\n   \u00a1S\u00ed! / [Seg\u00fan situaci\u00f3n]:\n   \n   BENEFICIO: [Nombre]\n   \n   APLICABLE A: [Requisitos]\n   \n   EN QU\u00c9 CONSISTE: [Descripci\u00f3n]\n   \n   C\u00d3MO SOLICITARLO:\n   1. [Paso]\n   \n   PLAZO: [X d\u00edas]\n   CONTACTO: [\u00c1rea]\n   \n   \ud83d\udca1 Si dudas, contacta [\u00e1rea].\n   \n   Fuente: [Documento]\n   ```\n   \n   URGENTES/COMPLEJAS:\n   ```\n   Entiendo que [es urgente], te ayudo:\n   \n   [Info]\n   \n   \u26a0\ufe0f IMPORTANTE: [Info cr\u00edtica]\n   \n   Contacta [\u00e1rea] para apoyo inmediato.\n   ```\n   \n   CIERRE: Abrir a seguir ayudando (ej: \"\u00bfNecesitas algo m\u00e1s?\").\n\n5. CITACI\u00d3N INTERNA:\n   - Formato: \"[Tipo] [Nombre] ([a\u00f1o/'vigente'])\"\n   - Ej: \"Seg\u00fan Manual DDPER (2023)...\"\n   - Incluir secci\u00f3n/art\u00edculo disponible.\n   - Citar cada documento en procedimientos transversales.\n\n6. MANEJO DE INFORMACI\u00d3N SENSIBLE:\n   - Compartir info operativa interna (procedimientos, flujos, contactos).\n   - Incluir \u00e1reas/cargos/contactos relevantes.\n   - Indicar restricciones por rol.\n   - No inventar contactos; usar solo de documentos.\n\n7. LENGUAJE Y TONO INSTITUCIONAL INTERNO:\n   - Lenguaje cercano, amable, colaborativo.\n   - Tono compa\u00f1ero: \"Con gusto te ayudo\", \"Aqu\u00ed est\u00e1 la info\".\n   - Usar siglas sin explicar.\n   - Frases apertura: \"\u00a1Claro! Te explico...\", \"Perfecto, esto es lo que necesitas\".\n   - Empat\u00eda: \"Entiendo que puede ser urgente...\".\n   - Si no claro: \"Confirma con [\u00e1rea]\".\n   - Cierre: \"Si necesitas algo m\u00e1s, aqu\u00ed estoy\".\n   - Emojis ocasionales: \u2705 \u23f1\ufe0f \ud83d\udce7 \ud83d\udca1 \u26a0\ufe0f\n\n8. GESTI\u00d3N DE CONSULTAS TRANSVERSALES:\n   - Identificar procesos multi-direcci\u00f3n.\n   - Presentar flujo con handoffs marcados.\n   - Ej: \"Inicia en tu Direcci\u00f3n \u2192 DDPER (validaci\u00f3n) \u2192 Finanzas (aprobaci\u00f3n)\".\n   - Coordinaci\u00f3n: \"Coordina con [\u00e1rea] antes de [paso]\".\n\n9. VERACIDAD ABSOLUTA Y TRAZABILIDAD:\n   - PROHIBIDO INVENTAR: No crear info no en documentos.\n   - Si falta dato cr\u00edtico: \"No encontr\u00e9 info espec\u00edfica. Confirma con [\u00e1rea]\".\n   - Transcribir listas exactamente.\n   - Si falta despu\u00e9s de b\u00fasquedas: \"No encontr\u00e9 info. Contacta [\u00e1rea]: [contacto]\".\n   - Honesto constructivo: Ofrecer alternativa.\n\n10. PROTOCOLO DE COMPLETITUD OPERATIVA:\n    - Se\u00f1ales incompletitud:\n      * Pasos incompletos.\n      * Referencias a anexos no mostrados.\n      * Menciones \"entre otros\".\n      * Plazos faltantes.\n      * Falta contacto/responsable.\n    - Acci\u00f3n: Detectar \u2192 Buscar de nuevo.\n    - Validaci\u00f3n: \"\u00bfPuede ejecutar con esta info?\" Si no \u2192 buscar m\u00e1s.\n\n11. ACTUALIZACI\u00d3N Y VIGENCIA:\n    - Mencionar fecha/a\u00f1o del documento.\n    - Usar versi\u00f3n m\u00e1s reciente.\n    - Si \u00fanico disponible: \"Seg\u00fan \u00faltimo ([a\u00f1o])... Valida vigencia con [\u00e1rea]\".\n\n12. SITUACIONES ESPECIALES:\n    - Sin documentaci\u00f3n: \"No hay procedimiento formal. Consulta [\u00e1rea]: [contacto]\".\n    - Consulta ambigua: \"Para ayudar mejor, \u00bfte refieres a [A] o [B]?\".\n    - Fuera \u00e1mbito: \"Corresponde a [\u00e1rea UCT]. Contacta [\u00e1rea]: [contacto]\".\n    - M\u00e1s contexto: \"\u00bfMe cuentas m\u00e1s sobre [aspecto]?\".\n    - Urgencia: \"Entiendo necesitas resolver pronto. [Info + contacto]\".\n    - Compleja: \"Situaci\u00f3n con varios pasos. Te detallo uno por uno:\", seguido de info.",
          "returnIntermediateSteps": true,
          "enableStreaming": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 2.2,
      "position": [
        1216,
        688
      ],
      "id": "99f6380a-3cb9-4eee-9911-f4d303d1a4f0",
      "name": "AI Agent1"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5.4-mini",
          "mode": "list",
          "cachedResultName": "gpt-5.4-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        1088,
        912
      ],
      "id": "68fd8493-442b-4c4e-8330-461d710b6196",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        1376,
        1072
      ],
      "id": "1845dc2a-2571-47d7-b838-2cd7b2e775d9",
      "name": "Embeddings OpenAI",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "chat-streaming",
        "responseMode": "streaming",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        992,
        688
      ],
      "id": "5490a39a-2f09-4c05-81c4-0618976486a8",
      "name": "Webhook"
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "=Esta herramienta busca documentos relevantes en la base de datos vectorial de Supabase.\n\nCuando el usuario solicite informaci\u00f3n respaldada o contextual, llama a esta herramienta para obtener los documentos m\u00e1s relacionados con la consulta.\n\n## Formato de salida requerido\n\nLa salida debe permitir trazabilidad completa e incluir los siguientes campos:\n\n* title\n* url\n* type\n* description\n* pageContent\n\n`pageContent` debe contener extractos textuales exactos utilizados para fundamentar la respuesta.\n\n## Pol\u00edtica de filtrado\n\nAplicar las siguientes reglas al procesar los resultados:\n\n* Si varios resultados tienen el mismo `title` o `doc_id`, fusi\u00f3nalos en un \u00fanico documento representativo.\n* Omite duplicados de extractos textuales.\n* Omite resultados sin metadatos claros, por ejemplo:\n\n  * sin t\u00edtulo\n  * sin contenido \u00fatil\n* Ordena los resultados por relevancia sem\u00e1ntica.\n\n## Objetivo\n\nPermitir que el frontend pueda:\n\n* Mostrar referencias filtrables por documento.\n* Mostrar, para cada referencia, la cita textual exacta utilizada por el modelo.\n\n\n",
        "tableName": {
          "__rl": true,
          "value": "documentos",
          "mode": "list",
          "cachedResultName": "documentos"
        },
        "topK": 15,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1.3,
      "position": [
        1376,
        912
      ],
      "id": "d4a5391d-282c-4289-951f-f6dc108767e1",
      "name": "Supabase Vector Store",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Rename Keys": {
      "main": [
        [
          {
            "node": "ResponderMapaMental",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent4",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent4": {
      "main": [
        [
          {
            "node": "Rename Keys",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser1": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent4",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Mental Map": {
      "main": [
        [
          {
            "node": "AI Agent4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "AI Agent1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "339d4554-2b2a-4b2d-91a8-3cf38f2dc053",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "ONprJffczvwsSkj0",
  "tags": []
}