{
  "name": "ALLSoft — Encuesta de satisfacción",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "encuesta",
        "responseMode": "responseNode",
        "options": {}
      },
      "name": "Llega una respuesta",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -680,
        300
      ],
      "webhookId": "3ncu35t4-0000-4000-8000-000000000001",
      "notes": "Conéctalo a tu formulario. Espera { cliente, servicio, nota, comentario }.",
      "id": "3ncu-0001-4000-8000-000000000001"
    },
    {
      "parameters": {
        "jsCode": "// Normaliza la respuesta que llega del formulario o del mensaje.\n// Espera { cliente, servicio, nota, comentario } — la nota de 1 a 5.\nconst e = $input.first().json;\nconst cuerpo = e.body || e;\n\nconst nota = Number(cuerpo.nota);\n\nreturn [{\n  json: {\n    cliente: cuerpo.cliente || 'Cliente',\n    servicio: cuerpo.servicio || 'el servicio',\n    nota: Number.isFinite(nota) ? nota : null,\n    comentario: (cuerpo.comentario || '').slice(0, 800),\n    // Sin comentario no hay nada que interpretar: la nota sola ya decide\n    tieneComentario: Boolean((cuerpo.comentario || '').trim()),\n  },\n}];\n"
      },
      "name": "Respuesta de la encuesta",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -460,
        300
      ],
      "id": "3ncu-0002-4000-8000-000000000002"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer TU_GROQ_API_KEY"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'llama-3.3-70b-versatile', temperature: 0.2, max_tokens: 200, response_format: { type: 'json_object' }, messages: [ { role: 'system', content: 'Lees el comentario de un cliente sobre un servicio recibido. Devuelve SOLO un JSON con esta forma: {\"tema\":\"\",\"resumen\":\"\"}. tema = de que se queja o que destaca, en 3 palabras. resumen = una frase. NO decidas si es urgente: eso lo define la calificacion, no tu.' }, { role: 'user', content: 'Calificacion: ' + $json.nota + ' de 5. Comentario: ' + ($json.comentario || 'sin comentario') } ] }) }}",
        "options": {}
      },
      "name": "Entender el comentario (Groq)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -220,
        300
      ],
      "onError": "continueErrorOutput",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "notes": "Solo interpreta. Si es urgente lo decide la nota, no el modelo.",
      "id": "3ncu-0003-4000-8000-000000000003"
    },
    {
      "parameters": {
        "jsCode": "// Decide qué hacer con la respuesta de la encuesta.\n//\n// La NOTA manda. El modelo aporta el resumen y el tema, pero quien decide si\n// esto es una alerta es el número, no una interpretación. Un cliente que puso\n// 2 está molesto aunque haya escrito \"gracias, todo bien\" por cortesía.\nconst r = $('Respuesta de la encuesta').first().json;\n\nlet analisis = {};\ntry {\n  analisis = JSON.parse($input.first().json.choices[0].message.content);\n} catch (e) {\n  analisis = {};\n}\n\nconst nota = r.nota;\nconst urgente = nota !== null && nota <= 3;\n\n// Palabras que convierten cualquier nota en alerta, aunque sea un 5\nconst grave = /(demand|abogad|denunci|robo|estaf|nunca m[aá]s|p[eé]sim|terrible)/i\n  .test(r.comentario);\n\nreturn [{\n  json: {\n    cliente: r.cliente,\n    servicio: r.servicio,\n    nota,\n    comentario: r.comentario,\n    tema: (analisis.tema || 'sin clasificar').slice(0, 60),\n    resumen: (analisis.resumen || '').slice(0, 300),\n    urgente: urgente || grave,\n    // Solo se le pide reseña pública a quien quedó contento de verdad\n    pedirResena: nota !== null && nota >= 5 && !grave,\n    motivo: grave\n      ? 'El comentario tiene lenguaje grave'\n      : urgente\n        ? `Calificó ${nota} de 5`\n        : '',\n  },\n}];\n"
      },
      "name": "Decidir qué hacer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        20,
        200
      ],
      "notes": "La nota manda. 3 o menos es alerta aunque el comentario suene amable.",
      "id": "3ncu-0004-4000-8000-000000000004"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "version": 2
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.urgente }}",
              "rightValue": "={{ true }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "¿Hay que atenderlo ya?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        240,
        200
      ],
      "notes": "Un cliente molesto que espera dos días se vuelve una reseña de una estrella.",
      "id": "3ncu-0005-4000-8000-000000000005"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "u1",
              "name": "estado",
              "value": "ALERTA_llamar_hoy",
              "type": "string"
            },
            {
              "id": "u2",
              "name": "cliente",
              "value": "={{ $json.cliente }}",
              "type": "string"
            },
            {
              "id": "u3",
              "name": "nota",
              "value": "={{ $json.nota }}",
              "type": "number"
            },
            {
              "id": "u4",
              "name": "tema",
              "value": "={{ $json.tema }}",
              "type": "string"
            },
            {
              "id": "u5",
              "name": "resumen",
              "value": "={{ $json.resumen }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "Alerta al equipo",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        480,
        120
      ],
      "notes": "Engánchalo a Slack o a un SMS. Esto no puede esperar al informe semanal.",
      "id": "3ncu-0006-4000-8000-000000000006"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b1",
              "name": "estado",
              "value": "contento",
              "type": "string"
            },
            {
              "id": "b2",
              "name": "pedirResena",
              "value": "={{ $json.pedirResena }}",
              "type": "boolean"
            },
            {
              "id": "b3",
              "name": "cliente",
              "value": "={{ $json.cliente }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "Registrar y pedir reseña",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        480,
        300
      ],
      "notes": "Solo a quien puso 5. Pedirle reseña a quien puso 3 es buscarse una mala pública.",
      "id": "3ncu-0007-4000-8000-000000000007"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "Gracias por responder.",
        "options": {}
      },
      "name": "Responder al formulario",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        720,
        200
      ],
      "id": "3ncu-0008-4000-8000-000000000008"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "e1",
              "name": "estado",
              "value": "error_ia",
              "type": "string"
            },
            {
              "id": "e2",
              "name": "detalle",
              "value": "={{ $json.error || 'Groq no respondió' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "Avisar del fallo",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        20,
        440
      ],
      "notes": "Salida de error del nodo de IA: el flujo no se cae, avisa.",
      "id": "3ncu-0009-4000-8000-000000000009"
    }
  ],
  "connections": {
    "Llega una respuesta": {
      "main": [
        [
          {
            "node": "Respuesta de la encuesta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respuesta de la encuesta": {
      "main": [
        [
          {
            "node": "Entender el comentario (Groq)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Entender el comentario (Groq)": {
      "main": [
        [
          {
            "node": "Decidir qué hacer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Avisar del fallo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decidir qué hacer": {
      "main": [
        [
          {
            "node": "¿Hay que atenderlo ya?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "¿Hay que atenderlo ya?": {
      "main": [
        [
          {
            "node": "Alerta al equipo",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Registrar y pedir reseña",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alerta al equipo": {
      "main": [
        [
          {
            "node": "Responder al formulario",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registrar y pedir reseña": {
      "main": [
        [
          {
            "node": "Responder al formulario",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "instanceId": "allsoft-academia"
  },
  "tags": []
}
