{"id":29778,"date":"2024-09-24T13:52:48","date_gmt":"2024-09-24T11:52:48","guid":{"rendered":"https:\/\/www.codemotion.com\/magazine\/?p=29778"},"modified":"2024-09-26T10:38:00","modified_gmt":"2024-09-26T08:38:00","slug":"practical-recipe-for-an-ai-based-chatbot-in-the-browser","status":"publish","type":"post","link":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/","title":{"rendered":"Practical Recipe for an AI-based Chatbot in the Browser"},"content":{"rendered":"\n<p>Let&#8217;s discover how we can create a genuine chat with a virtual assistant based on an AI model similar to ChatGPT, without having to communicate with a server but entirely within the browser!<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Is it really possible to do this at zero cost entirely client-side with JavaScript? Will we actually get to something \"similar to ChatGPT\"? Are we heading towards a future with offline virtual assistants and total privacy control?<\/pre>\n\n\n\n<p>We&#8217;ll answer these questions with this tutorial dedicated to Transformers.js, focusing on creating a chatbot based on a real LLM model from Huggingface.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-practical-recipe-for-an-ai-based-chatbot-integrated-into-a-web-page\">Practical Recipe for an AI-based Chatbot Integrated into a Web Page<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-requirements\">Requirements<\/h3>\n\n\n\n<p>This recipe, like the previous one, is designed to be clear and accessible!<\/p>\n\n\n\n<p>For example, we won&#8217;t use any bundler but a simple \/public folder to be served with your favorite web server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-ingredients\">Ingredients<\/h3>\n\n\n\n<p>For our webapp, we&#8217;ll need three main ingredients corresponding to the four project files we&#8217;ll work on:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">.\/<span class=\"hljs-keyword\">public<\/span>\/\n    index.html\n    worker.js\n    app.js\n    style.css<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Minimalist UI for chat:<\/p>\n\n\n\n<p>Inside our index.html we&#8217;ll have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>#chat-messages<\/code> where user, virtual assistant, and system messages will appear (with different styles)<\/li>\n\n\n\n<li><code>#chat-input-container<\/code> to send a message from the keyboard and with a button<\/li>\n<\/ul>\n\n\n\n<p>A web worker (loaded as a module): it will contain our AI model and allow us to query it without blocking the main thread&#8217;s user interface.<\/p>\n\n\n\n<p>The application logic of a classic chat: the user can send their messages, and so will the AI model.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-preparation\">Preparation<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-a-simple-chat\">A Simple Chat<\/h4>\n\n\n\n<p>For this experiment, we&#8217;ll limit ourselves to a container to host the entire chat with a <code>#chat-header<\/code>, <code>#chat-messages<\/code>, and <code>#chat-input-container<\/code> inside.<\/p>\n\n\n\n<p>Let&#8217;s add everything we need to our index.html:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat-container\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat-header\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>My first LLM<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat-messages\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"chat-messages\"<\/span>&gt;<\/span>\n            <span class=\"hljs-comment\">&lt;!-- messages will appear here --&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat-input-container\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat-input\"<\/span> <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Type your message...\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"send-button\"<\/span> <span class=\"hljs-attr\">disabled<\/span>&gt;<\/span>Send<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"h-sending-and-receiving-messages\">Sending and Receiving Messages<\/h4>\n\n\n\n<p>Now let&#8217;s add to our app.js the system for sending messages written by the user in their box. We&#8217;ll hook into their sending to send the message to our AI\u2026 but first, let&#8217;s create a simple system for sending and receiving messages.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">document<\/span>.addEventListener(<span class=\"hljs-string\">\"DOMContentLoaded\"<\/span>, () =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> sendButton = <span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">\"send-button\"<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> chatInput = <span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">\"chat-input\"<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> chatMessages = <span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">\"chat-messages\"<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> disableUI = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    sendButton.setAttribute(<span class=\"hljs-string\">\"disabled\"<\/span>, <span class=\"hljs-literal\">true<\/span>);\n    sendButton.innerText = <span class=\"hljs-string\">\"...\"<\/span>;\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> enableUI = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    sendButton.removeAttribute(<span class=\"hljs-string\">\"disabled\"<\/span>);\n    sendButton.innerText = <span class=\"hljs-string\">\"Send\"<\/span>;\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> chat = <span class=\"hljs-function\">(<span class=\"hljs-params\">text<\/span>) =&gt;<\/span> {\n    setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      addMessage(<span class=\"hljs-string\">\"Hello world\"<\/span>, <span class=\"hljs-string\">\"assistant\"<\/span>);\n    }, <span class=\"hljs-number\">1000<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> download = <span class=\"hljs-function\">(<span class=\"hljs-params\">modelURL<\/span>) =&gt;<\/span> {\n    disableUI();\n    setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      addMessage(\n        <span class=\"hljs-string\">'&lt;small id=\"downloading-message\"&gt;Downloading model...&lt;\/small&gt;'<\/span>,\n        <span class=\"hljs-string\">\"system\"<\/span>\n      );\n    }, <span class=\"hljs-number\">1000<\/span>);\n\n    setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      addMessage(\n        <span class=\"hljs-string\">`&lt;small&gt;Model ready! More information here &lt;a href=\"https:\/\/huggingface.co\/<span class=\"hljs-subst\">${modelURL}<\/span>\" target=\"_blank\"&gt;<span class=\"hljs-subst\">${modelURL}<\/span>&lt;\/a&gt;&lt;\/small&gt;`<\/span>,\n        <span class=\"hljs-string\">\"system\"<\/span>\n      );\n      enableUI();\n    }, <span class=\"hljs-number\">2000<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> addMessage = <span class=\"hljs-function\">(<span class=\"hljs-params\">message, role<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> newMessageElement = <span class=\"hljs-built_in\">document<\/span>.createElement(<span class=\"hljs-string\">\"div\"<\/span>);\n    newMessageElement.classList.add(<span class=\"hljs-string\">\"chat-message\"<\/span>);\n    newMessageElement.classList.add(role);\n\n    newMessageElement.innerHTML = message;\n    chatMessages.appendChild(newMessageElement);\n    chatMessages.scrollTop = chatMessages.scrollHeight;\n    <span class=\"hljs-keyword\">return<\/span> newMessageElement;\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> sendMessage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    disableUI();\n\n    <span class=\"hljs-keyword\">const<\/span> question = chatInput.value;\n\n    addMessage(question, <span class=\"hljs-string\">\"user\"<\/span>);\n    chat(question);\n    chatInput.value = <span class=\"hljs-string\">\"\"<\/span>;\n  };\n\n  sendButton.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, sendMessage);\n\n  chatInput.addEventListener(<span class=\"hljs-string\">\"keypress\"<\/span>, (event) =&gt; {\n    <span class=\"hljs-keyword\">if<\/span> (event.key === <span class=\"hljs-string\">\"Enter\"<\/span>) {\n      sendMessage();\n    }\n  });\n\n  download(<span class=\"hljs-string\">\"HF_USER\/HF_MODEL\"<\/span>);\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With a pinch of CSS, it will take on the appearance and behavior of a classic chat!<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">body<\/span> {\n    <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">font-family<\/span>: system-ui;\n}\n\n<span class=\"hljs-selector-tag\">a<\/span>, <span class=\"hljs-selector-tag\">a<\/span><span class=\"hljs-selector-pseudo\">:visited<\/span>, <span class=\"hljs-selector-tag\">a<\/span><span class=\"hljs-selector-pseudo\">:focus<\/span>  {\n    <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ff5c00<\/span>;\n}\n\n<span class=\"hljs-selector-id\">#container<\/span> {\n    <span class=\"hljs-attribute\">display<\/span>: flex;\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100<\/span>lvw;\n    <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100<\/span>lvh;\n    <span class=\"hljs-attribute\">justify-content<\/span>: center;\n    <span class=\"hljs-attribute\">align-items<\/span>: center;\n    <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#333<\/span>;\n}\n\n<span class=\"hljs-selector-id\">#chat-container<\/span> {\n    <span class=\"hljs-attribute\">display<\/span>: flex;\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">60vw<\/span>;\n    <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n    <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">80%<\/span>;\n    <span class=\"hljs-attribute\">max-height<\/span>: <span class=\"hljs-number\">80%<\/span>;\n    <span class=\"hljs-attribute\">background-color<\/span>: white;\n    <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n    <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">3px<\/span> solid <span class=\"hljs-number\">#666<\/span>;\n}\n\n<span class=\"hljs-selector-id\">#chat-header<\/span> {\n    <span class=\"hljs-attribute\">display<\/span>: flex;\n    <span class=\"hljs-attribute\">justify-content<\/span>: space-between;\n}\n\n<span class=\"hljs-selector-id\">#chat-header<\/span> <span class=\"hljs-selector-tag\">button<\/span> {\n    <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ff5c00<\/span>;\n    <span class=\"hljs-attribute\">background-color<\/span>: transparent;\n    <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">3rem<\/span>;\n    <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n}\n\n<span class=\"hljs-selector-id\">#chat-messages<\/span> {\n    <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">50vh<\/span>;\n    <span class=\"hljs-attribute\">overflow-y<\/span>: auto;\n    <span class=\"hljs-attribute\">display<\/span>: flex;\n    <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n}\n\n<span class=\"hljs-selector-id\">#chat-input-container<\/span> {\n    <span class=\"hljs-attribute\">display<\/span>: flex;\n}\n\n<span class=\"hljs-selector-id\">#chat-input<\/span> {\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">input<\/span><span class=\"hljs-selector-attr\">&#91;type=text]<\/span>, <span class=\"hljs-selector-tag\">button<\/span> {\n    <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n    <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-number\">#ff5c00<\/span>;\n    <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n    <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">button<\/span> {    \n    <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#ff5c00<\/span>;\n    <span class=\"hljs-attribute\">color<\/span>: white;\n    <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n}\n\n<span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:disabled<\/span> {  \n    <span class=\"hljs-attribute\">background-color<\/span>: white;\n    <span class=\"hljs-attribute\">cursor<\/span>: wait;\n    <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ff5c00<\/span>;\n    <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> dashed <span class=\"hljs-number\">#ff5c00<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">input<\/span><span class=\"hljs-selector-attr\">&#91;type=text]<\/span><span class=\"hljs-selector-pseudo\">:disabled<\/span> {  \n    <span class=\"hljs-attribute\">background-color<\/span>: white;\n    <span class=\"hljs-attribute\">cursor<\/span>: wait;\n    <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ff5c00<\/span>;\n    <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> dashed <span class=\"hljs-number\">#ff5c00<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.chat-message<\/span> {\n    <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n    <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n    <span class=\"hljs-attribute\">white-space<\/span>: break-spaces;\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">80%<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.chat-message<\/span><span class=\"hljs-selector-class\">.user<\/span> {\n    <span class=\"hljs-attribute\">background-color<\/span>: antiquewhite;\n    <span class=\"hljs-attribute\">align-self<\/span>: flex-end;\n}\n\n<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.chat-message<\/span><span class=\"hljs-selector-class\">.assistant<\/span> {\n    <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">rgb<\/span>(<span class=\"hljs-number\">249<\/span>, <span class=\"hljs-number\">205<\/span>, <span class=\"hljs-number\">147<\/span>);\n    <span class=\"hljs-attribute\">align-self<\/span>: flex-start;\n}\n\n<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.chat-message<\/span><span class=\"hljs-selector-class\">.system<\/span> {\n    <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#666<\/span>;\n    <span class=\"hljs-attribute\">font-family<\/span>: monospace;\n    <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.5rem<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The exterior part is ready! Can&#8217;t you already taste the result? \ud83e\udd24<\/p>\n\n\n\n<figure class=\"gb-block-image gb-block-image-487367b6\"><img decoding=\"async\" class=\"gb-image gb-image-487367b6\" src=\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/with_css.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>We&#8217;re ready for the actual communication system with our AI model!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-running-an-ai-model-inside-a-web-worker\">Running an AI Model Inside a Web Worker \ud83c\udf36\ufe0f \ud83c\udf36\ufe0f \ud83c\udf36\ufe0f<\/h3>\n\n\n\n<p>We&#8217;ve reached the spiciest part of the recipe: creating a web worker to download and run the LLM model in the browser without blocking the main thread.<\/p>\n\n\n\n<p>Don&#8217;t know Web Workers? It&#8217;s a great opportunity to try them!<\/p>\n\n\n\n<p>In the app.js file, we&#8217;ll include the worker.js file as a module:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">var<\/span> aiWorker = <span class=\"hljs-keyword\">new<\/span> Worker(<span class=\"hljs-string\">'worker.js'<\/span>, {\n    <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"module\"<\/span>\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Let&#8217;s implement the two functions that will allow us to send messages to the web worker using the postMessage() method, replacing the fake ones:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ To send messages to the AI<\/span>\n<span class=\"hljs-keyword\">const<\/span> chat = <span class=\"hljs-function\">(<span class=\"hljs-params\">message<\/span>) =&gt;<\/span> {\n  aiWorker.postMessage({\n    <span class=\"hljs-attr\">action<\/span>: <span class=\"hljs-string\">\"chat\"<\/span>,\n    <span class=\"hljs-attr\">content<\/span>: message,\n  });\n};\n<span class=\"hljs-comment\">\/\/ To load the AI model: happens only the first time<\/span>\n<span class=\"hljs-keyword\">const<\/span> download = <span class=\"hljs-function\">(<span class=\"hljs-params\">modelURL<\/span>) =&gt;<\/span> {\n  addMessage(\n    <span class=\"hljs-string\">'&lt;small id=\"downloading-message\"&gt;Downloading model...&lt;\/small&gt;'<\/span>,\n    <span class=\"hljs-string\">\"system\"<\/span>\n  );\n  aiWorker.postMessage({\n    <span class=\"hljs-attr\">action<\/span>: <span class=\"hljs-string\">'download'<\/span>,\n    <span class=\"hljs-attr\">modelURL<\/span>: modelURL,\n  });\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>To listen to the Web Worker&#8217;s responses, we simply need to add an event listener that will inform us of every message. Note that the event is always &#8216;message&#8217;, but the content passed to the callback will contain an object that you will define: in practice, you can invent your own protocol made of parameters and flags!<\/p>\n\n\n\n<p>For this recipe, we only need to receive two types of messages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If the response contains the status property, then it&#8217;s the signal that the model is ready (i.e., the response to the message with action: &#8216;download&#8217; sent by us once app.js is loaded)<\/li>\n\n\n\n<li>Otherwise, it&#8217;s the text generated by the model and contained in the result property<\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s see our complete message reception system with the corresponding reactions of our UI:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">aiWorker.addEventListener(<span class=\"hljs-string\">\"message\"<\/span>, (event) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> aiResponse = event.data;\n\n  <span class=\"hljs-keyword\">if<\/span> (aiResponse.status == <span class=\"hljs-string\">\"ready\"<\/span>) {\n    addMessage(\n      <span class=\"hljs-string\">`&lt;small&gt;Model ready! More information here &lt;a href=\"https:\/\/huggingface.co\/<span class=\"hljs-subst\">${aiResponse.modelURL}<\/span>\" target=\"_blank\"&gt;<span class=\"hljs-subst\">${aiResponse.modelURL}<\/span>&lt;\/a&gt;&lt;\/small&gt;`<\/span>,\n      <span class=\"hljs-string\">\"system\"<\/span>\n    );\n  } <span class=\"hljs-keyword\">else<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> result = aiResponse.result;\n    addMessage(result, <span class=\"hljs-string\">'assistant'<\/span>);\n    enableUI();\n  }\n});\n\n<span class=\"hljs-comment\">\/\/ everything starts from this request!<\/span>\ndownload(<span class=\"hljs-string\">'Felladrin\/onnx-Pythia-31M-Chat-v1'<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Yes, you read that right: we have a modelURL parameter! A few steps and we&#8217;ll discover what it&#8217;s for, but you can imagine it \ud83e\udd13<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-web-worker-stuffed-with-a-real-chatbot\">Web Worker Stuffed with a Real Chatbot<\/h3>\n\n\n\n<p>Everything is ready to give intelligence to our virtual assistant based on text-generation models (LLM) loaded entirely in the browser thanks to Transformers.js!!!<\/p>\n\n\n\n<p>First, let&#8217;s load the latest version of Transformers.js directly from a CDN service. Attention! \ud83d\udd25 Don&#8217;t burn yourself: we can load this or other libraries in this way exclusively because we loaded the Web Worker with the type: &#8220;module&#8221; option \ud83d\ude42\u200d\u2195\ufe0f<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> {\n  pipeline,\n  env,\n} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"https:\/\/cdn.jsdelivr.net\/npm\/@xenova\/transformers@2.17.1\"<\/span>;\n\nenv.allowLocalModels = <span class=\"hljs-literal\">false<\/span>; <span class=\"hljs-comment\">\/\/ we'll use remote models!<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now all we have to do is implement our pipeline as in the examples of the official documentation but inside the web worker and when the app asks for it!<\/p>\n\n\n\n<p>The downloadModel function will download the model files from Huggingface and finally create our generator which is a text-generation pipeline<\/p>\n\n\n\n<p>You&#8217;ve surely noticed async and await! When we download the model, the Web Worker will wait for the download to complete and then notify our app that everything is ready with self.postMessage() with the status: &#8220;ready&#8221; property (which is exactly what our application logic is waiting for to activate the UI and thus be able to use the chat)<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">var<\/span> generator;\n\n<span class=\"hljs-keyword\">const<\/span> downloadModel = <span class=\"hljs-keyword\">async<\/span> (modelURL) =&gt; {\n  generator = <span class=\"hljs-keyword\">await<\/span> pipeline(<span class=\"hljs-string\">\"text-generation\"<\/span>, modelURL);\n\n  self.postMessage({\n    <span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-string\">\"ready\"<\/span>,\n    <span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">\"text-generation\"<\/span>,\n    <span class=\"hljs-attr\">modelURL<\/span>: modelURL,\n  });\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is where the magic of text-generation models happens and their ability to seem &#8220;intelligent&#8221;: how exciting!<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">const<\/span> generateResponse = async (content) =&gt; {\n  <span class=\"hljs-comment\">\/\/ text-generation models for chatbots take a chat as input<\/span>\n  <span class=\"hljs-keyword\">const<\/span> messages = &#91;\n    {\n      role: <span class=\"hljs-string\">\"system\"<\/span>,\n      content: <span class=\"hljs-string\">\"You are a highly knowledgeable and friendly assistant.\"<\/span>,\n    },\n    {\n      role: <span class=\"hljs-string\">\"user\"<\/span>,\n      content: content,\n    },\n  ];\n\n  <span class=\"hljs-comment\">\/\/ The chat messages with their roles are fed to a<\/span>\n  <span class=\"hljs-comment\">\/\/ special tokenizer specific to that model that will transform them into vectors (embedding)<\/span>\n  <span class=\"hljs-keyword\">const<\/span> textInput = generator.tokenizer.apply_chat_template(messages, {\n    tokenize: <span class=\"hljs-keyword\">false<\/span>,\n    add_generation_prompt: <span class=\"hljs-keyword\">true<\/span>,\n  });\n\n  <span class=\"hljs-comment\">\/\/ the pipeline in action! This is where we can pass many parameters to change the result of text generation<\/span>\n  <span class=\"hljs-keyword\">const<\/span> output = await generator(textInput, {\n    max_new_tokens: <span class=\"hljs-number\">64<\/span>,\n    do_sample: <span class=\"hljs-keyword\">true<\/span>,\n  });\n\n  <span class=\"hljs-comment\">\/\/ the conversation is returned to us in a model-specific format<\/span>\n  <span class=\"hljs-comment\">\/\/ but by delving into the card on Huggingface we'll find all the information<\/span>\n  <span class=\"hljs-comment\">\/\/ and we can extract the content of the last response.<\/span>\n\n  <span class=\"hljs-comment\">\/\/ At the moment there is still no consensus on how a chat template should be, but to extract the last sentence (i.e. the AI's response) just cut what follows the last occurrence of the string `\"assistant\\n\"` for example like this<\/span>\n\n  <span class=\"hljs-keyword\">const<\/span> conversation = output&#91;<span class=\"hljs-number\">0<\/span>].generated_text;\n  <span class=\"hljs-keyword\">const<\/span> start = conversation.lastIndexOf(<span class=\"hljs-string\">\"assistant\\n\"<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> lastMessage = conversation\n    .substr(start)\n    .replace(<span class=\"hljs-string\">\"assistant\\n\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>);\n\n  <span class=\"hljs-comment\">\/\/ all ready to send the response generated by the AI<\/span>\n  <span class=\"hljs-keyword\">self<\/span>.postMessage({\n    result: lastMessage,\n  });\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>All that&#8217;s left is to amalgamate the Web Worker with requests from our app.js.<\/p>\n\n\n\n<p>We had prepared everything previously to send two messages action: &#8216;download&#8217; and action: &#8216;chat&#8217; and here we do nothing but receive them and react accordingly!<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">self<\/span>.addEventListener(<span class=\"hljs-string\">\"message\"<\/span>, (event) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> userRequest = event.data;\n\n  <span class=\"hljs-keyword\">if<\/span> (userRequest.action == <span class=\"hljs-string\">\"download\"<\/span>) {\n    <span class=\"hljs-keyword\">const<\/span> modelURL = userRequest.modelURL;\n    downloadModel(modelURL);\n\n  } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (userRequest.action == <span class=\"hljs-string\">\"chat\"<\/span>) {\n    <span class=\"hljs-keyword\">const<\/span> content = userRequest.content;\n\n    generateResponse(content);\n  }\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n\n<h3 class=\"wp-block-heading\">Final Result and Observations<\/h3>\n\n\n\n<p>When you first interact with your chatbot, you might find its responses a bit limited or odd. This is normal for a small model, and it&#8217;s important to understand why:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Model Size Matters<\/strong>: The model we used (Felladrin\/onnx-Pythia-31M-Chat-v1) is very small, only about 31 million parameters. While this makes it quick to load and run in a browser, it significantly limits its capabilities.<\/li>\n\n\n\n<li><strong>Improving Responses<\/strong>: You can tweak some parameters to potentially improve outputs:<\/li>\n<\/ol>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> output = <span class=\"hljs-keyword\">await<\/span> generator(textInput, {\n    <span class=\"hljs-attr\">max_new_tokens<\/span>: <span class=\"hljs-number\">1024<\/span>, <span class=\"hljs-comment\">\/\/ Allows for longer responses<\/span>\n    <span class=\"hljs-attr\">repetition_penalty<\/span>: <span class=\"hljs-number\">1.2<\/span>, <span class=\"hljs-comment\">\/\/ Reduces word repetition<\/span>\n    <span class=\"hljs-attr\">do_sample<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  });<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Bigger Models, Better Results<\/strong>: For more coherent and capable responses, consider using larger models:<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Felladrin\/onnx-TinyMistral-248M-Chat-v2 (248 million parameters)<\/li>\n\n\n\n<li>Xenova\/Qwen1.5-0.5B-Chat (500 million parameters) These larger models will take longer to load but offer significantly improved performance.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Next Steps and Challenges<\/h3>\n\n\n\n<p>Now that you&#8217;ve built a basic AI chatbot, here are some ways to expand your project:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Smooth Animations<\/strong>: Implement a typing animation for the chatbot&#8217;s responses to make the interaction feel more natural.<\/li>\n\n\n\n<li><strong>Server-Side Integration<\/strong>: Create a Python backend to interact with even larger language models (7-8B parameters) for more advanced capabilities.<\/li>\n\n\n\n<li><strong>Specialized Assistants<\/strong>: Adapt the chatbot for specific purposes, like creating an NPC (Non-Player Character) for a game.<\/li>\n\n\n\n<li><strong>Explore Other AI Tasks<\/strong>: Try implementing computer vision or speech recognition models using Transformers.js. Look for models by the library&#8217;s author on Hugging Face for compatible options.<\/li>\n\n\n\n<li><strong>UI Improvements<\/strong>: Enhance the chat interface with features like message history, user profiles, or theme customization.<\/li>\n\n\n\n<li><strong>Error Handling and Robustness<\/strong>: Implement better error handling for model loading failures or network issues.<\/li>\n<\/ol>\n\n\n\n<p>Remember, the field of AI and natural language processing is rapidly evolving. Keep experimenting, learning, and staying updated with the latest developments in transformer models and browser-based AI applications.<\/p>\n\n\n\n<p>We hope you enjoyed this tutorial and found it valuable for understanding how to create AI-powered chatbots directly in the browser. Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s discover how we can create a genuine chat with a virtual assistant based on an AI model similar to ChatGPT, without having to communicate with a server but entirely within the browser! Is it really possible to do this at zero cost entirely client-side with JavaScript? Will we actually get to something &#8220;similar to&#8230; <a class=\"more-link\" href=\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\">Read more<\/a><\/p>\n","protected":false},"author":255,"featured_media":27691,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","_uag_custom_page_level_css":"","_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"categories":[46],"tags":[12579,6253],"collections":[11388],"class_list":{"0":"post-29778","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-ai-ml","8":"tag-browser-based","9":"tag-chatbot","10":"collections-codemotion-guides","11":"entry"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Practical Recipe for an AI-based Chatbot in the Browser - Codemotion Magazine<\/title>\n<meta name=\"description\" content=\"Let&#039;s create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don&#039;t miss this guide!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Practical Recipe for an AI-based Chatbot in the Browser\" \/>\n<meta property=\"og:description\" content=\"Let&#039;s create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don&#039;t miss this guide!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\" \/>\n<meta property=\"og:site_name\" content=\"Codemotion Magazine\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Codemotion.Italy\/\" \/>\n<meta property=\"article:published_time\" content=\"2024-09-24T11:52:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-26T08:38:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"768\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Massimo Avvisati\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@MassimoAvvisati\" \/>\n<meta name=\"twitter:site\" content=\"@CodemotionIT\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Massimo Avvisati\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\"},\"author\":{\"name\":\"Massimo Avvisati\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/7d033c17576f9bdfec9dab783e58976a\"},\"headline\":\"Practical Recipe for an AI-based Chatbot in the Browser\",\"datePublished\":\"2024-09-24T11:52:48+00:00\",\"dateModified\":\"2024-09-26T08:38:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\"},\"wordCount\":1103,\"publisher\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png\",\"keywords\":[\"browser based\",\"Chatbot\"],\"articleSection\":[\"AI\/ML\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\",\"name\":\"Practical Recipe for an AI-based Chatbot in the Browser - Codemotion Magazine\",\"isPartOf\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png\",\"datePublished\":\"2024-09-24T11:52:48+00:00\",\"dateModified\":\"2024-09-26T08:38:00+00:00\",\"description\":\"Let's create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don't miss this guide!\",\"breadcrumb\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png\",\"contentUrl\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png\",\"width\":1024,\"height\":768,\"caption\":\"chatbon assistente virtuale AI sul browser.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.codemotion.com\/magazine\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"AI\/ML\",\"item\":\"https:\/\/www.codemotion.com\/magazine\/ai-ml\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Practical Recipe for an AI-based Chatbot in the Browser\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#website\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/\",\"name\":\"Codemotion Magazine\",\"description\":\"We code the future. Together\",\"publisher\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.codemotion.com\/magazine\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#organization\",\"name\":\"Codemotion\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2019\/11\/codemotionlogo.png\",\"contentUrl\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2019\/11\/codemotionlogo.png\",\"width\":225,\"height\":225,\"caption\":\"Codemotion\"},\"image\":{\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Codemotion.Italy\/\",\"https:\/\/x.com\/CodemotionIT\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/7d033c17576f9bdfec9dab783e58976a\",\"name\":\"Massimo Avvisati\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/04\/massimo-100x100.jpeg\",\"contentUrl\":\"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/04\/massimo-100x100.jpeg\",\"caption\":\"Massimo Avvisati\"},\"description\":\"I am a full-stack developer, digital artist, maker, and educator with a passion for Artificial Intelligence. I create immersive installations and develop educational software, pushing the boundaries of technology. I believe in Free Software and Creative Commons licensing as a foundation for knowledge sharing. My goal is to craft unique and engaging educational experiences using cutting-edge technology, showcasing the potential of AI in education. Currently, my focus is on Educational Technology, where I strive to create innovative software and hardware tools that engage and inspire learners. I firmly believe in the power of Free Software and Creative Commons, utilizing these open platforms to ensure my work is accessible and reusable by others. I actively reject restrictive platforms that limit creativity and collaboration. By combining my artistic vision with cutting-edge technology, I aim to develop unique educational experiences that spark curiosity and foster a love of learning. Through my work, I strive to demonstrate the incredible potential of AI in education and the arts.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/massimo-avvisati-7220312\/\",\"https:\/\/x.com\/MassimoAvvisati\"],\"knowsAbout\":[\"Javascript\",\"Node.js\",\"PHP\",\"AI\",\"Machine Learning\",\"Web Development\",\"Free Software\"],\"knowsLanguage\":[\"English\",\"Spanish\",\"Italian\"],\"jobTitle\":\"Head of EdTech R&D\",\"worksFor\":\"Codemotion spa\",\"url\":\"https:\/\/www.codemotion.com\/magazine\/author\/massimo-avvisati\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Practical Recipe for an AI-based Chatbot in the Browser - Codemotion Magazine","description":"Let's create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don't miss this guide!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/","og_locale":"en_US","og_type":"article","og_title":"Practical Recipe for an AI-based Chatbot in the Browser","og_description":"Let's create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don't miss this guide!","og_url":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/","og_site_name":"Codemotion Magazine","article_publisher":"https:\/\/www.facebook.com\/Codemotion.Italy\/","article_published_time":"2024-09-24T11:52:48+00:00","article_modified_time":"2024-09-26T08:38:00+00:00","og_image":[{"width":1024,"height":768,"url":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png","type":"image\/png"}],"author":"Massimo Avvisati","twitter_card":"summary_large_image","twitter_creator":"@MassimoAvvisati","twitter_site":"@CodemotionIT","twitter_misc":{"Written by":"Massimo Avvisati","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#article","isPartOf":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/"},"author":{"name":"Massimo Avvisati","@id":"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/7d033c17576f9bdfec9dab783e58976a"},"headline":"Practical Recipe for an AI-based Chatbot in the Browser","datePublished":"2024-09-24T11:52:48+00:00","dateModified":"2024-09-26T08:38:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/"},"wordCount":1103,"publisher":{"@id":"https:\/\/www.codemotion.com\/magazine\/#organization"},"image":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage"},"thumbnailUrl":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png","keywords":["browser based","Chatbot"],"articleSection":["AI\/ML"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/","url":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/","name":"Practical Recipe for an AI-based Chatbot in the Browser - Codemotion Magazine","isPartOf":{"@id":"https:\/\/www.codemotion.com\/magazine\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage"},"image":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage"},"thumbnailUrl":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png","datePublished":"2024-09-24T11:52:48+00:00","dateModified":"2024-09-26T08:38:00+00:00","description":"Let's create a real digital assistant (AI-based chatbot) with a model similar to ChatGPT. Don't miss this guide!","breadcrumb":{"@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#primaryimage","url":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png","contentUrl":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png","width":1024,"height":768,"caption":"chatbon assistente virtuale AI sul browser."},{"@type":"BreadcrumbList","@id":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/practical-recipe-for-an-ai-based-chatbot-in-the-browser\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.codemotion.com\/magazine\/"},{"@type":"ListItem","position":2,"name":"AI\/ML","item":"https:\/\/www.codemotion.com\/magazine\/ai-ml\/"},{"@type":"ListItem","position":3,"name":"Practical Recipe for an AI-based Chatbot in the Browser"}]},{"@type":"WebSite","@id":"https:\/\/www.codemotion.com\/magazine\/#website","url":"https:\/\/www.codemotion.com\/magazine\/","name":"Codemotion Magazine","description":"We code the future. Together","publisher":{"@id":"https:\/\/www.codemotion.com\/magazine\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.codemotion.com\/magazine\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.codemotion.com\/magazine\/#organization","name":"Codemotion","url":"https:\/\/www.codemotion.com\/magazine\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.codemotion.com\/magazine\/#\/schema\/logo\/image\/","url":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2019\/11\/codemotionlogo.png","contentUrl":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2019\/11\/codemotionlogo.png","width":225,"height":225,"caption":"Codemotion"},"image":{"@id":"https:\/\/www.codemotion.com\/magazine\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Codemotion.Italy\/","https:\/\/x.com\/CodemotionIT"]},{"@type":"Person","@id":"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/7d033c17576f9bdfec9dab783e58976a","name":"Massimo Avvisati","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.codemotion.com\/magazine\/#\/schema\/person\/image\/","url":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/04\/massimo-100x100.jpeg","contentUrl":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/04\/massimo-100x100.jpeg","caption":"Massimo Avvisati"},"description":"I am a full-stack developer, digital artist, maker, and educator with a passion for Artificial Intelligence. I create immersive installations and develop educational software, pushing the boundaries of technology. I believe in Free Software and Creative Commons licensing as a foundation for knowledge sharing. My goal is to craft unique and engaging educational experiences using cutting-edge technology, showcasing the potential of AI in education. Currently, my focus is on Educational Technology, where I strive to create innovative software and hardware tools that engage and inspire learners. I firmly believe in the power of Free Software and Creative Commons, utilizing these open platforms to ensure my work is accessible and reusable by others. I actively reject restrictive platforms that limit creativity and collaboration. By combining my artistic vision with cutting-edge technology, I aim to develop unique educational experiences that spark curiosity and foster a love of learning. Through my work, I strive to demonstrate the incredible potential of AI in education and the arts.","sameAs":["https:\/\/www.linkedin.com\/in\/massimo-avvisati-7220312\/","https:\/\/x.com\/MassimoAvvisati"],"knowsAbout":["Javascript","Node.js","PHP","AI","Machine Learning","Web Development","Free Software"],"knowsLanguage":["English","Spanish","Italian"],"jobTitle":"Head of EdTech R&D","worksFor":"Codemotion spa","url":"https:\/\/www.codemotion.com\/magazine\/author\/massimo-avvisati\/"}]}},"featured_image_src":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-600x400.png","featured_image_src_square":"https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-600x600.png","author_info":{"display_name":"Massimo Avvisati","author_link":"https:\/\/www.codemotion.com\/magazine\/author\/massimo-avvisati\/"},"uagb_featured_image_src":{"full":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png",1024,768,false],"thumbnail":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-150x150.png",150,150,true],"medium":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-300x225.png",300,225,true],"medium_large":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-768x576.png",768,576,true],"large":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png",1024,768,false],"1536x1536":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png",1024,768,false],"2048x2048":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e.png",1024,768,false],"small-home-featured":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-100x100.png",100,100,true],"sidebar-featured":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-180x128.png",180,128,true],"genesis-singular-images":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-896x504.png",896,504,true],"archive-featured":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-400x225.png",400,225,true],"gb-block-post-grid-landscape":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-600x400.png",600,400,true],"gb-block-post-grid-square":["https:\/\/www.codemotion.com\/magazine\/wp-content\/uploads\/2024\/05\/cee94f9e-6bc3-420a-aeeb-a61dda06b10e-600x600.png",600,600,true]},"uagb_author_info":{"display_name":"Massimo Avvisati","author_link":"https:\/\/www.codemotion.com\/magazine\/author\/massimo-avvisati\/"},"uagb_comment_info":0,"uagb_excerpt":"Let&#8217;s discover how we can create a genuine chat with a virtual assistant based on an AI model similar to ChatGPT, without having to communicate with a server but entirely within the browser! Is it really possible to do this at zero cost entirely client-side with JavaScript? Will we actually get to something \"similar to&#8230;&hellip;","lang":"en","_links":{"self":[{"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/posts\/29778","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/users\/255"}],"replies":[{"embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/comments?post=29778"}],"version-history":[{"count":3,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/posts\/29778\/revisions"}],"predecessor-version":[{"id":29781,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/posts\/29778\/revisions\/29781"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/media\/27691"}],"wp:attachment":[{"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/media?parent=29778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/categories?post=29778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/tags?post=29778"},{"taxonomy":"collections","embeddable":true,"href":"https:\/\/www.codemotion.com\/magazine\/wp-json\/wp\/v2\/collections?post=29778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}