{
  "name": "ALLSoft — Respuestas a reseñas",
  "nodes": [
    {
      "parameters": {},
      "name": "Cuando llega una reseña",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -620,
        300
      ],
      "notes": "Cámbialo por el nodo de Google Business Profile o un Webhook de tu plataforma de reseñas.",
      "id": "re5e-0001-4000-8000-000000000001"
    },
    {
      "parameters": {
        "jsCode": "// Reseñas nuevas. Sustituye este bloque por el nodo de Google Business\n// Profile, un webhook o la API de la plataforma donde te reseñen.\nconst resenas = [\n  { autor: 'Camila Ruiz',    estrellas: 5, texto: 'Excelente atención, me resolvieron todo el mismo día. Muy recomendados.' },\n  { autor: 'Hernán Díaz',    estrellas: 2, texto: 'Llegué a la hora y me hicieron esperar 40 minutos. Nadie me avisó nada.' },\n  { autor: 'Paola Martínez', estrellas: 4, texto: 'Buen servicio, aunque el parqueadero es complicado a esa hora.' },\n  { autor: 'Luis Ortega',    estrellas: 1, texto: 'Me cobraron de más y todavía no me devuelven el dinero. Pésimo.' },\n];\n\nreturn resenas.map((r) => ({\n  json: {\n    ...r,\n    nombre: r.autor.split(' ')[0],\n    // 3 estrellas o menos es una queja: esas NUNCA se publican solas.\n    esQueja: r.estrellas <= 3,\n  },\n}));\n"
      },
      "name": "Reseñas nuevas",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -400,
        300
      ],
      "notes": "Reemplaza por tu fuente real de reseñas.",
      "id": "re5e-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.7, max_tokens: 160, messages: [ { role: 'system', content: 'Eres quien responde reseñas de un negocio en Colombia. Escribe una respuesta publica, breve (maximo 45 palabras), en tu-teo y sin sonar a plantilla. Si la resena es negativa: reconoce el problema, no discutas, no des excusas y ofrece continuar por privado. NUNCA prometas devoluciones, descuentos ni compensaciones. No uses emojis.' }, { role: 'user', content: 'Resena de ' + $json.nombre + ' (' + $json.estrellas + ' estrellas): ' + $json.texto } ] }) }}",
        "options": {}
      },
      "name": "Redactar respuesta (Groq)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -160,
        300
      ],
      "onError": "continueErrorOutput",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "notes": "Redacta el borrador. Las reseñas negativas nunca se publican sin que alguien las lea.",
      "id": "re5e-0003-4000-8000-000000000003"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Prepara el borrador de respuesta. Corre una vez por reseña.\n//\n// DECISIÓN IMPORTANTE: una reseña negativa NUNCA se publica automáticamente.\n// El modelo redacta el borrador, pero lo revisa una persona antes de salir.\n// Una respuesta torpe a una queja pública hace más daño que no responder.\nconst resena = $('Reseñas nuevas').item.json;\n\nlet borrador;\ntry {\n  borrador = $input.item.json.choices[0].message.content.trim();\n} catch (e) {\n  borrador = '';\n}\n\nborrador = borrador.replace(/^[\"']|[\"']$/g, '').slice(0, 600);\n\n// Señales de que conviene que lo mire un humano aunque sean 4-5 estrellas\nconst prometeAlgo = /(devolv|reembols|garant|indemniz|compensa|descuento)/i.test(\n  resena.texto + ' ' + borrador\n);\n\nconst revisar = resena.esQueja || prometeAlgo || borrador.length < 30;\n\nreturn {\n  json: {\n    autor: resena.autor,\n    estrellas: resena.estrellas,\n    resena: resena.texto,\n    borrador,\n    revisar,\n    motivo: resena.esQueja\n      ? 'Es una queja (3 estrellas o menos)'\n      : prometeAlgo\n        ? 'Menciona dinero o garantías'\n        : borrador.length < 30\n          ? 'El borrador salió demasiado corto'\n          : '',\n  },\n};\n"
      },
      "name": "Preparar borrador",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        80,
        200
      ],
      "notes": "Marca qué respuestas necesitan revisión humana antes de publicarse.",
      "id": "re5e-0004-4000-8000-000000000004"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "version": 2
          },
          "conditions": [
            {
              "id": "rev1",
              "leftValue": "={{ $json.revisar }}",
              "rightValue": "={{ true }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "¿Necesita que alguien la lea?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        300,
        200
      ],
      "notes": "Quejas, menciones de dinero o borradores muy cortos van a revisión.",
      "id": "re5e-0005-4000-8000-000000000005"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "r1",
              "name": "estado",
              "value": "revisar_antes_de_publicar",
              "type": "string"
            },
            {
              "id": "r2",
              "name": "autor",
              "value": "={{ $json.autor }}",
              "type": "string"
            },
            {
              "id": "r3",
              "name": "estrellas",
              "value": "={{ $json.estrellas }}",
              "type": "number"
            },
            {
              "id": "r4",
              "name": "motivo",
              "value": "={{ $json.motivo }}",
              "type": "string"
            },
            {
              "id": "r5",
              "name": "borrador",
              "value": "={{ $json.borrador }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "A revisión humana",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        540,
        120
      ],
      "notes": "Engánchalo a Slack o a un correo interno. Alguien aprueba y publica.",
      "id": "re5e-0006-4000-8000-000000000006"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "p1",
              "name": "estado",
              "value": "lista_para_publicar",
              "type": "string"
            },
            {
              "id": "p2",
              "name": "autor",
              "value": "={{ $json.autor }}",
              "type": "string"
            },
            {
              "id": "p3",
              "name": "respuesta",
              "value": "={{ $json.borrador }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "Lista para publicar",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        540,
        300
      ],
      "notes": "Reseñas positivas y sin compromisos. Conéctalo a la API de tu plataforma si quieres publicarlas solo.",
      "id": "re5e-0007-4000-8000-000000000007"
    },
    {
      "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": [
        80,
        440
      ],
      "notes": "Salida de error del nodo de IA: el flujo no se cae, avisa.",
      "id": "re5e-0008-4000-8000-000000000008"
    }
  ],
  "connections": {
    "Cuando llega una reseña": {
      "main": [
        [
          {
            "node": "Reseñas nuevas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reseñas nuevas": {
      "main": [
        [
          {
            "node": "Redactar respuesta (Groq)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Redactar respuesta (Groq)": {
      "main": [
        [
          {
            "node": "Preparar borrador",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Avisar del fallo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar borrador": {
      "main": [
        [
          {
            "node": "¿Necesita que alguien la lea?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "¿Necesita que alguien la lea?": {
      "main": [
        [
          {
            "node": "A revisión humana",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lista para publicar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "instanceId": "allsoft-academia"
  },
  "tags": []
}
