{"id":1300,"date":"2025-08-28T21:11:56","date_gmt":"2025-08-28T21:11:56","guid":{"rendered":"https:\/\/ojoaosanti.com\/saude\/?page_id=1300"},"modified":"2025-08-28T21:59:28","modified_gmt":"2025-08-28T21:59:28","slug":"nutri-li-chat","status":"publish","type":"page","link":"https:\/\/ojoaosanti.com\/saude\/en\/nutri-li-chat\/","title":{"rendered":"Nutri Li &#8211; Chat"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"1300\" class=\"elementor elementor-1300\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-defeb6a e-flex e-con-boxed e-con e-parent\" data-id=\"defeb6a\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2fc3ca9 elementor-widget__width-initial elementor-widget-mobile__width-inherit titulo-gradient elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"2fc3ca9\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Talk to Li<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bc4f860 elementor-widget elementor-widget-shortcode\" data-id=\"bc4f860\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">        <div id=\"nutrili-chat\" class=\"nutrili-box\">\n            <div class=\"nutrili-header\">\n                <div class=\"nutrili-avatar\"><img decoding=\"async\" src=\"https:\/\/ojoaosanti.com\/saude\/wp-content\/uploads\/2025\/08\/LI.png\" alt=\"Nutri Li\" class=\"nutrili-avatar\"><\/div>\n                <div>\n                    <div class=\"nutrili-title\">Nutri Li \u2022 Educational AI<\/div>\n                    <div class=\"nutrili-sub\">Ask about nutrition, carbohydrates, and good choices\u2026<\/div>\n                <\/div>\n            <\/div>\n            <div class=\"nutrili-messages\" id=\"nutrili-messages\"><\/div>\n            <div class=\"nutrili-input-row\">\n                <textarea id=\"nutrili-input\" rows=\"2\" placeholder=\"Type your question\u2026\"><\/textarea>\n                <button id=\"nutrili-send\" type=\"button\">Send<\/button>\n            <\/div>\n            <div class=\"nutrili-footnote\">\u26a0\ufe0f Educational content. Does not replace consultation with a nutritionist or doctor.<\/div>\n        <\/div>\n        <style>\n:root {\n  --nutrili-primary: #066A98;\n  --nutrili-primary-dark: #055a7f;\n}\n\n\/* Container base *\/\n.nutrili-box{\n  max-width:720px;\n  margin:20px auto;\n  padding:16px;\n  border:1px solid #e6e8eb;\n  border-radius:16px;\n  background:#fff;\n  box-shadow:0 10px 24px rgba(0,0,0,.05);\n  font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,\"Helvetica Neue\",Arial;\n  box-sizing: border-box;\n  display: block;\n}\n\n\/* Header *\/\n.nutrili-header{\n  display:flex;\n  gap:12px;\n  align-items:center;\n  margin-bottom:10px;\n}\n.nutrili-avatar {\n  width:62px !important;\n  height:62px !important;\n  border-radius:50% !important;\n  margin-right:8px !important;\n  object-fit:cover !important;\n}\n.nutrili-title{font-weight:600;font-size:18px}\n.nutrili-sub{font-size:12px;color:#657786}\n\n\/* Mensagens *\/\n.nutrili-messages{\n  height:360px;\n  overflow:auto;\n  padding:8px;\n  border:1px solid #eef0f2;\n  border-radius:12px;\n  background:#fafbfc;\n  box-sizing:border-box;\n}\n\n\/* Bubbles *\/\n.nutrili-msg{\n  max-width:78%;\n  margin:8px 0;\n  padding:10px 12px;\n  border-radius:14px;\n  line-height:1.4;\n  white-space:pre-wrap;\n  word-break:break-word;\n}\n.nutrili-user{\n  margin-left:auto;\n  background:#e6f4fa;\n  border:1px solid #bfd6e0;\n}\n.nutrili-ai{\n  margin-right:auto;\n  background:#e3f2fd;\n  border:1px solid #bbdefb;\n}\n\n\/* Input row *\/\n.nutrili-input-row{\n  display:flex;\n  gap:8px;\n  margin-top:10px;\n  align-items:flex-end;\n}\n.nutrili-input-row textarea{\n  flex:1;\n  border:1px solid #dfe3e8;\n  border-radius:12px;\n  padding:10px;\n  resize:vertical;\n  min-height:44px;\n  max-height:180px;\n  box-sizing:border-box;\n}\n.nutrili-input-row button{\n  border:0;\n  background:var(--nutrili-primary) !important;\n  color:#fff !important;\n  border-radius:12px;\n  padding:10px 16px;\n  cursor:pointer;\n}\n.nutrili-input-row button:disabled{opacity:.6;cursor:not-allowed}\n\n\/* Footnote e loading *\/\n.nutrili-footnote{margin-top:8px;font-size:12px;color:#657786}\n.nutrili-loading{opacity:.8;font-style:italic}\n\n\/* For\u00e7a box-sizing em todo elemento dentro do componente *\/\n.nutrili-box, .nutrili-box * { box-sizing: border-box; }\n\n\/* ======= MOBILE \/ TABLET: altura maior estilo app (80vh) ======= *\/\n@media (max-width: 992px) {\n  \/* Faz o container ocupar 80% da altura da viewport *\/\n  #nutrili-chat.nutrili-box,\n  .nutrili-box {\n    height: 80vh !important;\n    max-height: 80vh !important;\n    display:flex !important;\n    flex-direction:column !important;\n    padding:12px !important;\n  }\n\n  \/* Mensagens passa a ser flex\u00edvel e ocupar espa\u00e7o dispon\u00edvel *\/\n  .nutrili-messages {\n    height: auto !important;\n    flex: 1 1 auto !important;\n    min-height: 120px !important;\n    max-height: calc(80vh - 160px) !important; \/* ajuste fino *\/\n    overflow-y: auto !important;\n    margin-bottom:8px !important;\n  }\n\n  \/* Ajustes do input para n\u00e3o empurrar o layout *\/\n  .nutrili-input-row {\n    margin-top:8px !important;\n    z-index: 2;\n  }\n  .nutrili-input-row textarea {\n    max-height: 28vh !important;\n  }\n\n  \/* Torna o footer discreto *\/\n  .nutrili-footnote { margin-top:6px !important; font-size:11px !important; }\n\n  \/* Garantir que o bot\u00e3o fique vis\u00edvel *\/\n  .nutrili-input-row button { flex: 0 0 auto; }\n}\n\n\/* Aumenta especificidade caso outro CSS esteja sobrescrevendo *\/\nbody .nutrili-box { outline: none; }\n<\/style>\n\n        <script>\n(() => {\n    const elMsgs = document.getElementById('nutrili-messages');\n    const elInput = document.getElementById('nutrili-input');\n    const elBtn = document.getElementById('nutrili-send');\n    const endpoint = 'https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/nutrili\/v1\/chat';\n    const nonce = '4aa36f6ef2';\n\n    \/\/ Hist\u00f3rico local tempor\u00e1rio (enviado ao servidor)\n    const history = []; \/\/ {role:'user'|'assistant', content:string}\n\n    function pushMessage(role, content, extraClass = '') {\n        const div = document.createElement('div');\n        div.className = 'nutrili-msg ' + (role === 'user' ? 'nutrili-user' : 'nutrili-ai') + (extraClass ? ' ' + extraClass : '');\n        \/\/ usamos textContent para evitar inje\u00e7\u00e3o HTML\n        div.textContent = content;\n        elMsgs.appendChild(div);\n        elMsgs.scrollTop = elMsgs.scrollHeight;\n    }\n\n    async function sendMessage() {\n        const text = (elInput.value || '').trim();\n        if (!text) return;\n        elInput.value = '';\n        elBtn.disabled = true;\n\n        \/\/ Mostra a mensagem do usu\u00e1rio\n        pushMessage('user', text);\n\n        \/\/ Mostra loading da IA\n        const loader = document.createElement('div');\n        loader.className = 'nutrili-msg nutrili-ai nutrili-loading';\n        loader.textContent = 'Pensando\u2026';\n        elMsgs.appendChild(loader);\n        elMsgs.scrollTop = elMsgs.scrollHeight;\n\n        try {\n            const res = await fetch(endpoint, {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application\/json',\n                    'X-Nutrili-Nonce': nonce\n                },\n                body: JSON.stringify({\n                    message: text,\n                    history\n                })\n            });\n\n            const data = await res.json();\n\n            \/\/ remove loading\n            const loaders = elMsgs.querySelectorAll('.nutrili-loading');\n            loaders.forEach(l => l.remove());\n\n            if (!data || !data.success) {\n                pushMessage('assistant', data && data.error ? data.error : 'Erro ao responder. Tente de novo.');\n            } else {\n                \/\/ exibe a resposta\n                pushMessage('assistant', data.reply);\n                \/\/ adiciona ao hist\u00f3rico que ser\u00e1 enviado nas pr\u00f3ximas requisi\u00e7\u00f5es\n                history.push({ role: 'user', content: text });\n                history.push({ role: 'assistant', content: data.reply });\n            }\n        } catch (err) {\n            const loaders = elMsgs.querySelectorAll('.nutrili-loading');\n            loaders.forEach(l => l.remove());\n            pushMessage('assistant', 'Falha de rede. Tente novamente.');\n            console.error('NutriLi chat error:', err);\n        } finally {\n            elBtn.disabled = false;\n            elInput.focus();\n        }\n    }\n\n    \/\/ Evento de clique \/ \"Enter\" para enviar\n    elBtn.addEventListener('click', sendMessage);\n    elInput.addEventListener('keydown', (e) => {\n        if (e.key === 'Enter' && !e.shiftKey) {\n            e.preventDefault();\n            sendMessage();\n        }\n    });\n\n    \/\/ Mensagem de boas-vindas: s\u00f3 insere se a \u00e1rea de mensagens estiver vazia\n    document.addEventListener('DOMContentLoaded', function() {\n        \/\/ Protege caso o container n\u00e3o exista\n        if (!elMsgs) return;\n\n        \/\/ Se j\u00e1 h\u00e1 mensagens (por exemplo, shortcode preencheu algo), n\u00e3o duplicar\n        if (elMsgs.children.length === 0) {\n            const welcomeText = \"Ol\u00e1! Eu sou a Li \ud83d\udc99, sua assistente de nutri\u00e7\u00e3o. Posso te ajudar com dicas pr\u00e1ticas sobre alimenta\u00e7\u00e3o, manejo de carboidratos e ideias de refei\u00e7\u00f5es. Qual \u00e9 o seu maior desafio com a alimenta\u00e7\u00e3o hoje?\";\n            pushMessage('assistant', welcomeText);\n            \/\/ adiciona ao hist\u00f3rico para contexto (opcional, ajuda continuidade)\n            history.push({ role: 'assistant', content: welcomeText });\n        }\n    });\n})();\n<\/script>\n\n        <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>Talk to Li<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-1300","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/pages\/1300","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/comments?post=1300"}],"version-history":[{"count":37,"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/pages\/1300\/revisions"}],"predecessor-version":[{"id":1351,"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/pages\/1300\/revisions\/1351"}],"wp:attachment":[{"href":"https:\/\/ojoaosanti.com\/saude\/en\/wp-json\/wp\/v2\/media?parent=1300"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}