{"id":247,"date":"2025-03-25T07:03:57","date_gmt":"2025-03-25T07:03:57","guid":{"rendered":"https:\/\/neocloud05.com\/neo\/?page_id=247"},"modified":"2025-03-27T19:15:22","modified_gmt":"2025-03-27T19:15:22","slug":"laboratorio-2-0-4-modelo-conversacional-perfiles-anexos","status":"publish","type":"page","link":"https:\/\/neocloud05.com\/neo\/laboratorio-2-0-4-modelo-conversacional-perfiles-anexos\/","title":{"rendered":"Laboratorio 2.0.4 Modelo Conversacional Perfiles Anexos"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"247\" class=\"elementor elementor-247\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dead8d3 e-flex e-con-boxed e-con e-parent\" data-id=\"dead8d3\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-41ce17a elementor-widget elementor-widget-heading\" data-id=\"41ce17a\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Neo 2.0 Beta<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b037d9f e-flex e-con-boxed e-con e-parent\" data-id=\"b037d9f\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-69fe3d2 elementor-widget elementor-widget-html\" data-id=\"69fe3d2\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\/>\n  <title>Asistente AI con Voz Continua<\/title>\n  <style>\n    body {\n      background: #f0f2f5;\n      font-family: 'Segoe UI', sans-serif;\n      margin: 0;\n      padding: 20px;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n    }\n\n    .chat-container {\n      background: #fff;\n      width: 100%;\n      max-width: 600px;\n      height: 80vh;\n      border-radius: 12px;\n      box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n    }\n\n    .chat-header {\n      color: white;\n      padding: 16px;\n      font-size: 18px;\n      font-weight: bold;\n      transition: background-color 0.4s ease;\n    }\n\n    .bg-general { background-color: #4f46e5; }\n\n    .chat-body {\n      flex: 1;\n      padding: 16px;\n      overflow-y: auto;\n      background: #f9fafb;\n    }\n\n    .message {\n      margin-bottom: 12px;\n      display: flex;\n      align-items: flex-start;\n      gap: 10px;\n    }\n\n    .user { flex-direction: row-reverse; text-align: right; }\n\n    .message p {\n      display: inline-block;\n      padding: 10px 14px;\n      border-radius: 20px;\n      max-width: 80%;\n      margin: 0;\n    }\n\n    .user p { background: #4f46e5; color: white; }\n    .bot p { background: #e5e7eb; color: #111827; }\n\n    .message-avatar {\n      width: 40px;\n      height: 40px;\n      border-radius: 50%;\n      background-color: #d1d5db;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      font-size: 20px;\n      flex-shrink: 0;\n    }\n\n    .user .message-avatar { background-color: #4f46e5; color: white; }\n    .bot .message-avatar { background-color: #e5e7eb; color: #111827; }\n\n    .timestamp {\n      display: block;\n      font-size: 11px;\n      color: #6b7280;\n      margin-top: 4px;\n      padding-left: 6px;\n    }\n\n    #drop-zone {\n      border: 2px dashed #ccc;\n      padding: 20px;\n      margin-top: 20px;\n      border-radius: 12px;\n      text-align: center;\n      color: #6b7280;\n    }\n\n    #drop-zone.dragover {\n      border-color: #10b981;\n      background-color: #ecfdf5;\n      color: #065f46;\n      transition: 0.3s ease;\n    }\n  <\/style>\n<\/head>\n<body>\n\n<div class=\"chat-container\">\n  <div class=\"chat-header bg-general\" id=\"chat-title\">\ud83e\udd16 Asistente IA<\/div>\n  <div class=\"chat-body\" id=\"chat-body\"><\/div>\n  <div class=\"chat-input\">\n    <input type=\"text\" id=\"user-input\" placeholder=\"Escribe o habla tu mensaje...\" \/>\n    <button onclick=\"sendMessage()\">Enviar<\/button>\n  <\/div>\n<\/div>\n\n<div style=\"margin-top: 15px;\">\n  <div class=\"upload-container\" style=\"display: flex; justify-content: center;\">\n    <label for=\"file-upload\" class=\"upload-label\" style=\"background: #e5e7eb; padding: 10px 20px; border-radius: 20px; color: #374151; font-weight: bold; cursor: pointer; transition: background 0.3s;\">\n      \ud83d\udcc2 Cargar archivo (texto, PDF, imagen, Excel...)\n    <\/label>\n    <input type=\"file\" id=\"file-upload\" multiple style=\"display: none;\" accept=\".txt,.pdf,.csv,.xlsx,.xls,.docx,.jpg,.jpeg,.png,.webp\" \/>\n  <\/div>\n\n  <div id=\"drop-zone\">\n    \ud83d\ude80 Arrastra y suelta tus archivos aqu\u00ed o p\u00e9galos directamente\n  <\/div>\n<\/div>\n\n<script>\n  const fileInput = document.getElementById('file-upload');\n  const chatBody = document.getElementById('chat-body');\n\n  function appendMessage(sender, content, isHTML = false) {\n    const messageDiv = document.createElement('div');\n    messageDiv.className = `message ${sender}`;\n\n    const avatar = document.createElement('div');\n    avatar.className = 'message-avatar';\n    avatar.textContent = sender === 'user' ? '\ud83e\uddd1' : '\ud83e\udd16';\n\n    const messageText = document.createElement('div');\n    messageText.style.maxWidth = '80%';\n\n    if (isHTML) {\n      messageText.innerHTML = content;\n    } else {\n      const p = document.createElement('p');\n      p.innerText = content;\n      messageText.appendChild(p);\n    }\n\n    const time = document.createElement('span');\n    time.className = 'timestamp';\n    const ahora = new Date();\n    time.innerText = ahora.toLocaleDateString('es-ES') + ' ' + ahora.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });\n\n    messageDiv.appendChild(avatar);\n    messageDiv.appendChild(messageText);\n    messageDiv.appendChild(time);\n    chatBody.appendChild(messageDiv);\n    chatBody.scrollTop = chatBody.scrollHeight;\n  }\n\n  function obtenerIconoPorTipo(mimeType, nombreArchivo) {\n    if (mimeType.startsWith('image\/')) return '\ud83d\uddbc\ufe0f';\n    if (mimeType === 'application\/pdf') return '\ud83d\udcc4';\n    if (mimeType.includes('word') || nombreArchivo.endsWith('.docx')) return '\ud83d\udcc3';\n    if (mimeType.includes('excel') || nombreArchivo.endsWith('.xls') || nombreArchivo.endsWith('.xlsx')) return '\ud83d\udcca';\n    if (mimeType === 'text\/plain' || nombreArchivo.endsWith('.txt')) return '\ud83d\udcc4';\n    if (mimeType.includes('csv')) return '\ud83d\udccb';\n    return '\ud83d\udcc1';\n  }\n\n  function procesarArchivos(archivos) {\n    [...archivos].forEach(file => {\n      const icono = obtenerIconoPorTipo(file.type, file.name);\n      appendMessage('user', `${icono} Archivo cargado: ${file.name}`);\n\n      if (file.type.startsWith('image\/')) {\n        const reader = new FileReader();\n        reader.onload = function (e) {\n          const vistaHTML = `\n            <div style=\"display: flex; align-items: center; gap: 10px; margin-top: 10px;\">\n              <img decoding=\"async\" src=\"${e.target.result}\" alt=\"Imagen\" style=\"width: 80px; height: 80px; object-fit: cover; border-radius: 8px; border: 1px solid #ccc;\" \/>\n              <span style=\"font-size: 14px; color: #4b5563;\">${file.name}<\/span>\n            <\/div>\n          `;\n          appendMessage('user', vistaHTML, true);\n        };\n        reader.readAsDataURL(file);\n      }\n    });\n  }\n\n  fileInput.addEventListener('change', () => {\n    if (fileInput.files.length) {\n      procesarArchivos(fileInput.files);\n    }\n  });\n\n  const dropZone = document.getElementById('drop-zone');\n\n  dropZone.addEventListener('dragover', (e) => {\n    e.preventDefault();\n    dropZone.classList.add('dragover');\n  });\n\n  dropZone.addEventListener('dragleave', () => {\n    dropZone.classList.remove('dragover');\n  });\n\n  dropZone.addEventListener('drop', (e) => {\n    e.preventDefault();\n    dropZone.classList.remove('dragover');\n\n    if (e.dataTransfer.files.length) {\n      procesarArchivos(e.dataTransfer.files);\n    }\n  });\n\n  document.addEventListener('paste', (event) => {\n    const items = event.clipboardData.items;\n    for (let item of items) {\n      if (item.kind === 'file') {\n        const file = item.getAsFile();\n        if (file) {\n          procesarArchivos([file]);\n        }\n      }\n    }\n  });\n<\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9f96e12 e-flex e-con-boxed e-con e-parent\" data-id=\"9f96e12\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ef60ff3 elementor-widget elementor-widget-html\" data-id=\"ef60ff3\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\/>\n  <title>Asistente AI con Voz Continua<\/title>\n  <style>\n    body {\n      background: #f0f2f5;\n      font-family: 'Segoe UI', sans-serif;\n      margin: 0;\n      padding: 20px;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n    }\n\n    .chat-container {\n      background: #fff;\n      width: 100%;\n      max-width: 600px;\n      height: 80vh;\n      border-radius: 12px;\n      box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n    }\n\n    .chat-header {\n      color: white;\n      padding: 16px;\n      font-size: 18px;\n      font-weight: bold;\n      transition: background-color 0.4s ease;\n    }\n    \n    .bg-general { background-color: #4f46e5; }         \/* Morado *\/\n    .bg-educador { background-color: #2563eb; }        \/* Azul *\/\n    .bg-coach { background-color: #f59e0b; }           \/* Naranja *\/\n    .bg-psicologo { background-color: #6366f1; }       \/* \u00cdndigo *\/\n    .bg-ejecutivo { background-color: #111827; }       \/* Gris oscuro *\/\n    .bg-cliente { background-color: #10b981; }         \/* Verde *\/\n    .bg-soporte { background-color: #6b7280; }         \/* Gris medio *\/\n    .bg-entrenador { background-color: #ef4444; }      \/* Rojo *\/\n    .bg-neuro { background-color: #7c3aed; }           \/* Violeta *\/\n    .bg-nutricionista { background-color: #22c55e; }   \/* Verde lima *\/\n\n    .chat-body {\n      flex: 1;\n      padding: 16px;\n      overflow-y: auto;\n      background: #f9fafb;\n    }\n\n    .message {\n      margin-bottom: 12px;\n    }\n\n    .user {\n      text-align: right;\n    }\n\n    .bot {\n      text-align: left;\n    }\n\n    .message p {\n      display: inline-block;\n      padding: 10px 14px;\n      border-radius: 20px;\n      max-width: 80%;\n    }\n\n    .user p {\n      background: #4f46e5;\n      color: white;\n    }\n\n    .bot p {\n      background: #e5e7eb;\n      color: #111827;\n    }\n\n    .chat-input {\n      display: flex;\n      padding: 10px;\n      border-top: 1px solid #e5e7eb;\n      background: #fff;\n    }\n\n    .chat-input input {\n      flex: 1;\n      padding: 10px;\n      border: 1px solid #d1d5db;\n      border-radius: 8px;\n      margin-right: 10px;\n      font-size: 16px;\n    }\n\n    .chat-input button {\n      padding: 10px;\n      background: #4f46e5;\n      color: white;\n      border: none;\n      border-radius: 8px;\n      cursor: pointer;\n      font-weight: bold;\n      margin-left: 5px;\n    }\n\n    .chat-input button:hover {\n      background: #4338ca;\n    }\n\n    .voice-controls {\n      margin-top: 15px;\n      display: flex;\n      gap: 10px;\n      flex-wrap: wrap;\n    }\n\n    .test-voice-button, .continuous-button {\n      padding: 10px 20px;\n      font-weight: bold;\n      background: #10b981;\n      color: white;\n      border: none;\n      border-radius: 8px;\n      cursor: pointer;\n    }\n\n    .test-voice-button:hover, .continuous-button:hover {\n      background: #059669;\n    }\n\n    #voiceSelect {\n      padding: 8px;\n      border-radius: 6px;\n      font-size: 14px;\n      margin-top: 10px;\n    }\n\n    .voice-status {\n      margin-top: 8px;\n      font-size: 14px;\n      color: green;\n      font-weight: bold;\n      display: none;\n    }\n    \n    .timestamp {\n      display: block;\n      font-size: 11px;\n      color: #6b7280;\n      margin-top: 4px;\n      padding-left: 6px;\n    }\n    \n    .message {\n      display: flex;\n      align-items: flex-start;\n      gap: 10px;\n    }\n    \n    .user {\n      flex-direction: row-reverse;\n      text-align: right;\n    }\n    \n    .message-avatar {\n      width: 40px;\n      height: 40px;\n      border-radius: 50%;\n      background-color: #d1d5db;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      font-size: 20px;\n      flex-shrink: 0;\n    }\n    \n    .user .message-avatar {\n      background-color: #4f46e5;\n      color: white;\n    }\n    \n    .bot .message-avatar {\n      background-color: #e5e7eb;\n      color: #111827;\n    }\n    \n    .message p {\n      margin: 0;\n    }\n    \n    #voz-status {\n      animation: pulse 1.5s infinite;\n    }\n    \n    @keyframes pulse {\n      0% { opacity: 1; }\n      50% { opacity: 0.4; }\n      100% { opacity: 1; }\n    }\n\n  <\/style>\n<\/head>\n<body>\n<div style=\"margin-top: 15px;\">\n  <label for=\"profileSelect\"><strong>Selecciona un perfil profesional del asistente:<\/strong><\/label>\n  <select id=\"profileSelect\">\n    <option value=\"asistente_general\">\ud83e\udd16Asistente General<\/option>\n    <option value=\"educador\">\ud83d\udc68\u200d\ud83c\udfeb Educador<\/option>\n    <option value=\"coach\">\ud83c\udfaf Coach<\/option>\n    <option value=\"psicologo\">\ud83e\udde0 Psic\u00f3logo<\/option>\n    <option value=\"ejecutivo_cuenta\">\ud83d\udcbc Ejecutivo de Cuenta<\/option>\n    <option value=\"servicio_cliente\">\ud83d\udcde Servicio al Cliente<\/option>\n    <option value=\"soporte_tecnico\">\ud83d\udee0\ufe0f Soporte T\u00e9cnico<\/option>\n    <option value=\"entrenador_personal\">\ud83c\udfcb\ufe0f Entrenador Personal<\/option>\n    <option value=\"neurocientifico\">\ud83e\uddec Neurocient\u00edfico<\/option>\n    <option value=\"nutricionista\">\ud83e\udd57 Nutricionista<\/option>\n  <\/select>\n<\/div>\n\n  <div class=\"chat-container\">\n    <div class=\"chat-header\" id=\"chat-title\">\ud83e\udd16 Asistente IA con Voz<\/div>\n      <div id=\"voz-status\" style=\"display: none; text-align: center; padding: 8px; font-size: 14px; color: #10b981; font-weight: bold;\">\n        \ud83d\udd0a El asistente est\u00e1 hablando...\n    <\/div>\n    <div class=\"chat-body\" id=\"chat-body\" style=\"padding: 20px;\"><\/div>\n    <div class=\"chat-input\">\n      <input type=\"text\" id=\"user-input\" placeholder=\"Escribe o habla tu mensaje...\" \/>\n      <button onclick=\"sendMessage()\">Enviar<\/button>\n      <button id=\"mic-button\" title=\"Hablar por micr\u00f3fono\">\ud83c\udf99\ufe0f<\/button>\n    <\/div>\n  <\/div>\n  \n  \n<!-- **************************************************************** -->  \n\n\n<div class=\"upload-container\" style=\"margin-top: 15px; display: flex; justify-content: center;\">\n  <label for=\"file-upload\" class=\"upload-label\" style=\"background: #e5e7eb; padding: 10px 20px; border-radius: 20px; color: #374151; font-weight: bold; cursor: pointer; transition: background 0.3s;\">\n    \ud83d\udcc2 Cargar archivo (texto, PDF, imagen, Excel...)\n  <\/label>\n  <input type=\"file\" id=\"file-upload\" style=\"display: none;\" accept=\".txt,.pdf,.csv,.xlsx,.xls,.docx,.jpg,.jpeg,.png,.webp\" \/>\n<\/div>\n\n<!-- Librer\u00eda PDF.js para leer PDFs en el navegador -->\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.4.120\/pdf.min.js\"><\/script>\n<!-- Librer\u00eda para gr\u00e1ficos -->\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\n<!-- Librer\u00edas para procesar DOCX y XLSX -->\n<script src=\"https:\/\/unpkg.com\/mammoth\/mammoth.browser.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\n\n<script>\n  const fileInput = document.getElementById('file-upload');\n  fileInput.addEventListener('change', () => {\n    const file = fileInput.files[0];\n    if (!file) return;\n\n    const fileName = file.name;\n    appendMessage('user', \ud83d\udcc2 Has cargado: ${fileName});\n\n    const reader = new FileReader();\n\n    if (file.type === \"text\/plain\") {\n      reader.onload = async (e) => {\n        const fileContent = e.target.result;\n        const prompt = He subido un archivo llamado \"${file.name}\". Aqu\u00ed est\u00e1 el contenido completo:\\n\\n${fileContent}\\n\\nPor favor, analiza este texto y proporciona un resumen claro y estructurado.;\n        appendMessage('user', prompt);\n        await sendMessage(prompt);\n      };\n      reader.readAsText(file);\n\n    } else if (file.type === \"application\/pdf\") {\n      reader.onload = async (e) => {\n        const typedarray = new Uint8Array(e.target.result);\n        const pdf = await pdfjsLib.getDocument({ data: typedarray }).promise;\n        let textContent = '';\n        for (let i = 1; i <= pdf.numPages; i++) {\n          const page = await pdf.getPage(i);\n          const content = await page.getTextContent();\n          const pageText = content.items.map(item => item.str).join(' ');\n          textContent += \\n\\n[Pagina ${i}]\\n${pageText};\n        }\n        const prompt = He subido un archivo PDF llamado \"${file.name}\". Aqu\u00ed est\u00e1 el contenido extra\u00eddo:\\n\\n${textContent}\\n\\nPor favor, analiza este documento y proporciona un resumen claro y estructurado.;\n        appendMessage('user', prompt);\n        await sendMessage(prompt);\n      };\n      reader.readAsArrayBuffer(file);\n\n    } else if (file.type === \"text\/csv\") {\n      reader.onload = async (e) => {\n        const csvContent = e.target.result;\n        const prompt = He subido un archivo CSV llamado \"${file.name}\". Aqu\u00ed est\u00e1n los datos:\\n\\n${csvContent}\\n\\nPor favor, analiza la informaci\u00f3n y proporciona un resumen o conclusiones.;\n        appendMessage('user', prompt);\n        await sendMessage(prompt);\n      };\n      reader.readAsText(file);\n\n    } else if (file.name.endsWith('.docx')) {\n      reader.onload = async (e) => {\n        const arrayBuffer = e.target.result;\n        try {\n          const result = await mammoth.convertToHtml({ arrayBuffer });\n          const textContent = result.value.replace(\/<[^>]+>\/g, '');\n          const prompt = He subido un archivo Word (.docx) llamado \"${file.name}\". Aqu\u00ed est\u00e1 el contenido extra\u00eddo:\\n\\n${textContent}\\n\\nPor favor, analiza este documento y proporciona un resumen claro y estructurado.;\n          appendMessage('user', prompt);\n          await sendMessage(prompt);\n        } catch (error) {\n          appendMessage('bot', '\u274c No se pudo procesar el archivo Word.');\n          console.error(error);\n        }\n      };\n      reader.readAsArrayBuffer(file);\n\n    } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {\n      reader.onload = async (e) => {\n        try {\n          const data = new Uint8Array(e.target.result);\n          const workbook = XLSX.read(data, { type: 'array' });\n          let textContent = '';\n          workbook.SheetNames.forEach(sheetName => {\n            const sheet = workbook.Sheets[sheetName];\n            const csv = XLSX.utils.sheet_to_csv(sheet);\n            const cleanedCsv = csv.replace(\/[\\r\\t]+\/g, ' ').replace(\/\"\/g, '').replace(\/\\n{2,}\/g, '\\n');\n            textContent += \\n\\n[Hoja: ${sheetName}]\\n${cleanedCsv};\n          });\n          if (!textContent || textContent.trim().length < 50) {\n            appendMessage('bot', '\u26a0\ufe0f El archivo Excel no contiene datos legibles o est\u00e1 vac\u00edo.');\n            return;\n          } else if (textContent.length > 10000) {\n            appendMessage('bot', '\u26a0\ufe0f El archivo Excel es muy grande para analizarlo completo.');\n            return;\n          }\n          const prompt = He subido un archivo Excel llamado \"${file.name}\". Aqu\u00ed est\u00e1n los datos extra\u00eddos:\\n\\n${textContent}\\n\\nPor favor analiza el archivo y proporciona insights.;\n          appendMessage('user', prompt);\n          await sendMessage(prompt);\n        } catch (err) {\n          appendMessage('bot', '\u274c No se pudo procesar el archivo Excel.');\n          console.error(err);\n        }\n      };\n      reader.readAsArrayBuffer(file);\n\n    } else if (file.type.startsWith('image\/')) {\n        const reader = new FileReader();\n        reader.onload = function (e) {\n          const imgHTML = \n            <div style=\"display: flex; align-items: center; gap: 10px; margin-top: 10px;\">\n              <img decoding=\"async\" src=\"${e.target.result}\" alt=\"Imagen cargada\" style=\"width: 60px; height: 60px; object-fit: cover; border-radius: 8px; box-shadow: 0 0 4px rgba(0,0,0,0.2); border: 1px solid #ccc;\" \/>\n              <span style=\"font-size: 14px; color: #4b5563;\">\ud83d\uddbc\ufe0f Imagen cargada correctamente<\/span>\n            <\/div>\n          ;\n          appendMessage('user', imgHTML, true);\n        };\n        reader.readAsDataURL(file);\n      } else {\n      appendMessage('bot', '\u274c Formato no soportado.');\n    }\n  });\n\n<!-- ************************************************************ -->\n\n  function appendMessage(sender, content, isHTML = false) {\n      const messageDiv = document.createElement('div');\n      messageDiv.className = message ${sender};\n\n      const avatar = document.createElement('div');\n      avatar.className = 'message-avatar';\n      avatar.textContent = sender === 'user' ? '\ud83e\uddd1' : '\ud83e\udd16';\n\n      const messageText = document.createElement('div');\n      messageText.style.maxWidth = '80%';\n\n      if (isHTML) {\n        messageText.innerHTML = content;\n      } else {\n        const p = document.createElement('p');\n        p.innerText = content;\n        messageText.appendChild(p);\n      }\n\n      const time = document.createElement('span');\n      time.className = 'timestamp';\n      const ahora = new Date();\n      time.innerText = ahora.toLocaleDateString('es-ES') + ' ' + ahora.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });\n\n      messageDiv.appendChild(avatar);\n      messageDiv.appendChild(messageText);\n      messageDiv.appendChild(time);\n      chatBody.appendChild(messageDiv);\n      chatBody.scrollTop = chatBody.scrollHeight;\n    }\n    \n\n<!-- ************************************************************ -->\n    \n    \n<\/script>\n\n\n<!-- **************************************************************** -->  \n\n\n\n  <div class=\"voice-controls\">\n    <button class=\"test-voice-button\" onclick=\"probarVoz()\">\ud83d\udd0a Probar Voz<\/button>\n    <button class=\"continuous-button\" id=\"toggle-continuous\">\ud83c\udfa4 Activar Conversaci\u00f3n<\/button>\n  <\/div>\n\n  <div>\n    <label for=\"voiceSelect\"><strong>Selecciona una voz:<\/strong><\/label>\n    <select id=\"voiceSelect\"><\/select>\n    <div id=\"voiceSavedMsg\" class=\"voice-status\">\u2705 Voz guardada correctamente<\/div>\n  <\/div>\n<div style=\"margin-top: 10px;\">\n  <button onclick=\"borrarHistorial()\" style=\"padding: 8px 16px; background: #ef4444; color: white; border: none; border-radius: 6px; cursor: pointer;\">\ud83d\uddd1\ufe0f Borrar historial<\/button>\n<\/div>\n  <script>\n    const chatBody = document.getElementById('chat-body');\n    const userInput = document.getElementById('user-input');\n    const micButton = document.getElementById('mic-button');\n    const toggleContinuous = document.getElementById('toggle-continuous');\n    const voiceSelect = document.getElementById('voiceSelect');\n    const voiceSavedMsg = document.getElementById('voiceSavedMsg');\n\n    let chatHistory = [];\n    let voces = [];\n    let continuousMode = false;\n    let speaking = false;\n\n    const recognition = window.SpeechRecognition ? new SpeechRecognition() : new webkitSpeechRecognition();\n    recognition.lang = 'es-ES';\n    recognition.interimResults = false;\n    recognition.continuous = false;\n\n    speechSynthesis.onvoiceschanged = () => {\n      voces = speechSynthesis.getVoices().filter(v => v.lang.includes('es'));\n\n      const addedNames = new Set();\n      voiceSelect.innerHTML = '';\n\n      voces.forEach((voz, index) => {\n        if (!addedNames.has(voz.name)) {\n          const option = document.createElement('option');\n          option.value = index;\n          option.textContent = ${voz.name} (${voz.lang});\n          voiceSelect.appendChild(option);\n          addedNames.add(voz.name);\n        }\n      });\n\n      const savedVoiceIndex = localStorage.getItem('selectedVoiceIndex');\n      if (savedVoiceIndex && voces[savedVoiceIndex]) {\n        voiceSelect.value = savedVoiceIndex;\n      }\n    };\n\n    voiceSelect.addEventListener('change', () => {\n      localStorage.setItem('selectedVoiceIndex', voiceSelect.value);\n      voiceSavedMsg.style.display = 'block';\n      setTimeout(() => voiceSavedMsg.style.display = 'none', 2000);\n    });\n    \n    function actualizarEncabezadoPorPerfil(perfil) {\n      const titulo = document.getElementById('chat-title');\n      const clases = titulo.classList;\n    \n      \/\/ Elimina cualquier clase de fondo anterior\n      clases.remove(\n        'bg-general', 'bg-educador', 'bg-coach', 'bg-psicologo',\n        'bg-ejecutivo', 'bg-cliente', 'bg-soporte',\n        'bg-entrenador', 'bg-neuro', 'bg-nutricionista'\n      );\n    \n      switch (perfil) {\n        case 'educador':\n          titulo.textContent = '\ud83d\udc68\u200d\ud83c\udfeb Educador IA';\n          clases.add('bg-educador');\n          break;\n        case 'coach':\n          titulo.textContent = '\ud83c\udfaf Coach Motivacional';\n          clases.add('bg-coach');\n          break;\n        case 'psicologo':\n          titulo.textContent = '\ud83e\udde0 Psic\u00f3logo Virtual';\n          clases.add('bg-psicologo');\n          break;\n        case 'ejecutivo_cuenta':\n          titulo.textContent = '\ud83d\udcbc Ejecutivo de Cuenta';\n          clases.add('bg-ejecutivo');\n          break;\n        case 'servicio_cliente':\n          titulo.textContent = '\ud83d\udcde Asistente de Atenci\u00f3n al Cliente';\n          clases.add('bg-cliente');\n          break;\n        case 'soporte_tecnico':\n          titulo.textContent = '\ud83d\udee0\ufe0f Soporte T\u00e9cnico';\n          clases.add('bg-soporte');\n          break;\n        case 'entrenador_personal':\n          titulo.textContent = '\ud83c\udfcb\ufe0f Entrenador Personal';\n          clases.add('bg-entrenador');\n          break;\n        case 'neurocientifico':\n          titulo.textContent = '\ud83e\uddec Neurocient\u00edfico IA';\n          clases.add('bg-neuro');\n          break;\n        case 'nutricionista':\n          titulo.textContent = '\ud83e\udd57 Nutricionista Virtual';\n          clases.add('bg-nutricionista');\n          break;\n        default:\n          titulo.textContent = '\ud83e\udd16 Asistente IA General';\n          clases.add('bg-general');\n      }\n    }\n    \n    function obtenerNombreAsistente(perfil) {\n      switch (perfil) {\n        case 'educador': return 'EduAI';\n        case 'coach': return 'CoachGPT';\n        case 'psicologo': return 'PsiBot';\n        case 'ejecutivo_cuenta': return 'SalesBot';\n        case 'servicio_cliente': return 'AtentoAI';\n        case 'soporte_tecnico': return 'TechAssist';\n        case 'entrenador_personal': return 'FitBot';\n        case 'neurocientifico': return 'NeuroAI';\n        case 'nutricionista': return 'NutriBot';\n        default: return 'Asistente AI';\n      }\n    }\n    \n    function actualizarEncabezadoPorPerfil(perfil) {\n      const titulo = document.getElementById('chat-title');\n      const clases = titulo.classList;\n      const nombre = obtenerNombreAsistente(perfil);\n    \n      clases.remove(\n        'bg-general', 'bg-educador', 'bg-coach', 'bg-psicologo',\n        'bg-ejecutivo', 'bg-cliente', 'bg-soporte',\n        'bg-entrenador', 'bg-neuro', 'bg-nutricionista'\n      );\n    \n      switch (perfil) {\n        case 'educador':\n          titulo.textContent = \ud83d\udc68\u200d\ud83c\udfeb ${nombre};\n          clases.add('bg-educador');\n          break;\n        case 'coach':\n          titulo.textContent = \ud83c\udfaf ${nombre};\n          clases.add('bg-coach');\n          break;\n        case 'psicologo':\n          titulo.textContent = \ud83e\udde0 ${nombre};\n          clases.add('bg-psicologo');\n          break;\n        case 'ejecutivo_cuenta':\n          titulo.textContent = \ud83d\udcbc ${nombre};\n          clases.add('bg-ejecutivo');\n          break;\n        case 'servicio_cliente':\n          titulo.textContent = \ud83d\udcde ${nombre};\n          clases.add('bg-cliente');\n          break;\n        case 'soporte_tecnico':\n          titulo.textContent = \ud83d\udee0\ufe0f ${nombre};\n          clases.add('bg-soporte');\n          break;\n        case 'entrenador_personal':\n          titulo.textContent = \ud83c\udfcb\ufe0f ${nombre};\n          clases.add('bg-entrenador');\n          break;\n        case 'neurocientifico':\n          titulo.textContent = \ud83e\uddec ${nombre};\n          clases.add('bg-neuro');\n          break;\n        case 'nutricionista':\n          titulo.textContent = \ud83e\udd57 ${nombre};\n          clases.add('bg-nutricionista');\n          break;\n        default:\n          titulo.textContent = \ud83e\udd16 ${nombre};\n          clases.add('bg-general');\n      }\n    }\n  \n    function obtenerMensajeSistemaPorPerfil(perfil) {\n      switch (perfil) {\n        case 'educador':\n          return 'Eres un educador paciente y claro. Explica conceptos de forma sencilla, con ejemplos cuando sea posible.';\n        case 'coach':\n          return 'Eres un coach motivacional. Inspiras y ayudas a las personas a alcanzar sus metas con energ\u00eda y empat\u00eda.';\n        case 'psicologo':\n          return 'Eres un psic\u00f3logo emp\u00e1tico y profesional. Responde con sensibilidad, escucha activa y consejos basados en la psicolog\u00eda.';\n        case 'ejecutivo_cuenta':\n          return 'Eres un ejecutivo de cuenta experto en ventas. Responde con enfoque comercial, orientado a resultados y siempre cordial.';\n        case 'servicio_cliente':\n          return 'Eres un agente de servicio al cliente. S\u00e9 amable, resolutivo y busca siempre ayudar al usuario con sus necesidades.';\n        case 'soporte_tecnico':\n          return 'Eres un especialista en soporte t\u00e9cnico. Proporciona soluciones claras y t\u00e9cnicas a problemas relacionados con tecnolog\u00eda.';\n        case 'entrenador_personal':\n          return 'Eres un entrenador personal motivador. Da consejos de ejercicio y bienestar f\u00edsico de forma clara y energ\u00e9tica.';\n        case 'neurocientifico':\n          return 'Eres un neurocient\u00edfico experto. Explica procesos cognitivos y del cerebro con precisi\u00f3n y un lenguaje t\u00e9cnico pero accesible.';\n        case 'nutricionista':\n          return 'Eres un nutricionista profesional. Da consejos sobre alimentaci\u00f3n y salud de forma clara, cient\u00edfica y adaptada a cada persona.';\n        default:\n          return 'Eres un asistente general amable y eficiente. Ayudas con tareas diversas de forma clara, \u00fatil y amigable.';\n      }\n    }\n    \n    function obtenerEmojiPorPerfil(perfil) {\n      switch (perfil) {\n        case 'educador': return '\ud83d\udc68\u200d\ud83c\udfeb';\n        case 'coach': return '\ud83c\udfaf';\n        case 'psicologo': return '\ud83e\udde0';\n        case 'ejecutivo_cuenta': return '\ud83d\udcbc';\n        case 'servicio_cliente': return '\ud83d\udcde';\n        case 'soporte_tecnico': return '\ud83d\udee0\ufe0f';\n        case 'entrenador_personal': return '\ud83c\udfcb\ufe0f';\n        case 'neurocientifico': return '\ud83e\uddec';\n        case 'nutricionista': return '\ud83e\udd57';\n        default: return '\ud83e\udd16';\n      }\n    }\n\n    document.getElementById('profileSelect').addEventListener('change', (e) => {\n      const perfil = e.target.value;\n      localStorage.setItem('perfilAsistente', perfil);\n      actualizarEncabezadoPorPerfil(perfil);\n    });\n    \n    window.addEventListener('DOMContentLoaded', () => {\n      const perfilGuardado = localStorage.getItem('perfilAsistente');\n      const perfilSelect = document.getElementById('profileSelect');\n    \n      if (perfilGuardado) {\n        perfilSelect.value = perfilGuardado;\n        actualizarEncabezadoPorPerfil(perfilGuardado);\n      } else {\n        actualizarEncabezadoPorPerfil(perfilSelect.value); \/\/ Valor por defecto\n      }\n    \n      \/\/ Tambi\u00e9n actualizamos la voz guardada si existe\n      const savedVoiceIndex = localStorage.getItem('selectedVoiceIndex');\n      if (savedVoiceIndex && voces[savedVoiceIndex]) {\n        voiceSelect.value = savedVoiceIndex;\n      }\n      \n      const historialGuardado = localStorage.getItem('historialChat');\n        if (historialGuardado) {\n          try {\n            chatHistory = JSON.parse(historialGuardado);\n            chatHistory.forEach(msg => {\n              const texto = msg.content;\n              const sender = msg.role === 'user' ? 'user' : 'bot';\n            \n              \/\/ Si tiene hora guardada, \u00fasala\n              if (msg.time) {\n                const customDate = new Date(msg.time);\n                const hora = customDate.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });\n                const fecha = customDate.toLocaleDateString('es-ES');\n                appendMessage(sender, ${texto}\\n\\n(${fecha} ${hora}));\n              } else {\n                appendMessage(sender, texto);\n              }\n            });\n\n            chatBody.scrollTop = chatBody.scrollHeight;\n          } catch (e) {\n            console.error('Error al cargar historial guardado:', e);\n          }\n        }\n\n    });\n\n\n    async function sendMessage(text = null) {\n      const message = text || userInput.value.trim();\n      if (!message) return;\n    \n      appendMessage('user', message);\n      chatHistory.push({ role: 'user', content: message });\n      userInput.value = '';\n      chatBody.scrollTop = chatBody.scrollHeight;\n    \n      appendMessage('bot', '\ud83e\udde0 Pensando...');\n    \n      try {\n        const perfilSeleccionado = document.getElementById('profileSelect').value;\n        const systemPrompt = {\n          role: 'system',\n          content: obtenerMensajeSistemaPorPerfil(perfilSeleccionado)\n        };\n    \n        const response = await fetch('https:\/\/api.openai.com\/v1\/chat\/completions', {\n          method: 'POST',\n          headers: {\n            'Authorization': 'Bearer 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',\n            'Content-Type': 'application\/json',\n            'Content-Type': 'application\/json'\n          },\n          body: JSON.stringify({\n            model: 'gpt-3.5-turbo',\n            messages: [systemPrompt, ...chatHistory]\n          })\n        });\n    \n        const data = await response.json();\n        const reply = data.choices?.[0]?.message?.content || 'No se obtuvo respuesta.';\n    \n        removeLastBotThinking();\n        appendMessage('bot', reply);\n        \n        const ahora = new Date();\n        const timestamp = ahora.toISOString();\n\n        chatHistory.push({ role: 'user', content: message, time: timestamp });\n        chatHistory.push({ role: 'assistant', content: reply, time: timestamp });\n\n        localStorage.setItem('historialChat', JSON.stringify(chatHistory));\n        \n        if (continuousMode) {\n          speakText(reply);\n        }\n        chatBody.scrollTop = chatBody.scrollHeight;\n    \n      } catch (error) {\n        removeLastBotThinking();\n        appendMessage('bot', '\u274c Error al conectarse a la IA.');\n        console.error(error);\n      }\n    }\n\n    function appendMessage(sender, text) {\n      const messageDiv = document.createElement('div');\n      messageDiv.className = message ${sender};\n    \n      \/\/ Crear avatar\n      const avatar = document.createElement('div');\n      avatar.className = 'message-avatar';\n    \n      if (sender === 'bot') {\n        const perfil = document.getElementById('profileSelect').value;\n        avatar.textContent = obtenerEmojiPorPerfil(perfil);\n      } else {\n        avatar.textContent = '\ud83e\uddd1'; \/\/ Puedes cambiarlo por un avatar personalizado del usuario\n      }\n    \n      \/\/ Crear mensaje\n      const messageText = document.createElement('p');\n      let mensajeFinal = text;\n    \n      if (sender === 'bot') {\n        const perfil = document.getElementById('profileSelect').value;\n        const nombreAsistente = obtenerNombreAsistente(perfil);\n        mensajeFinal = ${nombreAsistente} dice:\\n${text};\n      }\n    \n      messageText.innerText = mensajeFinal;\n    \n      \/\/ Timestamp\n      const time = document.createElement('span');\n      time.className = 'timestamp';\n      const ahora = new Date();\n      const hora = ahora.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });\n      const fecha = ahora.toLocaleDateString('es-ES');\n      time.innerText = ${fecha} ${hora};\n    \n      messageDiv.appendChild(avatar);\n      messageDiv.appendChild(messageText);\n      messageDiv.appendChild(time);\n    \n      chatBody.appendChild(messageDiv);\n    }\n\n\n\n\n    function removeLastBotThinking() {\n      const messages = chatBody.querySelectorAll('.bot');\n      if (messages.length > 0) {\n        const lastBotMsg = messages[messages.length - 1];\n        if (lastBotMsg.textContent.includes('Pensando')) {\n          chatBody.removeChild(lastBotMsg);\n        }\n      }\n    }\n\n    function obtenerAjustesDeVoz(perfil) {\n      switch (perfil) {\n        case 'coach':\n          return { rate: 1.3, pitch: 1.2 }; \/\/ Energ\u00e9tico y motivador\n        case 'psicologo':\n          return { rate: 0.9, pitch: 1.0 }; \/\/ Calmo y neutral\n        case 'educador':\n          return { rate: 1.0, pitch: 1.0 }; \/\/ Claridad est\u00e1ndar\n        case 'ejecutivo_cuenta':\n          return { rate: 1.1, pitch: 1.0 }; \/\/ Profesional\n        case 'servicio_cliente':\n          return { rate: 1.1, pitch: 1.1 }; \/\/ Cordial y claro\n        case 'soporte_tecnico':\n          return { rate: 1.0, pitch: 0.95 }; \/\/ Neutro y t\u00e9cnico\n        case 'entrenador_personal':\n          return { rate: 1.25, pitch: 1.1 }; \/\/ Motivador, activo\n        case 'neurocientifico':\n          return { rate: 0.95, pitch: 0.95 }; \/\/ Preciso y pausado\n        case 'nutricionista':\n          return { rate: 1.05, pitch: 1.0 }; \/\/ C\u00e1lido y profesional\n        default:\n          return { rate: 1.1, pitch: 1.1 }; \/\/ Asistente general\n      }\n    }\n\n    function speakText(text) {\n      if (!continuousMode) return; \/\/ \u2190 Verificaci\u00f3n adicional por si se llama desde otro lugar\n    \n      const mensaje = new SpeechSynthesisUtterance(text);\n      const selectedIndex = voiceSelect.value || 0;\n      const voz = voces[selectedIndex] || voces.find(v => v.lang.includes('es'));\n      const perfilSeleccionado = document.getElementById('profileSelect').value;\n      const ajustes = obtenerAjustesDeVoz(perfilSeleccionado);\n      const vozStatus = document.getElementById('voz-status');\n    \n      mensaje.voice = voz;\n      mensaje.lang = voz?.lang || 'es-ES';\n      mensaje.rate = ajustes.rate;\n      mensaje.pitch = ajustes.pitch;\n    \n      mensaje.onstart = () => {\n        speaking = true;\n        vozStatus.style.display = 'block'; \/\/ Mostrar indicador\n        if (continuousMode && recognition) recognition.stop();\n      };\n    \n      mensaje.onend = () => {\n        speaking = false;\n        vozStatus.style.display = 'none'; \/\/ Ocultar indicador\n        if (continuousMode && recognition) recognition.start();\n      };\n    \n      speechSynthesis.speak(mensaje);\n    }\n\n\n    function probarVoz() {\n      const prueba = new SpeechSynthesisUtterance(\"Hola, soy tu asistente con voz. Estoy listo para ayudarte.\");\n      const selectedIndex = voiceSelect.value || 0;\n      const voz = voces[selectedIndex] || voces.find(v => v.lang.includes('es'));\n\n      prueba.voice = voz;\n      prueba.lang = voz?.lang || 'es-ES';\n      \n      const perfilSeleccionado = document.getElementById('profileSelect').value;\n      const ajustes = obtenerAjustesDeVoz(perfilSeleccionado);\n      prueba.rate = ajustes.rate;\n      prueba.pitch = ajustes.pitch;\n\n      speechSynthesis.speak(prueba);\n\n      setTimeout(() => {\n        if (!speechSynthesis.speaking) {\n          alert(\"\u26a0\ufe0f La voz no se reprodujo. Revisa el navegador o el volumen.\");\n        }\n      }, 2000);\n    }\n\n    micButton.addEventListener('click', () => {\n      recognition.start();\n      micButton.textContent = '\ud83c\udfa7';\n    });\n\n    recognition.onresult = (event) => {\n      const transcript = event.results[0][0].transcript;\n      userInput.value = transcript;\n\n      if (continuousMode) {\n        recognition.stop();\n        sendMessage(transcript);\n      }\n    };\n\n    recognition.onend = () => {\n      if (continuousMode && !speaking) {\n        recognition.start();\n      } else {\n        micButton.textContent = '\ud83c\udf99\ufe0f';\n      }\n    };\n\n    recognition.onerror = (event) => {\n      console.error('Reconocimiento de voz error:', event.error);\n      if (!continuousMode) {\n        micButton.textContent = '\ud83c\udf99\ufe0f';\n      }\n    };\n\n    toggleContinuous.addEventListener('click', () => {\n      continuousMode = !continuousMode;\n      toggleContinuous.textContent = continuousMode ? '\u23f9\ufe0f Detener Conversaci\u00f3n' : '\ud83c\udfa4 Activar Conversaci\u00f3n';\n\n      if (continuousMode) {\n        recognition.continuous = true;\n        recognition.start();\n      } else {\n        recognition.stop();\n        speechSynthesis.cancel();\n      }\n    });\n\n    userInput.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter') sendMessage();\n    });\n    \n    function borrarHistorial() {\n      localStorage.removeItem('historialChat');\n      chatHistory = [];\n      chatBody.innerHTML = '';\n    }\n\n  <\/script>\n<\/body>\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Neo 2.0 Beta Asistente AI con Voz Continua \ud83e\udd16 Asistente IA Enviar \ud83d\udcc2 Cargar archivo (texto, PDF, imagen, Excel&#8230;) \ud83d\ude80 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-247","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/pages\/247","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/comments?post=247"}],"version-history":[{"count":148,"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/pages\/247\/revisions"}],"predecessor-version":[{"id":406,"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/pages\/247\/revisions\/406"}],"wp:attachment":[{"href":"https:\/\/neocloud05.com\/neo\/wp-json\/wp\/v2\/media?parent=247"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}