{"id":35321,"date":"2024-08-22T07:00:00","date_gmt":"2024-08-22T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=35321"},"modified":"2024-09-06T09:56:19","modified_gmt":"2024-09-06T16:56:19","slug":"quick-answers-better-experience-chatbot-openai-nodejs-react","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react","title":{"rendered":"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React"},"content":{"rendered":"\n<p>Quick access to accurate information is crucial in a development environment. The solution? Create a powerful chatbot that lives on your website and is designed to enhance the developer experience. Leveraging OpenAI, this chatbot will provide instant answers to queries from your developer documentation, helping users find what they need faster and more efficiently.<\/p>\n\n\n\n<p>In this blog post, you\u2019ll learn how to train a <a href=\"https:\/\/platform.openai.com\/docs\/models\">Model<\/a> for your chatbot, generate an image with the <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\/images\/create\">DALL-E API<\/a>, and generate the chat using the <a href=\"https:\/\/platform.openai.com\/docs\/guides\/text-generation\/chat-completions-api\">Chat Completion API<\/a>.<\/p>\n\n\n\n<p>This is an example of an output of the app in which I ask how one can use the Cloudinary React SDK:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"599\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_599,c_scale\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35322\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271509\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271509\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-1\/blog-Quick-Answers-Better-Experience-1.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>GitHub Repo<\/strong>: <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-Chatbot-OpenAI-Demo\/tree\/main\">Cloudinary-Chatbot-OpenAI-Demo<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Part 1: Set Up OpenAI<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Create an OpenAI account<\/h3>\n\n\n\n<p>To begin, log in to your <a href=\"https:\/\/platform.openai.com\/playground\/chat\">OpenAI Platform account or create a free account<\/a>. You\u2019ll be redirected to your OpenAI dashboard.<br><br>Now, click your avatar in the top right corner, then click <strong>Your Profile<\/strong> and you\u2019ll&nbsp;be redirected to your profile page.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"588\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_588,c_scale\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35323\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271495\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271495\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-2\/blog-Quick-Answers-Better-Experience-2.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Add Credit to Your OpenAI account<\/h3>\n\n\n\n<p>Deposit money to start using the<strong> OpenAI API<\/strong> or <strong>SDK<\/strong>. Even an amount as small as $2-$5 is enough for you to start playing with OpenAI.&nbsp;<\/p>\n\n\n\n<p>Inside the profile page, on the left side navigation, click <strong>Billing<\/strong>, then the green button <strong>Add payment details, <\/strong>and enter your bank account information to add credit to your account.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img width=\"1024\" height=\"588\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_588,c_scale\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35325\" style=\"width:839px;height:auto\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271488\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271488\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-3\/blog-Quick-Answers-Better-Experience-3.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>With OpenAI you can set charge limits so you won\u2019t be surprised by an unexpected bill.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Get API Keys<\/h3>\n\n\n\n<p>Generate an API Key to be used on our backend server to use the OpenAI services. To do this, on your left navigation bar, click <strong>YourProfile<\/strong>, then click <strong>Create new secret key.<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"588\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_588,c_scale\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35326\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271474\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271474\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-4-1\/blog-Quick-Answers-Better-Experience-4-1.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>In the pop-up, name your API key. I used <strong>chatbot<\/strong>. After entering your API key name, click <strong>Create secret key<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img width=\"1024\" height=\"588\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_588,c_scale\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35327\" style=\"width:840px;height:auto\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271463\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271463\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-5\/blog-Quick-Answers-Better-Experience-5.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"599\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_599,c_scale\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35328\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271455\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271455\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-6\/blog-Quick-Answers-Better-Experience-6.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Copy and paste the API key generated into a safe place and click <strong>Done<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Part 2:<\/strong> Build the React app<\/h2>\n\n\n\n<p>In this tutorial, I\u2019m using <a href=\"https:\/\/vitejs.dev\/guide\/\">Vite<\/a> to build my React application. I recommend you to do the same. Follow the instructions on Vite\u2019s official website to create a React application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Build the UI Chatbot<\/h3>\n\n\n\n<p>In your <strong>App.jsx<\/strong> file, replace the existing code with the following:<\/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 shcb-wrap-lines\">import { useState, useEffect } from <span class=\"hljs-string\">\"react\"<\/span>;\nimport ReactMarkdown from <span class=\"hljs-string\">\"react-markdown\"<\/span>;\nimport <span class=\"hljs-string\">\".\/App.css\"<\/span>;\n\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n <span class=\"hljs-keyword\">const<\/span> &#91;messages, setMessages] = useState(&#91;]);\n <span class=\"hljs-keyword\">const<\/span> &#91;inputMessage, setInputMessage] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n <span class=\"hljs-keyword\">const<\/span> &#91;isLoading, setisLoading] = useState(<span class=\"hljs-string\">\"START\"<\/span>);\n <span class=\"hljs-keyword\">const<\/span> &#91;userImage, setUserImage] = useState(<span class=\"hljs-keyword\">null<\/span>);\n <span class=\"hljs-keyword\">const<\/span> &#91;assistantImage, setAssistantImage] = useState(<span class=\"hljs-keyword\">null<\/span>);\n\n\n <span class=\"hljs-keyword\">const<\/span> handleMessageSend = async () =&gt; {\n   setisLoading(<span class=\"hljs-string\">\"LOADING\"<\/span>);\n   <span class=\"hljs-keyword\">if<\/span> (inputMessage.trim() === <span class=\"hljs-string\">\"\"<\/span>) <span class=\"hljs-keyword\">return<\/span>;\n\n\n   <span class=\"hljs-keyword\">const<\/span> newMessages = &#91;...messages, { role: <span class=\"hljs-string\">\"user\"<\/span>, content: inputMessage }];\n   setMessages(newMessages);\n   setInputMessage(<span class=\"hljs-string\">\"\"<\/span>);\n\n\n   <span class=\"hljs-keyword\">try<\/span> {\n     <span class=\"hljs-keyword\">const<\/span> response = await fetch(<span class=\"hljs-string\">\"api\/chat\"<\/span>, {\n       method: <span class=\"hljs-string\">\"POST\"<\/span>,\n       headers: {\n         <span class=\"hljs-string\">\"Content-Type\"<\/span>: <span class=\"hljs-string\">\"application\/json\"<\/span>,\n       },\n       body: JSON.stringify({ messages: newMessages }),\n     });\n     <span class=\"hljs-keyword\">const<\/span> data = await response.json();\n     <span class=\"hljs-keyword\">const<\/span> botReply = { role: <span class=\"hljs-string\">\"assistant\"<\/span>, content: data.content };\n     setisLoading(<span class=\"hljs-string\">\"DONE\"<\/span>);\n     setMessages(&#91;...newMessages, botReply]);\n   } <span class=\"hljs-keyword\">catch<\/span> (error) {\n     <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"Error\"<\/span>\n   }\n };\n\n\n   <span class=\"hljs-comment\">\/\/ Scroll to the bottom of the chat window when new messages are added<\/span>\n useEffect(() =&gt; {\n   <span class=\"hljs-keyword\">const<\/span> chatContainer = document.getElementById(<span class=\"hljs-string\">\"chat-container\"<\/span>);\n   chatContainer.scrollTop = chatContainer.scrollHeight;\n }, &#91;messages]);\n\n\n<span class=\"hljs-comment\">\/\/Generate Image with Dall-e<\/span>\n useEffect(() =&gt; {\n   <span class=\"hljs-comment\">\/\/ Create a new avatar when the page loads<\/span>\n   <span class=\"hljs-keyword\">const<\/span> generateImage = async () =&gt; {\n     <span class=\"hljs-keyword\">try<\/span> {\n       <span class=\"hljs-keyword\">const<\/span> response = await fetch(<span class=\"hljs-string\">\"api\/avatar\"<\/span>, {\n         method: <span class=\"hljs-string\">\"POST\"<\/span>,\n         headers: {\n           <span class=\"hljs-string\">\"Content-Type\"<\/span>: <span class=\"hljs-string\">\"application\/json\"<\/span>,\n         },\n         body: JSON.stringify({ prompt }),\n       });\n       <span class=\"hljs-keyword\">const<\/span> data = await response.json();\n       console.log(<span class=\"hljs-string\">\"images\"<\/span>, data);\n       setUserImage(data&#91;<span class=\"hljs-number\">0<\/span>].url);\n       setAssistantImage(data&#91;<span class=\"hljs-number\">1<\/span>].url);\n       <span class=\"hljs-keyword\">return<\/span> data;\n     } <span class=\"hljs-keyword\">catch<\/span> (error) {\n       console.error(error);\n     }\n   };\n   generateImage();\n }, &#91;]);\n\n\n <span class=\"hljs-keyword\">return<\/span> (\n   &lt;div className=<span class=\"hljs-string\">\"App\"<\/span>&gt;\n     &lt;div className=<span class=\"hljs-string\">\"chat-container\"<\/span> id=<span class=\"hljs-string\">\"chat-container\"<\/span>&gt;\n       {messages.map((message, index) =&gt;\n         message.content !== undefined ? (\n           &lt;div key={index} className={`message ${message.role}`}&gt;\n             &lt;img\n               src={message.role === <span class=\"hljs-string\">\"user\"<\/span> ? userImage : assistantImage}\n               alt=<span class=\"hljs-string\">\"user image\"<\/span>\n               className=<span class=\"hljs-string\">\"avatar\"<\/span>\n             \/&gt;\n             {message.role === <span class=\"hljs-string\">\"assistant\"<\/span> ? (\n               &lt;div className=<span class=\"hljs-string\">\"assistant-message\"<\/span>&gt;\n                 &lt;ReactMarkdown&gt;{message.content}&lt;\/ReactMarkdown&gt;\n               &lt;\/div&gt;\n             ) : (\n               message.content\n             )}\n           &lt;\/div&gt;\n         ) : (\n           &lt;div key={index} className=<span class=\"hljs-string\">\"message assistant\"<\/span>&gt;\n             Error in the server\n           &lt;\/div&gt;\n         )\n       )}\n       {isLoading === <span class=\"hljs-string\">\"START\"<\/span> || isLoading === <span class=\"hljs-string\">\"DONE\"<\/span> ? (\n         &lt;&gt;&lt;\/&gt;\n       ) : (\n         &lt;div className=<span class=\"hljs-string\">\"spinner-bar\"<\/span>&gt;\n           &lt;div className=<span class=\"hljs-string\">\"spinner chat\"<\/span>&gt;&lt;\/div&gt;\n         &lt;\/div&gt;\n       )}\n     &lt;\/div&gt;\n     &lt;div className=<span class=\"hljs-string\">\"input-container\"<\/span>&gt;\n       {assistantImage !== <span class=\"hljs-keyword\">null<\/span> &amp;&amp; userImage !== <span class=\"hljs-keyword\">null<\/span> ? (\n         &lt;&gt;\n           &lt;textarea\n             rows=<span class=\"hljs-string\">\"4\"<\/span>\n             cols=<span class=\"hljs-string\">\"50\"<\/span>\n             value={inputMessage}\n             onChange={(e) =&gt; setInputMessage(e.target.value)}\n             placeholder=<span class=\"hljs-string\">\"Chat with the AI bot\"<\/span>\n           \/&gt;\n           &lt;button onClick={handleMessageSend}&gt;Send&lt;\/button&gt;\n         &lt;\/&gt;\n       ) : (\n         &lt;div className=<span class=\"hljs-string\">\"spinner\"<\/span>&gt;&lt;\/div&gt;\n       )}\n     &lt;\/div&gt;\n   &lt;\/div&gt;\n );\n}\n\n\nexport <span class=\"hljs-keyword\">default<\/span> App;\n<\/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>This code has three main components:<\/p>\n\n\n\n<p>1. <code>handleMessageSend()<\/code>. This function is responsible for sending the new user message along with the previous conversation history to the NodeJS back end.<\/p>\n\n\n\n<p>2. <code>first useEffect()<\/code>. This <code>useEffect<\/code> improves the user experience by automatically scrolling the screen to focus on the latest messages whenever a new message is sent and a response is received from the chatbot.<\/p>\n\n\n\n<p>3. <code>second useEffect()<\/code>. This <code>useEffect<\/code> triggers a call to the backend to generate avatars using DALL-E, creating one avatar for the user and another for the chatbot.<\/p>\n\n\n\n<p>Let\u2019s now style the app. In your app, replace the code inside of the <code>App.css<\/code> with the code inside of this <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-Chatbot-OpenAI-Demo\/blob\/main\/src\/App.jsx\">file<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configure Your React Vite app<\/h3>\n\n\n\n<p>If you want to easily make a call to your NodeJS backend without using CORS, you can configure your Vite app to proxy the backend endpoints. This step only applies if you created the React app using Vite.&nbsp;<\/p>\n\n\n\n<p>Open your <code>vite.config.js<\/code> file and replace the content with the following code.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { defineConfig } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vite'<\/span>\n<span class=\"hljs-keyword\">import<\/span> react <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@vitejs\/plugin-react'<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> defineConfig({\n  <span class=\"hljs-attr\">plugins<\/span>: &#91;react()],\n  <span class=\"hljs-attr\">server<\/span>: {\n    <span class=\"hljs-attr\">port<\/span>: <span class=\"hljs-number\">3000<\/span>,\n    <span class=\"hljs-attr\">proxy<\/span>: {\n      <span class=\"hljs-string\">\"\/api\"<\/span>: {\n        <span class=\"hljs-attr\">target<\/span>: <span class=\"hljs-string\">\"http:\/\/localhost:6000\"<\/span>,\n        <span class=\"hljs-attr\">changeOrigin<\/span>: <span class=\"hljs-literal\">true<\/span>,\n        <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">false<\/span>,\n      },\n    },\n  },\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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>What we\u2019re doing here is proxying the backend with any path that is <code>\/api<\/code> to be forwarded to the target <a href=\"http:\/\/localhost:6000\"><strong>http:\/\/localhost:6000<\/strong><\/a>, which is the address of your backend server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Part 3: Build the NodeJS App<\/h2>\n\n\n\n<p>Time to work on the backend. In the root of your React app, create a folder called back end. Inside this folder create a <code>server.js<\/code> file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup your NodeJS Server<\/h3>\n\n\n\n<p>In the root of the project you have the <code>package.json<\/code>, we will use this same file for our backend. Replace everything that you currently have in the <code>package.json<\/code> copy and paste the content of <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-Chatbot-OpenAI-Demo\/blob\/main\/package.json\">this file<\/a> into your <code>package.json<\/code>.<\/p>\n\n\n\n<p>In the root of your project create a <code>.env<\/code> file, and enter the following:<\/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 shcb-wrap-lines\">OPENAI_API_KEY=<span class=\"hljs-string\">\"YOUR OPEN AI API KEY\"<\/span><\/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>Replace the string with the OpenAI API Key you generated earlier.<\/p>\n\n\n\n<p>Copy paste the following code into your <strong>server.js<\/strong> file.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/* eslint-disable no-undef *\/<\/span>\nimport express from <span class=\"hljs-string\">\"express\"<\/span>;\nimport bodyParser from <span class=\"hljs-string\">\"body-parser\"<\/span>;\nimport OpenAI from <span class=\"hljs-string\">\"openai\"<\/span>;\nimport <span class=\"hljs-string\">\"dotenv\/config\"<\/span>;\n\n\n<span class=\"hljs-keyword\">const<\/span> openai = <span class=\"hljs-keyword\">new<\/span> OpenAI({\n apiKey: process.env.OPENAI_API_KEY,\n});\n\n\n<span class=\"hljs-keyword\">const<\/span> app = express();\napp.<span class=\"hljs-keyword\">use<\/span>(<span class=\"hljs-title\">bodyParser<\/span>.<span class=\"hljs-title\">json<\/span>());\n\n\napp.post(<span class=\"hljs-string\">\"\/api\/chat\"<\/span>, async (req, res) =&gt; {\n <span class=\"hljs-comment\">\/*\n   Train the model by giving it some previous conversations\n   *\/<\/span>\n <span class=\"hljs-keyword\">const<\/span> demoModel = &#91;\n   {\n     role: <span class=\"hljs-string\">\"user\"<\/span>,\n     content:\n       <span class=\"hljs-string\">\"Hi, can you tell me where to find information about the Cloudinary React sdk?\"<\/span>,\n   },\n   {\n     role: <span class=\"hljs-string\">\"assistant\"<\/span>,\n     content:\n       <span class=\"hljs-string\">\"Yes, the conentent can be found inside of this website https:\/\/cloudinary.com\/documentation\/react_integration\"<\/span>,\n   },\n   {\n     role: <span class=\"hljs-string\">\"user\"<\/span>,\n     content:\n       <span class=\"hljs-string\">\"can you tell me where to find information about the cloudinary transformations\"<\/span>,\n   },\n   {\n     role: <span class=\"hljs-string\">\"assistant\"<\/span>,\n     content:\n       <span class=\"hljs-string\">\"Yes, the conentent can be found inside of this website https:\/\/cloudinary.com\/documentation\/react_image_transformations\"<\/span>,\n   },\n   {\n     role: <span class=\"hljs-string\">\"user\"<\/span>,\n     content: <span class=\"hljs-string\">\"can you tell me how to display an image using the cloudinary React SDK\"<\/span>,\n   },\n   {\n     role: <span class=\"hljs-string\">\"assistant\"<\/span>,\n     content: `Yes, to display an image using cloudinary follow this guide https:<span class=\"hljs-comment\">\/\/cloudinary.com\/documentation\/react_integration#landingpage and this code sample<\/span>\n     import React from <span class=\"hljs-string\">'react'<\/span>\n     import {AdvancedImage} from <span class=\"hljs-string\">'@cloudinary\/react'<\/span>;\n     import {Cloudinary} from <span class=\"hljs-string\">\"@cloudinary\/url-gen\"<\/span>;\n    \n     <span class=\"hljs-comment\">\/\/ Import required actions.<\/span>\n     import {sepia} from <span class=\"hljs-string\">\"@cloudinary\/url-gen\/actions\/effect\"<\/span>;\n    \n     <span class=\"hljs-keyword\">const<\/span> App = () =&gt; {\n    \n       <span class=\"hljs-comment\">\/\/ Create and configure your Cloudinary instance.<\/span>\n       <span class=\"hljs-keyword\">const<\/span> cld = <span class=\"hljs-keyword\">new<\/span> Cloudinary({\n         cloud: {\n           cloudName: <span class=\"hljs-string\">'demo'<\/span>\n         }\n       });\n    \n       <span class=\"hljs-comment\">\/\/ Use the image with public ID, 'front_face'.<\/span>\n       <span class=\"hljs-keyword\">const<\/span> myImage = cld.image(<span class=\"hljs-string\">'front_face'<\/span>);\n    \n       <span class=\"hljs-comment\">\/\/ Apply the transformation.<\/span>\n       myImage\n       .effect(sepia());  <span class=\"hljs-comment\">\/\/ Apply a sepia effect.<\/span>\n    \n       <span class=\"hljs-comment\">\/\/ Render the transformed image in a React component.<\/span>\n       <span class=\"hljs-keyword\">return<\/span> (\n         &lt;div&gt;\n           &lt;AdvancedImage cldImg={myImage} \/&gt;\n         &lt;\/div&gt;\n       )\n     };\n       `,\n   },\n ];\n\n\n <span class=\"hljs-keyword\">const<\/span> { messages } = req.body;\n messages&#91;messages.length - <span class=\"hljs-number\">1<\/span>].content = `${\n   messages&#91;messages.length - <span class=\"hljs-number\">1<\/span>].content\n }.`;\n\n\n <span class=\"hljs-comment\">\/**\n  * Call the OpenAI SDK and get a response\n  *\/<\/span>\n <span class=\"hljs-keyword\">try<\/span> {\n   <span class=\"hljs-keyword\">const<\/span> response = await openai.chat.completions.create({\n     model: <span class=\"hljs-string\">\"gpt-3.5-turbo\"<\/span>,\n     messages: &#91;...messages, ...demoModel], <span class=\"hljs-comment\">\/\/ pass the new message and the previous messages<\/span>\n   });\n   res.json(response.choices&#91;<span class=\"hljs-number\">0<\/span>].message);\n } <span class=\"hljs-keyword\">catch<\/span> (error) {\n   console.error(error);\n   res.status(<span class=\"hljs-number\">500<\/span>).json({ error: <span class=\"hljs-string\">\"Internal Server Error\"<\/span> });\n }\n});\n\n\n<span class=\"hljs-comment\">\/**\n* Generate a random animal avatar\n* using DALLE\n*\/<\/span>\napp.post(<span class=\"hljs-string\">\"\/api\/avatar\"<\/span>, async (req, res) =&gt; {\n <span class=\"hljs-keyword\">const<\/span> requestData = {\n   prompt: `generate picture of animal`,\n   n: <span class=\"hljs-number\">2<\/span>,\n   size: <span class=\"hljs-string\">\"256x256\"<\/span>,\n };\n\n\n <span class=\"hljs-keyword\">try<\/span> {\n   <span class=\"hljs-keyword\">const<\/span> response = await fetch(\n     <span class=\"hljs-string\">\"https:\/\/api.openai.com\/v1\/images\/generations\"<\/span>,\n     {\n       method: <span class=\"hljs-string\">\"POST\"<\/span>,\n       headers: {\n         <span class=\"hljs-string\">\"Content-Type\"<\/span>: <span class=\"hljs-string\">\"application\/json\"<\/span>,\n         Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,\n       },\n       body: JSON.stringify(requestData),\n     }\n   );\n\n\n   <span class=\"hljs-keyword\">if<\/span> (response.ok) {\n     <span class=\"hljs-keyword\">const<\/span> data = await response.json();\n     console.log(<span class=\"hljs-string\">\"Response:\"<\/span>, data);\n     res.json(data.data);\n   } <span class=\"hljs-keyword\">else<\/span> {\n     <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> Error(`HTTP error! status: ${response.status}`);\n   }\n } <span class=\"hljs-keyword\">catch<\/span> (error) {\n   console.error(<span class=\"hljs-string\">\"Error:\"<\/span>, error);\n   res.status(<span class=\"hljs-number\">500<\/span>).json({ error: <span class=\"hljs-string\">\"Internal Server Error\"<\/span> });\n }\n});\n\n\n<span class=\"hljs-keyword\">const<\/span> PORT = <span class=\"hljs-number\">6000<\/span>;\napp.listen(PORT, () =&gt; {\n console.log(`Server is running on port ${PORT}`);\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><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>Let\u2019s explain the code we have on our server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Generate Conversations Using the OpenAI SDK<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><code>\/api\/chat endpoint<\/code><\/h4>\n\n\n\n<p>This code defines an endpoint for a chat application that integrates with <a href=\"https:\/\/platform.openai.com\/docs\/models\/gpt-3-5-turbo\">OpenAI&#8217;s GPT-3.5-turbo model<\/a> to generate responses based on user messages. Here&#8217;s a detailed explanation:<\/p>\n\n\n\n<p>1. <strong>Route definition:<\/strong><\/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 shcb-wrap-lines\"> app.post(<span class=\"hljs-string\">\"\/api\/chat\"<\/span>, <span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {<\/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>This line defines a POST endpoint at <code>\/api\/chat<\/code>. The <code>async<\/code> keyword indicates that the function will be handling asynchronous operations, which is crucial for making API calls.<\/p>\n\n\n\n<p>2. <strong>Demo model setup:<\/strong><\/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 shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> demoModel = &#91;\n        {\n          <span class=\"hljs-attr\">role<\/span>: <span class=\"hljs-string\">\"user\"<\/span>,\n          <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">\"Hi, can you tell me where to find information about the Cloudinary React sdk?\"<\/span>,\n        },\n        {\n          <span class=\"hljs-attr\">role<\/span>: <span class=\"hljs-string\">\"assistant\"<\/span>,\n          <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">\"Yes, the content can be found inside of this website https:\/\/cloudinary.com\/documentation\/react_integration\"<\/span>,\n        },\n        <span class=\"hljs-comment\">\/\/ Additional demo messages...<\/span>\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>This array <code>demoModel<\/code> simulates previous conversations. It includes several user and assistant interactions about using the <a href=\"https:\/\/cloudinary.com\/documentation\/react_integration\">Cloudinary React SDK<\/a>. These examples help guide the model by providing context.<\/p>\n\n\n\n<p>3. <strong>Handling incoming messages<\/strong>:<\/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 shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> { messages } = req.body;\n    messages&#91;messages.length - <span class=\"hljs-number\">1<\/span>].content = <span class=\"hljs-string\">`<span class=\"hljs-subst\">${messages&#91;messages.length - <span class=\"hljs-number\">1<\/span>].content}<\/span>.`<\/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>The code extracts the <code>messages<\/code> array from the request body. It also modifies the last message by appending a period to its content, ensuring proper punctuation.<\/p>\n\n\n\n<p>4. <strong>Calling OpenAI&#8217;s API<\/strong>:<\/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 shcb-wrap-lines\"> <span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> openai.chat.completions.create({\n        <span class=\"hljs-attr\">model<\/span>: <span class=\"hljs-string\">\"gpt-3.5-turbo\"<\/span>,\n        <span class=\"hljs-attr\">messages<\/span>: &#91;...messages, ...demoModel],\n      });\n      res.json(response.choices&#91;<span class=\"hljs-number\">0<\/span>].message);\n    } <span class=\"hljs-keyword\">catch<\/span> (error) {\n      <span class=\"hljs-built_in\">console<\/span>.error(error);\n      res.status(<span class=\"hljs-number\">500<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">\"Internal Server Error\"<\/span> });\n    }<\/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<ul class=\"wp-block-list\">\n<li>The <strong>try<\/strong> block attempts to call the<a href=\"https:\/\/platform.openai.com\/docs\/api-reference\/introduction\"> OpenAI API<\/a> to get a response from the <a href=\"https:\/\/platform.openai.com\/docs\/models\/gpt-3-5-turbo\">GPT-3.5-turbo model<\/a>.<\/li>\n\n\n\n<li><strong>openai.chat.completions.create<\/strong> is used to generate the response, passing both the incoming messages and the predefined <strong>demoModel<\/strong> to provide context.<\/li>\n\n\n\n<li>If successful, it sends the first choice&#8217;s message back as a JSON response.<\/li>\n\n\n\n<li>If an error occurs, it logs the error and responds with a 500 status code and an error message.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Generate Avatar Images With DALL-E<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><code>\/api\/chat endpoint<\/code><\/h4>\n\n\n\n<p>This code defines an endpoint for generating random animal avatars using OpenAI&#8217;s DALL-E model. Here&#8217;s a detailed explanation:<\/p>\n\n\n\n<p>1. <strong>Route definition:<\/strong><\/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 shcb-wrap-lines\">app.post(<span class=\"hljs-string\">\"\/api\/avatar\"<\/span>, <span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {<\/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 line defines a POST endpoint at <code>\/api\/avatar<\/code>. The <code>async<\/code> keyword indicates that the function will be handling asynchronous operations, which is necessary for making API calls.<\/p>\n\n\n\n<p>2. <strong>Request data setup:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> requestData = {\n<span class=\"hljs-attr\">prompt<\/span>: <span class=\"hljs-string\">`generate picture of animal`<\/span>,\n<span class=\"hljs-attr\">n<\/span>: <span class=\"hljs-number\">2<\/span>,\n<span class=\"hljs-attr\">size<\/span>: <span class=\"hljs-string\">\"256x256\"<\/span>,\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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 object, <code>requestData<\/code>, contains the parameters for the <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\/images\">DALL-E API<\/a> request:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>prompt<\/strong>. A text prompt instructing DALL-E to generate a picture of an animal.<\/li>\n\n\n\n<li><strong>n<\/strong>. Specifies that two images should be generated.<\/li>\n\n\n\n<li><strong>size<\/strong>. Specifies the size of the generated images (256&#215;256 pixels).<\/li>\n<\/ul>\n\n\n\n<p>3. <strong>Calling OpenAI&#8217;s API<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(\n      <span class=\"hljs-string\">\"https:\/\/api.openai.com\/v1\/images\/generations\"<\/span>,\n      {\n         <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">\"POST\"<\/span>,\n         <span class=\"hljs-attr\">headers<\/span>: {\n          \t<span class=\"hljs-string\">\"Content-Type\"<\/span>: <span class=\"hljs-string\">\"application\/json\"<\/span>,\n           <span class=\"hljs-attr\">Authorization<\/span>: <span class=\"hljs-string\">`Bearer <span class=\"hljs-subst\">${process.env.OPENAI_API_KEY}<\/span>`<\/span>,\n          },\n          <span class=\"hljs-attr\">body<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify(requestData),\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\">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<ul class=\"wp-block-list\">\n<li>The <strong>try<\/strong> block attempts to make a POST request to the OpenAI DALL-E API endpoint using the <strong>fetch<\/strong> function.<\/li>\n\n\n\n<li>The request includes:\n<ul class=\"wp-block-list\">\n<li><strong>method<\/strong>. Specifies the HTTP method (POST).<\/li>\n\n\n\n<li><strong>headers<\/strong>. Contains the content type (<code>application\/json<\/code>) and authorization header with the OpenAI API key.<\/li>\n\n\n\n<li><strong>body<\/strong>. The <strong>requestData<\/strong> object is converted to a JSON string and sent as the request body.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>4. <strong>Handling the response<\/strong>:<\/p>\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 shcb-wrap-lines\"> <span class=\"hljs-keyword\">if<\/span> (response.ok) {\n    <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> response.json();\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Response:\"<\/span>, data);\n    res.json(data.data);\n } <span class=\"hljs-keyword\">else<\/span> {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`HTTP error! status: <span class=\"hljs-subst\">${response.status}<\/span>`<\/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<ul class=\"wp-block-list\">\n<li>If the response from the API is successful (<code>response.ok<\/code>), it converts the response body to a JavaScript object using <code>response.json()<\/code>.<\/li>\n\n\n\n<li>It logs the response data to the console and sends the relevant part of the data (<code>data.data<\/code>) as a JSON response to the client.<\/li>\n\n\n\n<li>&nbsp;If the response isn\u2019t successful, it throws an error with the HTTP status code.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Part 4: Test the App<\/h2>\n\n\n\n<p>The first thing we have to do is to run<strong> <\/strong><code>npm install<\/code><strong> <\/strong>in the root of your project to install the frontend and backend dependencies.<br><\/p>\n\n\n\n<p>Dependencies:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>dotenv<\/strong>. Loads environment variables from a <code>.env<\/code> file into <code>process.env<\/code>, helping manage configuration settings securely.<\/li>\n\n\n\n<li><strong>express<\/strong>. A minimal and flexible Node.js web application framework that provides a robust set of features to build web and mobile applications.<\/li>\n\n\n\n<li><strong>node-fetch<\/strong>. A lightweight module that brings <code>window.fetch<\/code> to Node.js, allowing you to make HTTP requests from a server environment.<\/li>\n\n\n\n<li><strong>nodemon<\/strong>. A development tool that automatically restarts your Node.js application when a file changes in the directory is detected, improving the development workflow.<\/li>\n\n\n\n<li><strong>openai<\/strong>. The official OpenAI client library for accessing OpenAI&#8217;s API, including GPT-3 and DALL-E, to generate text and images.<\/li>\n\n\n\n<li><strong>react<\/strong>. A JavaScript library for building user interfaces, particularly single-page applications, by creating reusable UI components.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Run the Back-End Server<\/h3>\n\n\n\n<p>Open your terminal and run <strong>npm run start. <\/strong>Nodemon will run your express server in NodeJS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Run the Front-End Server<\/h3>\n\n\n\n<p>Open your other terminal run <strong>npm run dev <\/strong>and navigate to <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>.<br>You should see this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"599\" data-public-id=\"Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_599,c_scale\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA\" alt=\"\" class=\"wp-post-35321 wp-image-35329\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1724271446\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1724271446\/Web_Assets\/blog\/blog-Quick-Answers-Better-Experience-7\/blog-Quick-Answers-Better-Experience-7.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Part 5:<\/strong> Conclusion<\/h2>\n\n\n\n<p>We demonstrated how to create a powerful chatbot for your website to provide instant answers to queries from your developer documentation. With the chatbot, users can find the information they need faster and more efficiently, enhancing the developer experience and productivity.<br><br>Additionally, we&#8217;ve shown how to integrate features such as generating animal avatars using DALL-E, adding a fun and engaging element to your application. With tools like Express for backend handling, node-fetch for API requests, and <strong>dotenv<\/strong> for secure configuration, your chatbot can seamlessly provide valuable support to developers.<br><br><a href=\"https:\/\/cloudinary.com\/\">Contact us today<\/a> to learn more about how to save developer hours by using Cloudinary\u2019s Programmable Media, which enables you to implement comprehensive image and video upload, transformation, optimization, and delivery capabilities using your favorite programming languages.<br><br>To stay updated with the latest product features, follow <a href=\"https:\/\/twitter.com\/cloudinary\">Cloudinary<\/a> on Twitter, explore other <a href=\"https:\/\/github.com\/cloudinary-community\">sample apps<\/a>, and join our <a href=\"https:\/\/discord.gg\/AJWHaMuk\">Discord server<\/a> and<a href=\"https:\/\/community.cloudinary.com\/\"> Community forum<\/a>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GitHub Repo<\/strong>: <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-Chatbot-OpenAI-Demo\/tree\/main\">Cloudinary-Chatbot-OpenAI-Demo<\/a><\/li>\n\n\n\n<li><strong>Additional resources:<\/strong>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/egghead.io\/courses\/get-started-with-ai-driven-app-development-using-the-openai-node-js-sdk-b8d4b04e\">Get Started with AI-Driven App Development Using the OpenAI Node.js SDK<\/a> by Colby Fayock<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Quick access to accurate information is crucial in a development environment. The solution? Create a powerful chatbot that lives on your website and is designed to enhance the developer experience. Leveraging OpenAI, this chatbot will provide instant answers to queries from your developer documentation, helping users find what they need faster and more efficiently. In [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":35331,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[336,383,246],"class_list":["post-35321","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-ai","tag-nodejs","tag-react"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Building a Developer Chatbot With OpenAI, NodeJS, and React<\/title>\n<meta name=\"description\" content=\"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React\" \/>\n<meta property=\"og:description\" content=\"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-22T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-06T16:56:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1723847401\/quick_answers-blog\/quick_answers-blog-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React\",\"datePublished\":\"2024-08-22T14:00:00+00:00\",\"dateModified\":\"2024-09-06T16:56:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\"},\"wordCount\":1451,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA\",\"keywords\":[\"AI\",\"Node(JS)\",\"React\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2024\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\",\"url\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\",\"name\":\"Building a Developer Chatbot With OpenAI, NodeJS, and React\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA\",\"datePublished\":\"2024-08-22T14:00:00+00:00\",\"dateModified\":\"2024-09-06T16:56:19+00:00\",\"description\":\"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building a Developer Chatbot With OpenAI, NodeJS, and React","description":"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.","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:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react","og_locale":"en_US","og_type":"article","og_title":"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React","og_description":"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.","og_url":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react","og_site_name":"Cloudinary Blog","article_published_time":"2024-08-22T14:00:00+00:00","article_modified_time":"2024-09-06T16:56:19+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1723847401\/quick_answers-blog\/quick_answers-blog-jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React","datePublished":"2024-08-22T14:00:00+00:00","dateModified":"2024-09-06T16:56:19+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react"},"wordCount":1451,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA","keywords":["AI","Node(JS)","React"],"inLanguage":"en-US","copyrightYear":"2024","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react","url":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react","name":"Building a Developer Chatbot With OpenAI, NodeJS, and React","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA","datePublished":"2024-08-22T14:00:00+00:00","dateModified":"2024-09-06T16:56:19+00:00","description":"Build a chatbot, train an OpenAI model, and generate an image with the DALL-E API.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/quick-answers-better-experience-chatbot-openai-nodejs-react#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Quick Answers, Better Experience: Building a Developer Chatbot With OpenAI, NodeJS, and React"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1723847401\/quick_answers-blog\/quick_answers-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35321","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=35321"}],"version-history":[{"count":4,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35321\/revisions"}],"predecessor-version":[{"id":35531,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35321\/revisions\/35531"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/35331"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=35321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=35321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=35321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}