{"id":9586,"date":"2025-05-22T09:24:43","date_gmt":"2025-05-22T08:24:43","guid":{"rendered":"https:\/\/mbioworks.com\/?p=9586"},"modified":"2025-06-08T08:31:44","modified_gmt":"2025-06-08T07:31:44","slug":"mbioworksai","status":"publish","type":"post","link":"https:\/\/mbioworks.com\/?p=9586","title":{"rendered":"mBioWorks AI Assistants"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"9586\" class=\"elementor elementor-9586\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-43bc81d elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"43bc81d\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-495bd80\" data-id=\"495bd80\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-32a3fc1 elementor-widget elementor-widget-heading\" data-id=\"32a3fc1\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.11.5 - 14-03-2023 *\/\n.elementor-heading-title{padding:0;margin:0;line-height:1}.elementor-widget-heading .elementor-heading-title[class*=elementor-size-]>a{color:inherit;font-size:inherit;line-height:inherit}.elementor-widget-heading .elementor-heading-title.elementor-size-small{font-size:15px}.elementor-widget-heading .elementor-heading-title.elementor-size-medium{font-size:19px}.elementor-widget-heading .elementor-heading-title.elementor-size-large{font-size:29px}.elementor-widget-heading .elementor-heading-title.elementor-size-xl{font-size:39px}.elementor-widget-heading .elementor-heading-title.elementor-size-xxl{font-size:59px}<\/style><h5 class=\"elementor-heading-title elementor-size-default\">mBioWorks Virtual Assistant<\/h5>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8a59f6c elementor-widget elementor-widget-text-editor\" data-id=\"8a59f6c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.11.5 - 14-03-2023 *\/\n.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:#818a91;color:#fff}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap{color:#818a91;border:3px solid;background-color:transparent}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap{margin-top:8px}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap-letter{width:1em;height:1em}.elementor-widget-text-editor .elementor-drop-cap{float:left;text-align:center;line-height:1;font-size:50px}.elementor-widget-text-editor .elementor-drop-cap-letter{display:inline-block}<\/style>\t\t\t\t<p>Ask anything about mBioWorks&#8217; business and services. The accuracy of information is as good as you can get from our service team. It can also address general questions about microbiology.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-43574bb elementor-invisible elementor-widget elementor-widget-shortcode\" data-id=\"43574bb\" data-element_type=\"widget\" data-settings=\"{&quot;motion_fx_motion_fx_scrolling&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_effect&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_range&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:{&quot;start&quot;:20,&quot;end&quot;:50}},&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;motion_fx_opacity_direction&quot;:&quot;out-in&quot;,&quot;motion_fx_opacity_level&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]},&quot;motion_fx_devices&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;]}\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\">    <!-- Font Awesome -->\n    <link\n      rel=\"stylesheet\"\n      href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\"\n      integrity=\"sha512-pVn1X+gRN4iQ0xwU2Wz+M4mvQk+uD1Vn2Yp9kW0+lfuM+BUZKqQ7D0KLqN8B1B5SBQ\/A1ZCkHnksOuS1+I1sIg==\"\n      crossorigin=\"anonymous\"\n      referrerpolicy=\"no-referrer\"\n    \/>\n    <style>\n    \/* Container will flow inline where shortcode is placed *\/\n    #mbio-ai-page-chatbot {\n      border: 1px solid #e4e8ec;\n      border-radius: 12px;\n      width: 100%;\n      max-width: 700px;\n      height: 800px;\n      max-height: 80vh;\n      background: #fff;\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n      box-shadow: 0 8px 24px rgba(0,0,0,.12);\n      \/* position removed to allow placement in page flow *\/\n    }\n    #mbio-ai-page-chatbot .chat-content {\n      flex: 1;\n      overflow-y: auto;\n      padding: 20px;\n      background: #f8fafc;\n    }\n    #mbio-ai-page-chatbot .chat-log {\n      display: flex;\n      flex-direction: column;\n      gap: 16px;\n    }\n    .chat-row { display: flex; flex-direction: column; }\n    .chat-bubble {\n      max-width: 90%;\n      padding: 12px 16px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1.5;\n      word-wrap: break-word;\n      position: relative;\n    }\n    .user .chat-bubble {\n      background: #007cba;\n      color: #fff;\n      margin-left: auto;\n      border-radius: 15px 15px 0 15px;\n    }\n    .assistant .chat-bubble {\n      background: rgb(206, 240, 255);\n      color: #333;\n      border: 1px solid #e4e8ec;\n      margin-right: auto;\n      border-radius: 15px 15px 15px 0;\n    }\n    .typing {\n      font-size: 24px!important;\n      color: #ff69b4!important;\n      opacity: .75;\n      font-style: italic;\n      line-height: 1!important;\n      margin: 0;\n    }\n    #mbio-ai-page-header {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      padding: 12px 16px;\n      background: rgb(0,69,104);\n      border-bottom: 1px solid rgba(255,255,255,.1);\n      color: #fff;\n      font-size: 16px;\n      font-weight: 400;\n      margin: 0;\n    }\n    #mbio-ai-page-header h3 { font-size: 14px; margin: 0; }\n    #mbio-ai-page-header-actions { display: flex; gap: 8px; }\n    .mbio-ai-page-header-btn {\n      background: none;\n      border: none;\n      color: #fff;\n      cursor: pointer;\n      padding: 4px 8px;\n      border-radius: 4px;\n      font-size: 14px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n    }\n    .mbio-ai-page-header-btn:hover { background: rgba(255,255,255,.1); }\n    #mbio-ai-page-chatbot .chat-form {\n      display: flex;\n      border-top: 1px solid #e4e8ec;\n      padding: 12px 16px;\n      background: #fff;\n    }\n    #mbio-ai-page-chatbot .chat-input {\n      flex: 1;\n      border: 1px solid #e4e8ec;\n      border-radius: 8px;\n      padding: 8px 12px;\n      font-size: 15px;\n    }\n    #mbio-ai-page-chatbot .chat-input:focus {\n      border-color: #007cba;\n      box-shadow: 0 0 0 2px rgba(0,124,186,.1);\n      outline: none;\n    }\n    #mbio-ai-page-chatbot .chat-send {\n      border: none;\n      background: rgb(0,69,104);\n      color: #fff;\n      padding: 8px 16px;\n      border-radius: 8px;\n      cursor: pointer;\n      margin-left: 12px;\n      font-size: 14px;\n    }\n    #mbio-ai-page-chatbot .chat-send:disabled {\n      opacity: .6;\n      cursor: not-allowed;\n      background: #ccc;\n    }\n    <\/style>\n\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/marked\/marked.min.js\"><\/script>\n\n    <div id=\"mbio-ai-page-chatbot\" aria-label=\"mBioWorks chatbot webpage\">\n      <div id=\"mbio-ai-page-header\">\n        <h3>mBioWorks Assistant<\/h3>\n        <div id=\"mbio-ai-page-header-actions\">\n          <button id=\"mbio-ai-page-save-chat\" class=\"mbio-ai-page-header-btn\" title=\"Save Chat\">\n            <i class=\"fas fa-download\"><\/i>\n          <\/button>\n        <\/div>\n      <\/div>\n      <div class=\"chat-content\">\n        <div class=\"chat-log\" role=\"log\" aria-live=\"polite\"><\/div>\n      <\/div>\n      <form class=\"chat-form\" autocomplete=\"off\">\n        <input class=\"chat-input\" type=\"text\" placeholder=\"Ask anything about our services...\">\n        <button class=\"chat-send\" type=\"submit\">Send<\/button>\n      <\/form>\n    <\/div>\n\n    <script>\n    (()=>{\n      const AID     = \"asst_vh23MWRLjCeY9oiQ1LSBBKWy\";\n      const keyPref = 'mbio-ai-page_thread_' + AID;\n      let threadId  = localStorage.getItem(keyPref) || '';\n\n      const content = document.querySelector('#mbio-ai-page-chatbot .chat-content');\n      const log     = content.querySelector('.chat-log');\n      const form    = document.querySelector('#mbio-ai-page-chatbot .chat-form');\n      const input   = form.querySelector('.chat-input');\n      const send    = form.querySelector('.chat-send');\n      const scroll  = ()=> content.scrollTop = content.scrollHeight;\n      const lock    = s => { input.disabled = send.disabled = !s; };\n\n      const row = (cls, html) => {\n        const r = document.createElement('div');\n        r.className = 'chat-row ' + cls;\n        r.dataset.timestamp = new Date().toISOString().split('.')[0].replace('T',' ');\n        r.innerHTML = html;\n        log.appendChild(r);\n        scroll();\n        return r.querySelector('.chat-bubble');\n      };\n\n      form.addEventListener('submit', async e => {\n        e.preventDefault();\n        const q = input.value.trim();\n        if (!q) return;\n        row('user', `<div class=\"chat-bubble\">${q.replace(\/[&<>]\/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]))}<\/div>`);\n        input.value = '';\n        lock(false);\n\n        const bub = row('assistant',\n          '<div class=\"chat-bubble\"><strong>mBioWorks:<\/strong> <span class=\"typing\">.<\/span><\/div>'\n        );\n        const dots = bub.querySelector('.typing');\n        let d = 0, tic = setInterval(()=> {\n          d = (d % 6) + 1;\n          dots.textContent = '.'.repeat(d);\n        }, 400);\n\n        try {\n          const WP_NONCE = \"b4ec52cef4\";\n          const res = await fetch(\n            'https:\/\/mbioworks.com\/index.php?rest_route=\/mbio-ai-page\/v2\/message',\n            {\n              method: 'POST',\n              headers: {\n                'Content-Type': 'application\/json',\n                'X-WP-Nonce': WP_NONCE\n              },\n              credentials: 'same-origin',\n              body: JSON.stringify({ message: q, thread_id: threadId }),\n            }\n          );\n          const data = await res.json();\n          if (!res.ok) throw new Error(data.message || res.statusText);\n\n          clearInterval(tic);\n          threadId = data.thread_id;\n          localStorage.setItem(keyPref, threadId);\n\n          let md = data.reply.replace(\/\u3010[^\u3011]*\u3011\/g, '').replace(\/\ue200[\\s\\S]*?\ue201\/g, '');\n          if ( md.includes('Error') ) md = 'Something wrong, please try again.';\n          let i = 0;\n          (function type() {\n            bub.innerHTML = '<strong>mBioWorks:<\/strong> ' + marked.parse(md.slice(0, ++i));\n            scroll();\n            if (i < md.length) requestAnimationFrame(type);\n            else input.focus();\n          })();\n        } catch(err) {\n          clearInterval(tic);\n          bub.textContent = 'mBioWorks: Error \u2013 ' + err.message;\n          scroll();\n        } finally {\n          lock(true);\n        }\n      });\n\n      document.getElementById('mbio-ai-page-save-chat').addEventListener('click', e => {\n        e.stopPropagation();\n        const rows = Array.from(log.querySelectorAll('.chat-row'));\n        const lines = rows.map(r => {\n          const ts   = r.dataset.timestamp;\n          const role = r.classList.contains('user') ? 'You' : 'mBioWorks';\n          let txt    = r.querySelector('.chat-bubble').textContent.trim();\n          txt = txt.replace(\/^You:\\s*\/i,'').replace(\/^mBioWorks:\\s*\/i,'');\n          return `[${ts}] ${role}:\\n${txt}`;\n        });\n        const blob = new Blob([ lines.join('\\n\\n') ], { type: 'text\/plain' });\n        const url = URL.createObjectURL(blob);\n        const a   = document.createElement('a');\n        a.href    = url;\n        a.download = `mbioworks-chat-${new Date().toISOString().split('.')[0].replace(\/:\/g,'-')}.txt`;\n        document.body.appendChild(a);\n        a.click();\n        setTimeout(() => {\n          document.body.removeChild(a);\n          URL.revokeObjectURL(url);\n        }, 100);\n      });\n    })();\n    <\/script>\n    <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-f3bd479 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"f3bd479\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-736560d\" data-id=\"736560d\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-d6947aa elementor-widget elementor-widget-heading\" data-id=\"d6947aa\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">Bioinformatics Assistant<\/h5>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c4997cc elementor-widget elementor-widget-text-editor\" data-id=\"c4997cc\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>This AI tool specializes in microbial bioinformatics. Ask anything about bash, python and other programming issues you may face in your everyday bioinformatics tasks. It is based on OpenAI&#8217;s GPT-4.1 mini model, optimized for rapid response without deep thinking and reasoning.\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bb8b5f5 elementor-widget elementor-widget-shortcode\" data-id=\"bb8b5f5\" data-element_type=\"widget\" data-settings=\"{&quot;motion_fx_motion_fx_scrolling&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_effect&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_range&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:{&quot;start&quot;:20,&quot;end&quot;:50}},&quot;motion_fx_opacity_direction&quot;:&quot;out-in&quot;,&quot;motion_fx_opacity_level&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]},&quot;motion_fx_devices&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;]}\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\">    <!-- Font Awesome -->\n    <link\n      rel=\"stylesheet\"\n      href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\"\n      integrity=\"sha512-pVn1X+gRN4iQ0xwU2Wz+M4mvQk+uD1Vn2Yp9kW0+lfuM+BUZKqQ7D0KLqN8B1B5SBQ\/A1ZCkHnksOuS1+I1sIg==\"\n      crossorigin=\"anonymous\"\n      referrerpolicy=\"no-referrer\"\n    \/>\n    <style>\n    \/* Container *\/\n    #mbio-bioinformatics-webpage-chatbot {\n      border: 1px solid #e4e8ec;\n      border-radius: 12px;\n      width: 100%;\n      max-width: 700px;\n      height: 800px;\n      max-height: 80vh;\n      background: #fff;\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n      box-shadow: 0 8px 24px rgba(0,0,0,.12);\n    }\n    #mbio-bioinformatics-webpage-content {\n      flex: 1;\n      overflow-y: auto;\n      padding: 20px;\n      background: #f8fafc;\n    }\n    #mbio-bioinformatics-webpage-log {\n      display: flex;\n      flex-direction: column;\n      gap: 16px;\n    }\n    .mbio-bioinformatics-webpage-row { display: flex; flex-direction: column; }\n    .mbio-bioinformatics-webpage-bubble {\n      max-width: 90%;\n      padding: 12px 16px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1.5;\n      word-wrap: break-word;\n      position: relative;\n    }\n    .user .mbio-bioinformatics-webpage-bubble {\n      background: rgb(65, 0, 84);\n      color: #fff;\n      margin-left: auto;\n      border-radius: 15px 15px 0 15px;\n    }\n    .assistant .mbio-bioinformatics-webpage-bubble {\n      background: rgb(254, 248, 255);\n      color: #333;\n      border: 1px solid #e4e8ec;\n      margin-right: auto;\n      border-radius: 15px 15px 15px 0;\n    }\n    .mbio-bioinformatics-webpage-typing {\n      font-size: 24px!important;\n      color: #ff69b4!important;\n      opacity: .75;\n      font-style: italic;\n      line-height: 1!important;\n      margin: 0;\n    }\n    #mbio-bioinformatics-webpage-header {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      padding: 12px 16px;\n      background: rgb(42, 0, 55);\n      border-bottom: 1px solid rgba(255,255,255,.1);\n      color: #fff;\n      font-size: 16px;\n      font-weight: 400;\n      margin: 0;\n    }\n    .mbio-bioinformatics-webpage-header-btn {\n      background: none;\n      border: none;\n      color: #fff;\n      cursor: pointer;\n      padding: 4px 8px;\n      border-radius: 4px;\n      font-size: 14px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n    }\n    #mbio-bioinformatics-webpage-header h3 { font-size: 14px; margin: 0; }\n    .mbio-bioinformatics-webpage-header-btn:hover { background: rgba(255,255,255,.1); }\n    #mbio-bioinformatics-webpage-form {\n      display: flex;\n      border-top: 1px solid #e4e8ec;\n      padding: 12px 16px;\n      background: #fff;\n    }\n    #mbio-bioinformatics-webpage-input {\n      flex: 1;\n      border: 1px solid #e4e8ec;\n      border-radius: 8px;\n      padding: 8px 12px;\n      font-size: 15px;\n    }\n    #mbio-bioinformatics-webpage-input:focus {\n      border-color: rgb(137, 0, 179);\n      box-shadow: 0 0 0 2px rgba(0,124,186,.1);\n      outline: none;\n    }\n    #mbio-bioinformatics-webpage-send {\n      border: none;\n      background: rgb(42, 0, 55);\n      color: #fff;\n      padding: 8px 16px;\n      border-radius: 8px;\n      cursor: pointer;\n      margin-left: 12px;\n      font-size: 14px;\n    }\n    #mbio-bioinformatics-webpage-send:disabled {\n      opacity: .6;\n      cursor: not-allowed;\n      background: #ccc;\n    }\n    <\/style>\n\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/marked\/marked.min.js\"><\/script>\n\n    <div id=\"mbio-bioinformatics-webpage-chatbot\" aria-label=\"mBioWorks Bioinformatics Assistant\">\n      <div id=\"mbio-bioinformatics-webpage-header\">\n        <h3>mBioWorks Bioinformatics Assistant<\/h3>\n        <div>\n          <button id=\"mbio-bioinformatics-webpage-save-chat\" class=\"mbio-bioinformatics-webpage-header-btn\" title=\"Save Chat\">\n            <i class=\"fas fa-download\"><\/i>\n          <\/button>\n        <\/div>\n      <\/div>\n      <div id=\"mbio-bioinformatics-webpage-content\">\n        <div id=\"mbio-bioinformatics-webpage-log\" role=\"log\" aria-live=\"polite\"><\/div>\n      <\/div>\n      <form id=\"mbio-bioinformatics-webpage-form\" autocomplete=\"off\">\n        <input id=\"mbio-bioinformatics-webpage-input\" type=\"text\" placeholder=\"Ask anything about bioinformatics...\">\n        <button id=\"mbio-bioinformatics-webpage-send\" type=\"submit\">Send<\/button>\n      <\/form>\n    <\/div>\n\n    <script>\n    (()=> {\n      const AID     = \"asst_6sngwCzmaO8WWO4R5Jbm1fOs\";\n      const keyPref = 'mbio-bioinformatics-webpage_thread_' + AID;\n      let threadId  = localStorage.getItem(keyPref) || '';\n\n      const content = document.getElementById('mbio-bioinformatics-webpage-content');\n      const log     = document.getElementById('mbio-bioinformatics-webpage-log');\n      const form    = document.getElementById('mbio-bioinformatics-webpage-form');\n      const input   = document.getElementById('mbio-bioinformatics-webpage-input');\n      const send    = document.getElementById('mbio-bioinformatics-webpage-send');\n      const saveBtn = document.getElementById('mbio-bioinformatics-webpage-save-chat');\n      const scroll  = () => content.scrollTop = content.scrollHeight;\n      const lock    = s => { input.disabled = send.disabled = !s; };\n\n      const row = (cls, html) => {\n        const r = document.createElement('div');\n        r.className = 'mbio-bioinformatics-webpage-row ' + cls;\n        r.dataset.timestamp = new Date().toISOString().split('.')[0].replace('T',' ');\n        r.innerHTML = html;\n        log.appendChild(r);\n        scroll();\n        return r.querySelector('.mbio-bioinformatics-webpage-bubble');\n      };\n\n      form.addEventListener('submit', async e => {\n        e.preventDefault();\n        const q = input.value.trim();\n        if (!q) return;\n        row('user', `<div class=\"mbio-bioinformatics-webpage-bubble\">${q.replace(\/[&<>]\/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]))}<\/div>`);\n        input.value = '';\n        lock(false);\n\n        const bub = row('assistant',\n          '<div class=\"mbio-bioinformatics-webpage-bubble\"><span class=\"mbio-bioinformatics-webpage-typing\">.<\/span><\/div>'\n        );\n        const dots = bub.querySelector('.mbio-bioinformatics-webpage-typing');\n        let d = 0, tic = setInterval(()=> {\n          d = (d % 6) + 1;\n          dots.textContent = '.'.repeat(d);\n        }, 400);\n\n        try {\n          const WP_NONCE = \"b4ec52cef4\";\n          const res = await fetch(\n            'https:\/\/mbioworks.com\/index.php?rest_route=\/mbio-bioinformatics-webpage\/v2\/message',\n            {\n              method: 'POST',\n              headers: {\n                'Content-Type': 'application\/json',\n                'X-WP-Nonce': WP_NONCE\n              },\n              credentials: 'same-origin',\n              body: JSON.stringify({ message: q, thread_id: threadId }),\n            }\n          );\n          const data = await res.json();\n          if (!res.ok) throw new Error(data.message || res.statusText);\n\n          clearInterval(tic);\n          threadId = data.thread_id;\n          localStorage.setItem(keyPref, threadId);\n\n          let md = data.reply.replace(\/\u3010[^\u3011]*\u3011\/g, '').replace(\/\ue200[\\s\\S]*?\ue201\/g, '');\n          if ( md.includes('Error') ) md = 'Something went wrong, please try again.';\n          let i = 0;\n          (function type() {\n            bub.innerHTML = marked.parse(md.slice(0, ++i));\n            scroll();\n            if (i < md.length) requestAnimationFrame(type);\n            else input.focus();\n          })();\n        } catch(err) {\n          clearInterval(tic);\n          bub.textContent = 'Error \u2013 ' + err.message;\n          scroll();\n        } finally {\n          lock(true);\n        }\n      });\n\n      saveBtn.addEventListener('click', e => {\n        e.stopPropagation();\n        const rows = Array.from(log.querySelectorAll('.mbio-bioinformatics-webpage-row'));\n        const lines = rows.map(r => {\n          const ts   = r.dataset.timestamp;\n          const role = r.classList.contains('user') ? 'You' : 'Assistant';\n          let txt    = r.querySelector('.mbio-bioinformatics-webpage-bubble').textContent.trim();\n          return `[${ts}] ${role}:\\n${txt}`;\n        });\n        const blob = new Blob([ lines.join('\\n\\n') ], { type: 'text\/plain' });\n        const url = URL.createObjectURL(blob);\n        const a   = document.createElement('a');\n        a.href    = url;\n        a.download = `mbio-bioinf-chat-${new Date().toISOString().split('.')[0].replace(\/:\/g,'-')}.txt`;\n        document.body.appendChild(a);\n        a.click();\n        setTimeout(() => {\n          document.body.removeChild(a);\n          URL.revokeObjectURL(url);\n        }, 100);\n      });\n    })();\n    <\/script>\n    <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-d58f858 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"d58f858\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-cf30cf2\" data-id=\"cf30cf2\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b536bb5 elementor-widget elementor-widget-heading\" data-id=\"b536bb5\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">AskMicrobe Chatbot<\/h5>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c6ad397 elementor-widget elementor-widget-text-editor\" data-id=\"c6ad397\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>AskMicrobe AI Chatbot is capable of answering any questions about microbes. It is designed exclusively for microbiologist.\u00a0It has access to the Microbiology Knowledge Hub that contains all top Microbiology journal articles, digests of textbooks, and EU\/US patents related to microbe and molecular biology. So you can simply \u201cchat\u201d to the latest microbial science and technologies.\u00a0<\/p><p>See more details at <a href=\"https:\/\/askmicrobe.com\">https:\/\/askmicrobe.com<\/a>.\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-169b26c elementor-widget elementor-widget-shortcode\" data-id=\"169b26c\" data-element_type=\"widget\" data-settings=\"{&quot;motion_fx_motion_fx_scrolling&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_effect&quot;:&quot;yes&quot;,&quot;motion_fx_opacity_range&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:{&quot;start&quot;:20,&quot;end&quot;:50}},&quot;motion_fx_opacity_direction&quot;:&quot;out-in&quot;,&quot;motion_fx_opacity_level&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]},&quot;motion_fx_devices&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;]}\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\">    <!-- Font Awesome -->\n    <link\n      rel=\"stylesheet\"\n      href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\"\n      integrity=\"sha512-pVn1X+gRN4iQ0xwU2Wz+M4mvQk+uD1Vn2Yp9kW0+lfuM+BUZKqQ7D0KLqN8B1B5SBQ\/A1ZCkHnksOuS1+I1sIg==\"\n      crossorigin=\"anonymous\"\n      referrerpolicy=\"no-referrer\"\n    \/>\n    <style>\n    \/* Container *\/\n    #askmicrobe-chatbot {\n      border: 1px solid #e4e8ec;\n      border-radius: 12px;\n      width: 100%;\n      max-width: 700px;\n      height: 800px;\n      max-height: 80vh;\n      background: #fff;\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n      box-shadow: 0 8px 24px rgba(0,0,0,.12);\n    }\n    #askmicrobe-content {\n      flex: 1;\n      overflow-y: auto;\n      padding: 20px;\n      background: #f8fafc;\n    }\n    #askmicrobe-log {\n      display: flex;\n      flex-direction: column;\n      gap: 16px;\n    }\n    .askmicrobe-row { display: flex; flex-direction: column; }\n    .askmicrobe-bubble {\n      max-width: 90%;\n      padding: 12px 16px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1.5;\n      word-wrap: break-word;\n      position: relative;\n    }\n    #askmicrobe-chatbot .user .askmicrobe-bubble {\n      background: rgb(0, 84, 14);\n      color: #fff;\n      margin-left: auto;\n      border-radius: 15px 15px 0 15px;\n    }\n    #askmicrobe-chatbot .assistant .askmicrobe-bubble {\n      background: rgb(248, 255, 250);\n      color: #333;\n      border: 1px solid #e4e8ec;\n      margin-right: auto;\n      border-radius: 15px 15px 15px 0;\n    }\n    .askmicrobe-typing {\n      font-size: 24px!important;\n      color:rgb(0, 81, 16)!important;\n      opacity: .75;\n      font-style: italic;\n      line-height: 1!important;\n      margin: 0;\n    }\n    #askmicrobe-header {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      padding: 12px 16px;\n      background: rgb(0, 55, 8);\n      border-bottom: 1px solid rgba(255,255,255,.1);\n      color: #fff;\n      font-size: 16px;\n      font-weight: 400;\n      margin: 0;\n    }\n    .askmicrobe-header-btn {\n      background: none;\n      border: none;\n      color: #fff;\n      cursor: pointer;\n      padding: 4px 8px;\n      border-radius: 4px;\n      font-size: 14px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n    }\n    .askmicrobe-header-btn:hover { background: rgba(255,255,255,.1); }\n    #askmicrobe-header h3 { font-size: 14px; margin: 0; }\n    #askmicrobe-form {\n      display: flex;\n      border-top: 1px solid #e4e8ec;\n      padding: 12px 16px;\n      background: #fff;\n    }\n    #askmicrobe-input {\n      flex: 1;\n      border: 1px solid #e4e8ec;\n      border-radius: 8px;\n      padding: 8px 12px;\n      font-size: 15px;\n    }\n    #askmicrobe-input:focus {\n      border-color: rgb(3, 179, 0);\n      box-shadow: 0 0 0 2px rgba(0,124,186,.1);\n      outline: none;\n    }\n    #askmicrobe-send {\n      border: none;\n      background: rgb(0, 55, 15);\n      color: #fff;\n      padding: 8px 16px;\n      border-radius: 8px;\n      cursor: pointer;\n      margin-left: 12px;\n      font-size: 14px;\n    }\n    #askmicrobe-send:disabled {\n      opacity: .6;\n      cursor: not-allowed;\n      background: #ccc;\n    }\n    <\/style>\n\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/marked\/marked.min.js\"><\/script>\n\n    <div id=\"askmicrobe-chatbot\" aria-label=\"AskMicrobe Assistant\">\n      <div id=\"askmicrobe-header\">\n        <h3>AskMicrobe Assistant<\/h3>\n        <button id=\"askmicrobe-save-chat\" class=\"askmicrobe-header-btn\" title=\"Save Chat\">\n          <i class=\"fas fa-download\"><\/i>\n        <\/button>\n      <\/div>\n      <div id=\"askmicrobe-content\">\n        <div id=\"askmicrobe-log\" role=\"log\" aria-live=\"polite\"><\/div>\n      <\/div>\n      <form id=\"askmicrobe-form\" autocomplete=\"off\">\n        <input id=\"askmicrobe-input\" type=\"text\" placeholder=\"Ask a virtual microbiology professor...\">\n        <button id=\"askmicrobe-send\" type=\"submit\">Send<\/button>\n      <\/form>\n    <\/div>\n\n    <script>\n    (()=> {\n      const AID     = \"asst_95LQKS0ThT3vrWctUzNj6Ram\";\n      const keyPref = 'askmicrobe_thread_' + AID;\n      let threadId  = localStorage.getItem(keyPref) || '';\n\n      const content = document.getElementById('askmicrobe-content');\n      const log     = document.getElementById('askmicrobe-log');\n      const form    = document.getElementById('askmicrobe-form');\n      const input   = document.getElementById('askmicrobe-input');\n      const send    = document.getElementById('askmicrobe-send');\n      const saveBtn = document.getElementById('askmicrobe-save-chat');\n      const scroll  = () => content.scrollTop = content.scrollHeight;\n      const lock    = s => { input.disabled = send.disabled = !s; };\n\n      const row = (cls, html) => {\n        const r = document.createElement('div');\n        r.className = 'askmicrobe-row ' + cls;\n        r.dataset.timestamp = new Date().toISOString().split('.')[0].replace('T',' ');\n        r.innerHTML = html;\n        log.appendChild(r);\n        scroll();\n        return r.querySelector('.askmicrobe-bubble');\n      };\n\n      form.addEventListener('submit', async e => {\n        e.preventDefault();\n        const q = input.value.trim();\n        if (!q) return;\n        row('user', `<div class=\"askmicrobe-bubble\">${q.replace(\/[&<>]\/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]))}<\/div>`);\n        input.value = '';\n        lock(false);\n\n        const bub = row('assistant',\n          '<div class=\"askmicrobe-bubble\"><span class=\"askmicrobe-typing\">.<\/span><\/div>'\n        );\n        const dots = bub.querySelector('.askmicrobe-typing');\n        let d = 0, tic = setInterval(()=> {\n          d = (d % 6) + 1;\n          dots.textContent = '.'.repeat(d);\n        }, 400);\n\n        try {\n          const WP_NONCE = \"b4ec52cef4\";\n          const res = await fetch(\n            'https:\/\/mbioworks.com\/index.php?rest_route=\/askmicrobe\/v2\/message',\n            {\n              method: 'POST',\n              headers: {\n                'Content-Type': 'application\/json',\n                'X-WP-Nonce': WP_NONCE\n              },\n              credentials: 'same-origin',\n              body: JSON.stringify({ message: q, thread_id: threadId }),\n            }\n          );\n          const data = await res.json();\n          if (!res.ok) throw new Error(data.message || res.statusText);\n\n          clearInterval(tic);\n          threadId = data.thread_id;\n          localStorage.setItem(keyPref, threadId);\n\n          let md = data.reply.replace(\/\u3010[^\u3011]*\u3011\/g, '').replace(\/\ue200[\\s\\S]*?\ue201\/g, '');\n          if ( md.includes('Error') ) md = 'Something went wrong, please try again.';\n          let i = 0;\n          (function type() {\n            bub.innerHTML = marked.parse(md.slice(0, ++i));\n            scroll();\n            if (i < md.length) requestAnimationFrame(type);\n            else input.focus();\n          })();\n        } catch(err) {\n          clearInterval(tic);\n          bub.textContent = 'Error \u2013 ' + err.message;\n          scroll();\n        } finally {\n          lock(true);\n        }\n      });\n\n      saveBtn.addEventListener('click', e => {\n        e.stopPropagation();\n        const rows = Array.from(log.querySelectorAll('.askmicrobe-row'));\n        const lines = rows.map(r => {\n          const ts   = r.dataset.timestamp;\n          const role = r.classList.contains('user') ? 'You' : 'Assistant';\n          let txt    = r.querySelector('.askmicrobe-bubble').textContent.trim();\n          return `[${ts}] ${role}:\\n${txt}`;\n        });\n        const blob = new Blob([ lines.join('\\n\\n') ], { type: 'text\/plain' });\n        const url = URL.createObjectURL(blob);\n        const a   = document.createElement('a');\n        a.href    = url;\n        a.download = `askmicrobe-chat-${new Date().toISOString().split('.')[0].replace(\/:\/g,'-')}.txt`;\n        document.body.appendChild(a);\n        a.click();\n        setTimeout(() => {\n          document.body.removeChild(a);\n          URL.revokeObjectURL(url);\n        }, 100);\n      });\n    })();\n    <\/script>\n    <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b2db7fb elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"b2db7fb\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ebb9a62\" data-id=\"ebb9a62\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-dcdbdd0 elementor-widget elementor-widget-heading\" data-id=\"dcdbdd0\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">Office Assistant<\/h5>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-af099d3 elementor-widget elementor-widget-text-editor\" data-id=\"af099d3\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>mBioWorks employs various AI assistants to enhance work efficency. They are also available to our customers and microbe lovers free of charge. Let&#8217;s together unlock the power of microbes.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b0efe18 elementor-widget elementor-widget-shortcode\" data-id=\"b0efe18\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\">    <!-- Font Awesome & Marked.js -->\n    <link\n      rel=\"stylesheet\"\n      href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\"\n      integrity=\"sha512-pVn1X+gRN4iQ0xwU2Wz+M4mvQk+uD1Vn2Yp9kW0+lfuM+BUZKqQ7D0KLqN8B1B5SBQ\/A1ZCkHnksOuS1+I1sIg==\"\n      crossorigin=\"anonymous\"\n      referrerpolicy=\"no-referrer\"\n    \/>\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/marked\/marked.min.js\"><\/script>\n\n    <style>\n    .translator-dk-container {\n      position: relative;\n      display: inline-block;\n      margin: 10px 0;\n      z-index: 1000000;\n    }\n    .translator-dk-icon {\n      cursor: pointer;\n      font-size: 24px;\n      color: rgb(55, 43, 0);\n      background: #fff;\n      width: 50px;\n      height: 50px;\n      border-radius: 50%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      box-shadow: 0 2px 10px rgba(0,0,0,0.15);\n      transition: transform 0.3s ease, box-shadow 0.3s ease;\n    }\n    .translator-dk-icon:hover {\n      transform: scale(1.1);\n      box-shadow: 0 4px 15px rgba(0,0,0,0.2);\n    }\n\n    \/* Overlay *\/\n    .translator-dk-overlay {\n      display: none;\n      position: fixed;\n      top: 0; left: 0;\n      width: 100%; height: 100%;\n      background: rgba(0,0,0,0.5);\n      z-index: 1000001;\n    }\n\n    #translator-dk-chatbot {\n      display: none;\n      position: fixed;\n      top: 50%; left: 50%;\n      transform: translate(-50%, -50%);\n      width: 600px;\n      max-height: 90vh;\n      min-height: 500px;\n      background: #fff;\n      border: 1px solid #e4e8ec;\n      border-radius: 8px;\n      box-shadow: 0 8px 24px rgba(0,0,0,0.2);\n      flex-direction: column;\n      z-index: 1000002;\n    }\n    #translator-dk-chatbot .header {\n      background: rgb(55, 43, 0);\n      color: #fff;\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      padding: 12px 16px;\n      border-bottom: 1px solid rgba(255,255,255,.1);\n      font-size: 16px;\n      font-weight: 400;\n      margin: 0;\n      border-radius: 8px 8px 0 0;\n    }\n    #translator-dk-chatbot .content {\n      flex: 1;\n      overflow-y: auto;\n      padding: 8px;\n      background: #f8fafc;\n      display: flex;\n      flex-direction: column;\n      gap: 6px;\n    }\n    .translator-dk-message {\n      display: flex;\n      flex-direction: column;\n    }\n    .translator-dk-bubble {\n      padding: 12px 16px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1.5;\n      margin-right: 10px;\n      max-width: 90%;\n      width: auto;\n      display: inline-block;\n    }\n    .translator-dk-message.user {\n      margin-left: auto;\n      padding-right: 10px;\n      align-items: flex-end;\n    }\n    .translator-dk-message.assistant {\n      margin-right: auto;\n      padding-left: 10px;\n      align-items: flex-start;\n    }\n    .translator-dk-message.user .translator-dk-bubble {\n      background: rgb(55, 43, 0);\n      color: #fff;\n      border-radius: 15px 15px 0 15px;\n      max-width: 80%;\n    }\n    .translator-dk-message.assistant .translator-dk-bubble {\n      background: #f9f5e9;\n      color: #333;\n      border: 1px solid #e4e8ec;\n      border-radius: 15px 15px 15px 0;\n      max-width: 80%;\n    }\n    .typing-dots {\n      display: inline-flex;\n      align-items: center;\n      height: 17px;\n    }\n    .typing-dots span {\n      width: 8px; height: 8px; margin: 0 2px;\n      background-color: #8a8a8a;\n      border-radius: 50%;\n      animation: typing-dots 1.4s infinite ease-in-out both;\n    }\n    .typing-dots span:nth-child(1) { animation-delay: -0.32s; }\n    .typing-dots span:nth-child(2) { animation-delay: -0.16s; }\n    @keyframes typing-dots {\n      0%,80%,100% { transform: scale(0.6); }\n      40% { transform: scale(1); }\n    }\n    #translator-dk-form {\n      display: flex;\n      border-top: 1px solid #e4e8ec;\n      padding: 6px 8px;\n      background: #fff;\n    }\n    #translator-dk-input {\n      flex: 1;\n      border: 1px solid #e4e8ec;\n      border-radius: 8px;\n      padding: 6px 10px;\n      font-size: 14px;\n      outline: none;\n    }\n    #translator-dk-send {\n      background: rgb(55, 43, 0);\n      color: #fff;\n      border: none;\n      margin-left: 12px;\n      cursor: pointer;\n      padding: 8px 16px;\n      border-radius: 8px;\n      font-size: 14px;\n    }\n    <\/style>\n\n    <div class=\"translator-dk-container\">\n      <span id=\"translator-dk-toggle\" class=\"translator-dk-icon\"\n            role=\"button\" aria-label=\"Open translator\" tabindex=\"0\" aria-expanded=\"false\">\n        <i class=\"fas fa-language\" aria-hidden=\"true\"><\/i>\n      <\/span>\n\n      <div class=\"translator-dk-overlay\" id=\"translator-dk-overlay\"><\/div>\n\n      <div id=\"translator-dk-chatbot\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Translator DK Chat\">\n        <div class=\"header\">\n          <span>Translator DK<\/span>\n          <button id=\"translator-dk-close\"\n                  style=\"background:none;border:none;color:#fff;font-size:16px;cursor:pointer;\">\n            \u00d7\n          <\/button>\n        <\/div>\n        <div class=\"content\">\n          <div class=\"translator-dk-message assistant\">\n            <div class=\"translator-dk-bubble\">\n              Hello! I'm here to help with translations. What would you like to translate?\n            <\/div>\n          <\/div>\n        <\/div>\n        <form id=\"translator-dk-form\" autocomplete=\"off\">\n          <input id=\"translator-dk-input\" type=\"text\" placeholder=\"Type to translate\u2026\" \/>\n          <button id=\"translator-dk-send\">Send<\/button>\n        <\/form>\n      <\/div>\n    <\/div>\n\n    <script>\n    (()=> {\n      const AID      = \"asst_y6RpHPxdHeq7PbWepbDWJ4QI\";\n      const keyPref  = 'translator-dk_thread_' + AID;\n      let threadId   = localStorage.getItem(keyPref) || '';\n\n      const container = document.querySelector('.translator-dk-container');\n      const toggleBtn = document.getElementById('translator-dk-toggle');\n      const overlay   = document.getElementById('translator-dk-overlay');\n      const bot       = document.getElementById('translator-dk-chatbot');\n      const closeBtn  = document.getElementById('translator-dk-close');\n      const content   = bot.querySelector('.content');\n      const form      = document.getElementById('translator-dk-form');\n      const input     = document.getElementById('translator-dk-input');\n      const sendBtn   = document.getElementById('translator-dk-send');\n\n      function scrollBottom(){\n        content.scrollTop = content.scrollHeight;\n      }\n      function addMessage(role, html){\n        const msg = document.createElement('div');\n        msg.className = 'translator-dk-message ' + role;\n        msg.innerHTML = `<div class=\"translator-dk-bubble\">${html}<\/div>`;\n        content.appendChild(msg);\n        scrollBottom();\n      }\n      function showChat(show){\n        overlay.style.display = show ? 'block' : 'none';\n        bot.style.display     = show ? 'flex' : 'none';\n        toggleBtn.setAttribute('aria-expanded', show);\n        if (show) input.focus();\n      }\n\n      toggleBtn.addEventListener('click', e=>{\n        e.stopPropagation();\n        showChat( bot.style.display !== 'flex' );\n      });\n      closeBtn.addEventListener('click', e=>{\n        e.stopPropagation();\n        showChat(false);\n      });\n      overlay.addEventListener('click', ()=> showChat(false));\n      document.addEventListener('keydown', e=>{\n        if (e.key==='Escape' && bot.style.display==='flex') showChat(false);\n      });\n      toggleBtn.addEventListener('keydown', e=>{\n        if (e.key==='Enter' || e.key===' ') {\n          e.preventDefault();\n          showChat( bot.style.display !== 'flex' );\n        }\n      });\n\n      form.addEventListener('submit', async e=>{\n        e.preventDefault();\n        const text = input.value.trim();\n        if (!text) return;\n        addMessage('user', text);\n        input.value = '';\n        sendBtn.disabled = true;\n        addMessage('assistant','<div class=\"typing-dots\"><span><\/span><span><\/span><\/div>');\n        scrollBottom();\n\n        try {\n          const res = await fetch(\n            'https:\/\/mbioworks.com\/index.php?rest_route=\/translator-dk\/v2\/message',\n            {\n              method:'POST',\n              headers:{\n                'Content-Type':'application\/json',\n                'X-WP-Nonce':'b4ec52cef4'\n              },\n              credentials:'same-origin',\n              body:JSON.stringify({ message:text, thread_id:threadId })\n            }\n          );\n          const data = await res.json();\n          if (!res.ok) throw new Error(data.message || res.statusText);\n\n          threadId = data.thread_id;\n          localStorage.setItem(keyPref, threadId);\n\n          \/\/ remove typing\n          const last = content.querySelector('.translator-dk-message.assistant:last-child');\n          last.remove();\n          addMessage('assistant', data.message);\n        } catch(err){\n          const last = content.querySelector('.translator-dk-message.assistant:last-child');\n          last.remove();\n          addMessage('assistant','Error: '+err.message);\n        } finally {\n          sendBtn.disabled = false;\n          scrollBottom();\n          input.focus();\n        }\n      });\n    })();\n    <\/script>\n    <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4f059d1 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"4f059d1\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ae639ce\" data-id=\"ae639ce\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ac17f09 elementor-widget elementor-widget-heading\" data-id=\"ac17f09\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">CyanoExpert<\/h5>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4d4a0a9 elementor-widget elementor-widget-text-editor\" data-id=\"4d4a0a9\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>This is a demo chatbot dedicated to answering anything about cyanobacteria and its environmental impacts. We created this chatbot in collaboration with Lund University and AmoreAqua AB in Sweden. CyanoExpert AI can make mistakes. Please be cautious with AI-generated responses. Inquiry and technical support: <a href=\"mailto:info@mbioworks.com\">info@mbioworks.com<\/a>.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-37cc03a elementor-widget elementor-widget-shortcode\" data-id=\"37cc03a\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\"><link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\" referrerpolicy=\"no-referrer\" \/>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/marked@5.1.1\/marked.min.js\"><\/script>\n<style>\n\/* \u2500\u2500\u2500 layout & look (unchanged except typing effect) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.cyanoexpert-container{position:relative;display:inline-block;margin:10px 0;z-index:1000000}\n.cyanoexpert-icon{cursor:pointer;font-size:24px;background:#fff;width:50px;height:50px;border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 10px rgba(0,0,0,.15);transition:transform .3s,box-shadow .3s}\n.cyanoexpert-icon:hover{transform:scale(1.1);box-shadow:0 4px 15px rgba(0,0,0,.2)}\n.cyanoexpert-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1000001}\n\n#cyanoexpert-chatbot{display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:600px;max-height:90vh;min-height:500px;background:#fff;border:1px solid #e4e8ec;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.2);flex-direction:column;z-index:1000002}\n#cyanoexpert-chatbot .header{display:flex;align-items:center;padding:12px 16px;background:#005f73;color:#fff;border-bottom:1px solid #e4e8ec;border-radius:8px 8px 0 0}\n#cyanoexpert-chatbot .header img,#cyanoexpert-chatbot .header i{margin-right:8px;width:24px;height:24px}\n#cyanoexpert-chatbot .header span{font-size:16px;font-weight:500;color:#fff}\n#cyanoexpert-chatbot .content{flex:1;overflow-y:auto;padding:8px;background:#f8fafc;display:flex;flex-direction:column;gap:6px}\n\n.cyanoexpert-message{display:flex;flex-direction:column}\n.cyanoexpert-bubble{padding:12px 16px;border-radius:12px;font-size:15px;line-height:1.5;min-width:20%;max-width:80%;word-break:break-word;overflow-wrap:anywhere;}\n.cyanoexpert-bubble hr{margin:20px 0}\n.cyanoexpert-message.user{align-items:flex-end;margin-left:auto;min-width:20%;}\n.cyanoexpert-message.user .cyanoexpert-bubble{background:#005f73;color:#fff;border-radius:15px 15px 0 15px}\n.cyanoexpert-message.assistant{align-items:flex-start;margin-right:auto;min-width:20%;}\n.cyanoexpert-message.assistant .cyanoexpert-bubble{background:#F9F9F9;color:#333;border:1px solid #e4e8ec;border-radius:15px 15px 15px 0}\n\n@media(max-width:500px){#cyanoexpert-chatbot{width:95%}.cyanoexpert-bubble{max-width:100%}}\n\n\/* \u2500\u2500\u2500 3-dot loading indicator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.typing-dots{display:inline-flex;align-items:center;height:17px}\n.typing-dots span{width:8px;height:8px;margin:0 2px;background:#8a8a8a;border-radius:50%;animation:typing 1.4s infinite}\n.typing-dots span:nth-child(1){animation-delay:-.32s}\n.typing-dots span:nth-child(2){animation-delay:-.16s}\n.typing-dots span:nth-child(3){animation-delay:0s}\n@keyframes typing{0%,80%,100%{transform:scale(.6)}40%{transform:scale(1)}}\n\n\/* \u2500\u2500\u2500 input row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n#cyanoexpert-form{display:flex;border-top:1px solid #e4e8ec;padding:6px 8px;background:#fff}\n#cyanoexpert-input{flex:1;border:1px solid #e4e8ec;border-radius:8px;padding:6px 10px;font-size:14px}\n#cyanoexpert-send{background:#005f73;color:#fff;border:none;margin-left:12px;cursor:pointer;padding:8px 16px;border-radius:8px;font-size:14px}\n<\/style>\n\n<div class=\"cyanoexpert-container\">\n  <span id=\"cyanoexpert-toggle\" class=\"cyanoexpert-icon\" role=\"button\" tabindex=\"0\" aria-expanded=\"false\">\n    <img decoding=\"async\" src=\"https:\/\/mbioworks.com\/wp-content\/uploads\/2025\/06\/water-drop-liquid-power-08-scaled.png\" alt=\"Chat\">  <\/span>\n\n  <div id=\"cyanoexpert-overlay\" class=\"cyanoexpert-overlay\"><\/div>\n\n  <div id=\"cyanoexpert-chatbot\" role=\"dialog\" aria-modal=\"true\" aria-label=\"CyanoExpert Chat\">\n    <div class=\"header\">\n      <img decoding=\"async\" src=\"https:\/\/mbioworks.com\/wp-content\/uploads\/2025\/06\/water-drop-liquid-power-08-scaled.png\" alt=\"Logo\">      <span>CyanoExpert<\/span>\n      <button id=\"cyanoexpert-close\" style=\"margin-left:auto;background:none;border:none;font-size:18px;cursor:pointer\">\u00d7<\/button>\n    <\/div>\n    <div class=\"content\">\n      <div class=\"cyanoexpert-message assistant\">\n        <div class=\"cyanoexpert-bubble\">Hi, I&#039;m CyanoExpert. I answer any questions about cyanobacteria and its environmental impacts. I&#039;m created by Lund University and AmoreAqua AB in Sweden. <br \/>\r\n<br \/>\r\nCyanoExpert AI can make mistakes. Please be cautious with AI-generated responses. Technical support: info@mbioworks.com.<\/div>\n      <\/div>\n    <\/div>\n    <form id=\"cyanoexpert-form\" autocomplete=\"off\">\n      <input id=\"cyanoexpert-input\" type=\"text\" placeholder=\"Type your question\u2026\" \/>\n      <button id=\"cyanoexpert-send\">Send<\/button>\n    <\/form>\n  <\/div>\n<\/div>\n\n<script>\n(()=>{\n\n\/* \u2500\u2500\u2500 Helper: type HTML without breaking tags \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\nfunction typeHTML(el, html, msPerChar = 20){\n  let i = 0, out = '';\n  const timer = setInterval(()=>{\n    if(i >= html.length){\n      clearInterval(timer);\n      el.innerHTML = html;              \/\/ final cleanup (ensures proper DOM)\n      scrollBottom();\n      return;\n    }\n    const char = html[i++];\n    if(char === '<'){                   \/\/ append entire tag at once\n      const close = html.indexOf('>', i-1);\n      out += html.slice(i-1, close+1);\n      i = close + 1;\n    }else{\n      out += char;                      \/\/ append single character\n    }\n    el.innerHTML = out;\n    scrollBottom();\n  }, msPerChar);\n}\n\n\/* \u2500\u2500\u2500 cache DOM & state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\nconst AID = \"asst_wlhBuRLCBJJYK0Nl1B5m8MtR\",\n      keyPref='cyanoexpert_thread_'+AID;\nlet threadId = localStorage.getItem(keyPref)||'';\n\nconst $       = s=>document.querySelector(s),\n      toggle  = $('#cyanoexpert-toggle'),\n      overlay = $('#cyanoexpert-overlay'),\n      bot     = $('#cyanoexpert-chatbot'),\n      close   = $('#cyanoexpert-close'),\n      content = bot.querySelector('.content'),\n      form    = $('#cyanoexpert-form'),\n      input   = $('#cyanoexpert-input'),\n      sendBtn = $('#cyanoexpert-send');\n\nconst scrollBottom = ()=>{ content.scrollTop = content.scrollHeight };\n\nfunction addMessage(role, html){\n  const wrap=document.createElement('div');\n  wrap.className='cyanoexpert-message '+role;\n  wrap.innerHTML=`<div class=\"cyanoexpert-bubble\">${html}<\/div>`;\n  content.appendChild(wrap); scrollBottom();\n}\n\nfunction showChat(v){\n  overlay.style.display=v?'block':'none';\n  bot.style.display    =v?'flex' :'none';\n  toggle.setAttribute('aria-expanded', v);\n  if(v) input.focus();\n}\n\n\/* \u2500\u2500\u2500 UI events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\ntoggle.addEventListener('click',e=>{e.stopPropagation();showChat(bot.style.display!=='flex')});\nclose .addEventListener('click',e=>{e.stopPropagation();showChat(false)});\noverlay.addEventListener('click',       ()=>showChat(false));\ndocument.addEventListener('keydown',e=>{if(e.key==='Escape'&&bot.style.display==='flex')showChat(false)});\ntoggle .addEventListener('keydown',e=>{if(['Enter',' '].includes(e.key)){e.preventDefault();showChat(bot.style.display!=='flex')}});\n\n\/* \u2500\u2500\u2500 main submit handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\nform.addEventListener('submit',async e=>{\n  e.preventDefault();\n  const txt=input.value.trim();\n  if(!txt) return;\n  addMessage('user', txt);\n  input.value=''; sendBtn.disabled=true;\n\n  \/* 1\ufe0f\u20e3 show three-dot placeholder *\/\n  addMessage('assistant','<div class=\"typing-dots\"><span><\/span><span><\/span><span><\/span><\/div>');\n  scrollBottom();\n\n  try{\n    const res=await fetch('https:\/\/mbioworks.com\/index.php?rest_route=\/cyanoexpert\/v2\/message',{\n      method:'POST',\n      headers:{'Content-Type':'application\/json','X-WP-Nonce':'b4ec52cef4'},\n      credentials:'same-origin',\n      body:JSON.stringify({message:txt,thread_id:threadId})\n    });\n    const data = await res.json();\n    if(!res.ok) throw new Error(data.message||res.statusText);\n    threadId=data.thread_id; localStorage.setItem(keyPref,threadId);\n\n    \/* 2\ufe0f\u20e3 remove dots, create bubble, type it out *\/\n    const typing = content.querySelector('.typing-dots');\n    if(typing) typing.closest('.cyanoexpert-message').remove();\n\n    const html = marked.parse(data.message);  \/\/ full HTML inc. references\n    const wrap = document.createElement('div');\n    wrap.className='cyanoexpert-message assistant';\n    const bubble=document.createElement('div');\n    bubble.className='cyanoexpert-bubble';\n    wrap.appendChild(bubble); content.appendChild(wrap); scrollBottom();\n    typeHTML(bubble, html, 20);               \/\/ adjust speed (ms\/char) here\n  }catch(err){\n    const typing=content.querySelector('.typing-dots');\n    if(typing) typing.closest('.cyanoexpert-message').remove();\n    addMessage('assistant','Error: '+err.message);\n  }finally{\n    sendBtn.disabled=false; scrollBottom(); input.focus();\n  }\n});\n})();\n<\/script>\n<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>The virtual AI assistant for mBioWorks was built with OpenAI&#8217;s latest LLM models and RAG technologies. It can search a local knowledge database and return an accurate answer to user&#8217;s query.<\/p>\n","protected":false},"author":2,"featured_media":9609,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[32,13],"tags":[72,91,93],"class_list":["post-9586","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-admin","category-technical-documents","tag-ai","tag-chatbot","tag-sales"],"_links":{"self":[{"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/posts\/9586","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mbioworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9586"}],"version-history":[{"count":92,"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/posts\/9586\/revisions"}],"predecessor-version":[{"id":9810,"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/posts\/9586\/revisions\/9810"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mbioworks.com\/index.php?rest_route=\/wp\/v2\/media\/9609"}],"wp:attachment":[{"href":"https:\/\/mbioworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mbioworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mbioworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}