{"id":36328,"date":"2024-11-20T07:00:00","date_gmt":"2024-11-20T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=36328"},"modified":"2025-03-03T15:57:22","modified_gmt":"2025-03-03T23:57:22","slug":"fashion-app-genai-react-node-js","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js","title":{"rendered":"Building a Fashion App Using Cloudinary&#8217;s GenAI in React and Node.js"},"content":{"rendered":"\n<p>The FashionistaAI app uses <a href=\"https:\/\/cloudinary.com\/products\/cloudinary_ai\">Cloudinary\u2019s GenAI<\/a> technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will generate four elegant, streetwear, sporty, and business casual outfits styles to suit your unique preferences.&nbsp;<\/p>\n\n\n\n<p>In this blog post we\u2019ll walk you through how we built the app using Cloudinary\u2019s GenAI features, React SDK on the frontend, and Node.js SDK on the backend to handle image uploads. If you\u2019re interested in fashion, cutting-edge AI, or both, this guide is for you!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"664\" data-public-id=\"Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_664,c_scale\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA\" alt=\"\" class=\"wp-post-36328 wp-image-36329\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1732145462\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145462\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-1.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">An example of a FashionistaAIn output. The background of the images changes to match the model\u2019s outfit.<\/figcaption><\/figure>\n\n\n\n<p><strong>GitHub Repo<\/strong>: <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-FashionistaAI\">Cloudinary-FashionistaAI<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Part 1: Set Up Cloudinary<\/h2>\n\n\n\n<p>To begin, log in to your <a href=\"https:\/\/cloudinary.com\/\">Cloudinary account or create a free account<\/a>. If prompted with the question, \u201cWhat\u2019s your main interest?\u201d, select <strong>Coding with APIs and SDKs<\/strong> or <strong>Skip<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"400\" data-public-id=\"Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_400,c_scale\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA\" alt=\"\" class=\"wp-post-36328 wp-image-36330\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1732145456\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145456\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-2.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Cloudinary Cloud<\/h3>\n\n\n\n<p>In your account, select <strong>Settings <\/strong>&gt;<strong> Product Environments<\/strong>. Here, you\u2019ll see the cloud that you\u2019ve created. Let\u2019s click the three-dot menu to edit your Cloudinary Cloud Name.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"597\" data-public-id=\"Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_597,c_scale\/f_auto,q_auto\/v1732145452\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png?_i=AA\" alt=\"\" class=\"wp-post-36328 wp-image-36331\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1732145452\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145452\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png?_i=AA 1183w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145452\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145452\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145452\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-3.png?_i=AA 1024w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Edit the product environment and name your cloud, then click <strong>Save Changes<\/strong>.<\/p>\n\n\n\n<p>It\u2019s important to keep the same cloud name across different tools to be consistent.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"597\" data-public-id=\"Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_597,c_scale\/f_auto,q_auto\/v1732145448\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png?_i=AA\" alt=\"\" class=\"wp-post-36328 wp-image-36332\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1732145448\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145448\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png?_i=AA 1183w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145448\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145448\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1732145448\/Web_Assets\/blog\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4\/blog-Building-a-Fashion-App-Using-Cloudinarys-GenAI-in-React-and-Node.js-4.png?_i=AA 1024w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Get Cloudinary API Keys<\/h3>\n\n\n\n<p>In your account, select <strong>Settings <\/strong>&gt;<strong> Product Environments Setting<\/strong> &gt;<strong> API Keys<\/strong>. Click <strong>Generate New API Key <\/strong>and save these credentials in a safe place. We\u2019ll use them later.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Part 2:<strong> <\/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 that you 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 FashionistaAI app<\/h3>\n\n\n\n<p>In your <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-FashionistaAI\/blob\/main\/src\/App.tsx\"><strong>App.tsx<\/strong><\/a> 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=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React, { useState, useEffect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'axios'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'.\/App.css'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { AdvancedImage } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { fill } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen\/actions\/resize'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Cloudinary, CloudinaryImage } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> {\n  generativeReplace,\n  generativeRecolor,\n  generativeRestore,\n  generativeBackgroundReplace,\n} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen\/actions\/effect'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> App: React.FC = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  type StyleKeys = <span class=\"hljs-string\">'top'<\/span> | <span class=\"hljs-string\">'bottom'<\/span> | <span class=\"hljs-string\">'background'<\/span> | <span class=\"hljs-string\">'type'<\/span>;\n  <span class=\"hljs-keyword\">const<\/span> &#91;image, setImage] = useState&lt;any | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;images, setImages] = useState&lt;CloudinaryImage&#91;]&gt;(&#91;]);\n  <span class=\"hljs-keyword\">const<\/span> &#91;error, setError] = useState&lt;string&gt;(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;loading, setLoading] = useState&lt;boolean&gt;(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;loadingStatus, setLoadingStatus] = useState&lt;boolean&#91;]&gt;(&#91;]); <span class=\"hljs-comment\">\/\/ Track loading status for each image<\/span>\n  <span class=\"hljs-keyword\">const<\/span> &#91;shouldSubmit, setShouldSubmit] = useState&lt;boolean&gt;(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;openModal, setOpenModal] = useState(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;color, setColor] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;selectedItem, setSelectedItem] = useState&lt;StyleKeys&gt;(<span class=\"hljs-string\">'top'<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;selectedImage, setSelectedImage] = useState(<span class=\"hljs-number\">0<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> styles = &#91;\n    { <span class=\"hljs-attr\">top<\/span>: <span class=\"hljs-string\">'suit jacket for upper body'<\/span>, <span class=\"hljs-attr\">bottom<\/span>: <span class=\"hljs-string\">'suit pants for lower body'<\/span>, <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-string\">'office'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'business casual'<\/span> },\n    { <span class=\"hljs-attr\">top<\/span>: <span class=\"hljs-string\">'sport tshirt for upper body'<\/span>, <span class=\"hljs-attr\">bottom<\/span>: <span class=\"hljs-string\">'sport shorts for lower body'<\/span>, <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-string\">'gym'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'sporty'<\/span> },\n    { <span class=\"hljs-attr\">top<\/span>: <span class=\"hljs-string\">'streetwear shirt for upper body'<\/span>, <span class=\"hljs-attr\">bottom<\/span>: <span class=\"hljs-string\">'streetwear pants for lower body'<\/span>, <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-string\">'street'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'streetwear'<\/span> },\n    { <span class=\"hljs-attr\">top<\/span>: <span class=\"hljs-string\">'elegant tuxedo for upper body'<\/span>, <span class=\"hljs-attr\">bottom<\/span>: <span class=\"hljs-string\">'elegant tuxedo pants for lower body'<\/span>, <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-string\">'gala'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'elegant'<\/span> },\n  ];\n\n  <span class=\"hljs-keyword\">const<\/span> cld = <span class=\"hljs-keyword\">new<\/span> Cloudinary({\n    <span class=\"hljs-attr\">cloud<\/span>: {\n      <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">'YOUR CLOUDINARY CLOUD NAME'<\/span>,\n    },\n  });\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">if<\/span> (shouldSubmit &amp;&amp; image) {\n      handleSubmit();\n    }\n  }, &#91;shouldSubmit, image]);\n\n  <span class=\"hljs-keyword\">const<\/span> handleImageChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: React.ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">if<\/span> (e.target.files &amp;&amp; e.target.files&#91;<span class=\"hljs-number\">0<\/span>]) {\n      setImage(e.target.files&#91;<span class=\"hljs-number\">0<\/span>]);\n      setShouldSubmit(<span class=\"hljs-literal\">true<\/span>);\n    }\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> handleSubmit = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    setImage(<span class=\"hljs-literal\">null<\/span>);\n    setImages(&#91;]);\n    setLoadingStatus(&#91;]);\n    <span class=\"hljs-keyword\">if<\/span> (!image) {\n      alert(<span class=\"hljs-string\">'Please select an image to upload'<\/span>);\n      setShouldSubmit(<span class=\"hljs-literal\">false<\/span>);\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n\n    <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData();\n    formData.append(<span class=\"hljs-string\">'image'<\/span>, image);\n\n    <span class=\"hljs-keyword\">try<\/span> {\n      setLoading(<span class=\"hljs-literal\">true<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> axios.post(<span class=\"hljs-string\">'\/api\/generate'<\/span>, formData, {\n        <span class=\"hljs-attr\">headers<\/span>: {\n          <span class=\"hljs-string\">'Content-Type'<\/span>: <span class=\"hljs-string\">'multipart\/form-data'<\/span>,\n        },\n      });\n      <span class=\"hljs-keyword\">const<\/span> image = cld.image(response.data.public_id);\n      image.resize(fill().width(<span class=\"hljs-number\">508<\/span>).height(<span class=\"hljs-number\">508<\/span>));\n      setImage(image);\n      generateImages(response.data.public_id);\n      setLoading(<span class=\"hljs-literal\">false<\/span>);\n      setError(<span class=\"hljs-string\">''<\/span>); <span class=\"hljs-comment\">\/\/ Clear any previous error messages<\/span>\n    } <span class=\"hljs-keyword\">catch<\/span> (error) {\n      <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Error uploading image:'<\/span>, error);\n      setError(<span class=\"hljs-string\">'Error uploading image: '<\/span> + (error <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-built_in\">Error<\/span>).message);\n      setLoading(<span class=\"hljs-literal\">false<\/span>);\n    } <span class=\"hljs-keyword\">finally<\/span> {\n      setShouldSubmit(<span class=\"hljs-literal\">false<\/span>);\n      setLoading(<span class=\"hljs-literal\">false<\/span>);\n    }\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> handleImageLoading = <span class=\"hljs-function\">(<span class=\"hljs-params\">image: CloudinaryImage, index: number, attempts = <span class=\"hljs-number\">0<\/span><\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> url = image.toURL();\n    <span class=\"hljs-keyword\">const<\/span> img = <span class=\"hljs-keyword\">new<\/span> Image();\n    img.src = url;\n\n    img.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n        <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n        newStatus&#91;index] = <span class=\"hljs-literal\">false<\/span>; <span class=\"hljs-comment\">\/\/ Image has finished loading<\/span>\n        <span class=\"hljs-keyword\">return<\/span> newStatus;\n      });\n    };\n\n    img.onerror = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n      <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">`Error loading image at index <span class=\"hljs-subst\">${index}<\/span>, Attempt <span class=\"hljs-subst\">${attempts + <span class=\"hljs-number\">1<\/span>}<\/span>`<\/span>);\n\n      <span class=\"hljs-comment\">\/\/ Check if 423 status was returned (this requires you to use a proxy server or inspect headers)<\/span>\n      <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(url);\n      <span class=\"hljs-keyword\">if<\/span> (response.status === <span class=\"hljs-number\">423<\/span>) {\n        <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`423 error received. Retrying image load in 5 seconds... (Attempt <span class=\"hljs-subst\">${attempts + <span class=\"hljs-number\">1<\/span>}<\/span>)`<\/span>);\n        setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> handleImageLoading(image, index, attempts + <span class=\"hljs-number\">1<\/span>), <span class=\"hljs-number\">5000<\/span>);\n      } <span class=\"hljs-keyword\">else<\/span> {\n        <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Max retries reached or non-423 error. Image failed to load.'<\/span>);\n        setError(<span class=\"hljs-string\">'Error loading image. Max retries reached.'<\/span>);\n        setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n          <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n          newStatus&#91;index] = <span class=\"hljs-literal\">false<\/span>; <span class=\"hljs-comment\">\/\/ Stop spinner even if loading fails<\/span>\n          <span class=\"hljs-keyword\">return<\/span> newStatus;\n        });\n      }\n    };\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> generateImages = <span class=\"hljs-function\">(<span class=\"hljs-params\">publicId: string<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> genAIImages: CloudinaryImage&#91;] = &#91;];\n    <span class=\"hljs-keyword\">const<\/span> newLoadingStatus: boolean&#91;] = &#91;];\n\n    styles.forEach(<span class=\"hljs-function\">(<span class=\"hljs-params\">style, index<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> image = cld.image(publicId);\n      image.effect(generativeReplace().from(<span class=\"hljs-string\">'shirt'<\/span>).to(style.top));\n      image.effect(generativeReplace().from(<span class=\"hljs-string\">'pants'<\/span>).to(style.bottom));\n      image.effect(generativeBackgroundReplace());\n      image.effect(generativeRestore());\n      image.resize(fill().width(<span class=\"hljs-number\">500<\/span>).height(<span class=\"hljs-number\">500<\/span>));\n      genAIImages.push(image);\n      newLoadingStatus.push(<span class=\"hljs-literal\">true<\/span>); <span class=\"hljs-comment\">\/\/ Set initial loading status<\/span>\n      handleImageLoading(image, index); <span class=\"hljs-comment\">\/\/ Start loading image<\/span>\n    });\n\n    setImages(genAIImages);\n    setLoadingStatus(newLoadingStatus);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> onHandleSelectImage = <span class=\"hljs-function\">(<span class=\"hljs-params\">index: number<\/span>) =&gt;<\/span> {\n    setOpenModal(!openModal);\n    setSelectedImage(index);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> onHandleChangeItemsColor = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> genAIImagesCopy = &#91;...images];\n    <span class=\"hljs-keyword\">const<\/span> tempImage = genAIImagesCopy&#91;selectedImage];\n\n    <span class=\"hljs-comment\">\/\/ Show spinner and hide modal<\/span>\n    setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n      newStatus&#91;selectedImage] = <span class=\"hljs-literal\">true<\/span>; <span class=\"hljs-comment\">\/\/ Set loading to true for the selected image<\/span>\n      <span class=\"hljs-keyword\">return<\/span> newStatus;\n    });\n    setOpenModal(<span class=\"hljs-literal\">false<\/span>); <span class=\"hljs-comment\">\/\/ Close the modal<\/span>\n\n    <span class=\"hljs-comment\">\/\/ Change color<\/span>\n    tempImage.effect(generativeRecolor(styles&#91;selectedImage]&#91;selectedItem], color));\n\n    <span class=\"hljs-comment\">\/\/ Once done, update state and hide spinner<\/span>\n    setImages(genAIImagesCopy);\n    handleImageLoading(tempImage, selectedImage); <span class=\"hljs-comment\">\/\/ Trigger reloading of the image<\/span>\n  };\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Updated images array:'<\/span>, images); <span class=\"hljs-comment\">\/\/ Log after images state is updated<\/span>\n  }, &#91;images]);\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"app\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Fashionista AI<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> e.preventDefault()}&gt;\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"custom-file-upload\"<\/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\">\"file\"<\/span> <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"image\/*\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleImageChange}<\/span> \/&gt;<\/span>\n          Choose File\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n      {loading &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"spinner\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>}\n      {error &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">color:<\/span> '<span class=\"hljs-attr\">red<\/span>' }}&gt;<\/span>{error}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>}\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n        {image &amp;&amp; !loading &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">AdvancedImage<\/span> <span class=\"hljs-attr\">cldImg<\/span>=<span class=\"hljs-string\">{image}<\/span> \/&gt;<\/span>}\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"grid-container\"<\/span>&gt;<\/span>\n          {images.map((image: CloudinaryImage, index: number) =&gt; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>&gt;<\/span>\n              {loadingStatus&#91;index] ? (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"spinner\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              ) : (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">AdvancedImage<\/span> <span class=\"hljs-attr\">cldImg<\/span>=<span class=\"hljs-string\">{image}<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> onHandleSelectImage(index)} \/&gt;\n              )}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          ))}\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      {openModal &amp;&amp; (\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"modal-overlay\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"modal\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"close-icon\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setOpenModal(false)}&gt;\n              <span class=\"hljs-symbol\">&amp;times;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Pick an Item to Change The Color<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span>\n          <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"top\"<\/span>\n          <span class=\"hljs-attr\">checked<\/span>=<span class=\"hljs-string\">{selectedItem<\/span> === <span class=\"hljs-string\">'top'<\/span>}\n          <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span>=&gt;<\/span>setSelectedItem(e.target.value as StyleKeys)}\n        \/&gt;\n        Top\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span>\n          <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"bottom\"<\/span>\n          <span class=\"hljs-attr\">checked<\/span>=<span class=\"hljs-string\">{selectedItem<\/span> === <span class=\"hljs-string\">'bottom'<\/span>}\n          <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span>=&gt;<\/span>setSelectedItem(e.target.value as StyleKeys)}\n        \/&gt;\n        Bottom\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/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\">\"color\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{color}<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> setColor(e.target.value)} \/&gt;\n            {color &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{onHandleChangeItemsColor}<\/span>&gt;<\/span>Change Item Color<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      )}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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\u2019s explain our frontend code:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Cloudinary Configuration<\/h4>\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\">const<\/span> cld = <span class=\"hljs-keyword\">new<\/span> Cloudinary({\n    <span class=\"hljs-attr\">cloud<\/span>: {\n      <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">'YOUR CLOUDINARY CLOUD NAME'<\/span>,\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>handleImageChange<\/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\"><span class=\"hljs-keyword\">const<\/span> handleImageChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: React.ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">if<\/span> (e.target.files &amp;&amp; e.target.files&#91;<span class=\"hljs-number\">0<\/span>]) {\n    setImage(e.target.files&#91;<span class=\"hljs-number\">0<\/span>]);\n    setShouldSubmit(<span class=\"hljs-literal\">true<\/span>);\n  }\n};\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<ul class=\"wp-block-list\">\n<li>This function is triggered when a user selects an image from the file input.<\/li>\n\n\n\n<li>It checks if a file is selected and, if so, updates the <strong><em>image<\/em><\/strong> state with the selected file.<\/li>\n\n\n\n<li>The <strong><em>setShouldSubmit(true)<\/em><\/strong> triggers the `handleSubmit` function by setting a flag.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">handleSubmit<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" 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> handleSubmit = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n  setImage(<span class=\"hljs-literal\">null<\/span>);           \n  setImages(&#91;]);            \n  setLoadingStatus(&#91;]);      \n  <span class=\"hljs-keyword\">if<\/span> (!image) {\n    alert(<span class=\"hljs-string\">'Please select an image to upload'<\/span>);\n    setShouldSubmit(<span class=\"hljs-literal\">false<\/span>);  \n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData();  \n  formData.append(<span class=\"hljs-string\">'image'<\/span>, image);\n\n  <span class=\"hljs-keyword\">try<\/span> {\n    setLoading(<span class=\"hljs-literal\">true<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> axios.post(<span class=\"hljs-string\">'\/api\/generate'<\/span>, formData, {\n      <span class=\"hljs-attr\">headers<\/span>: {\n        <span class=\"hljs-string\">'Content-Type'<\/span>: <span class=\"hljs-string\">'multipart\/form-data'<\/span>,\n      },\n    });\n\n<span class=\"hljs-keyword\">const<\/span> image = cld.image(response.data.public_id);      image.resize(fill().width(<span class=\"hljs-number\">508<\/span>).height(<span class=\"hljs-number\">508<\/span>));\nsetImage(image);                                       generateImages(response.data.public_id);               setLoading(<span class=\"hljs-literal\">false<\/span>);                                     setError(<span class=\"hljs-string\">''<\/span>);                                        \n} <span class=\"hljs-keyword\">catch<\/span> (error) {\n    <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Error uploading image:'<\/span>, error);\n    setError(<span class=\"hljs-string\">'Error uploading image: '<\/span> + (error <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-built_in\">Error<\/span>).message);\n    setLoading(<span class=\"hljs-literal\">false<\/span>);  \n  } <span class=\"hljs-keyword\">finally<\/span> {\n    setShouldSubmit(<span class=\"hljs-literal\">false<\/span>);\n    setLoading(<span class=\"hljs-literal\">false<\/span>);\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\">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>This function is responsible for handling the form submission when an image is uploaded.<\/li>\n\n\n\n<li>First, it resets the <strong><em>image<\/em><\/strong>, <strong><em>images<\/em><\/strong>, and <strong><em>loadingStatus<\/em><\/strong> state to ensure no residual data from previous uploads.<\/li>\n\n\n\n<li>If no image is selected, it alerts the user and stops the submission.<\/li>\n\n\n\n<li>If an image is selected, it creates a <strong><em>FormData<\/em><\/strong> object and sends the image via a POST request to the <strong><em>\/api\/generate<\/em><\/strong> endpoint.<\/li>\n\n\n\n<li>Upon successful upload, it gets the public ID of the uploaded image from the server, creates a <strong><em>CloudinaryImage<\/em><\/strong> object, resizes it, and calls <strong><em>generateImages<\/em><\/strong> to generate styled images.<\/li>\n\n\n\n<li>It handles errors and sets error messages appropriately if the upload fails.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">handleImageLoading<\/h4>\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\"><span class=\"hljs-keyword\">const<\/span> handleImageLoading = <span class=\"hljs-function\">(<span class=\"hljs-params\">image: CloudinaryImage, index: number, attempts = <span class=\"hljs-number\">0<\/span><\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> url = image.toURL();\n  <span class=\"hljs-keyword\">const<\/span> img = <span class=\"hljs-keyword\">new<\/span> Image();\n  img.src = url;\n\n  img.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n      newStatus&#91;index] = <span class=\"hljs-literal\">false<\/span>;\n      <span class=\"hljs-keyword\">return<\/span> newStatus;\n    });\n  };\n\n  img.onerror = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">`Error loading image at index <span class=\"hljs-subst\">${index}<\/span>, Attempt <span class=\"hljs-subst\">${attempts + <span class=\"hljs-number\">1<\/span>}<\/span>`<\/span>);\n\n    <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(url);\n    <span class=\"hljs-keyword\">if<\/span> (response.status === <span class=\"hljs-number\">423<\/span>) {\n      <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`423 error received. Retrying image load in 5 seconds... (Attempt <span class=\"hljs-subst\">${attempts + <span class=\"hljs-number\">1<\/span>}<\/span>)`<\/span>);\n      setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> handleImageLoading(image, index, attempts + <span class=\"hljs-number\">1<\/span>), <span class=\"hljs-number\">5000<\/span>);\n    } <span class=\"hljs-keyword\">else<\/span> {\n      <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Max retries reached or non-423 error. Image failed to load.'<\/span>);\n      setError(<span class=\"hljs-string\">'Error loading image. Max retries reached.'<\/span>);\n      setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n        <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n        newStatus&#91;index] = <span class=\"hljs-literal\">false<\/span>;\n        <span class=\"hljs-keyword\">return<\/span> newStatus;\n      });\n    }\n  };\n};\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<ul class=\"wp-block-list\">\n<li>This function handles the loading status of each generated image.<\/li>\n\n\n\n<li>It checks whether an image successfully loads via <strong><em>img.onload<\/em><\/strong>.<\/li>\n\n\n\n<li>If the image fails to load due to a network issue or a specific error (such as HTTP status 423), it retries the image loading after five seconds.\n<ul class=\"wp-block-list\">\n<li>Initial transformation requests may result in a 423 error response while the transformation is being processed. You can prepare derived versions in advance using an <a href=\"https:\/\/cloudinary.com\/documentation\/eager_and_incoming_transformations#eager_transformations\">eager transformation<\/a>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>If the image fails multiple times, it gives up and updates the state to stop loading and displays an error.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">generateImages<\/h4>\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> generateImages = <span class=\"hljs-function\">(<span class=\"hljs-params\">publicId: string<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> genAIImages: CloudinaryImage&#91;] = &#91;];\n  <span class=\"hljs-keyword\">const<\/span> newLoadingStatus: boolean&#91;] = &#91;];\n\n  styles.forEach(<span class=\"hljs-function\">(<span class=\"hljs-params\">style, index<\/span>) =&gt;<\/span> {\n   \t<span class=\"hljs-keyword\">const<\/span> image = cld.image(publicId);\timage.effect(generativeReplace().from(<span class=\"hljs-string\">'shirt'<\/span>).to(style.top));     image.effect(generativeReplace().from(<span class=\"hljs-string\">'pants'<\/span>).to(style.bottom));  \n    image.effect(generativeBackgroundReplace());\n    image.effect(generativeRestore());\n    image.resize(fill().width(<span class=\"hljs-number\">500<\/span>).height(<span class=\"hljs-number\">500<\/span>));\n    genAIImages.push(image);\n    newLoadingStatus.push(<span class=\"hljs-literal\">true<\/span>);\n    handleImageLoading(image, index);\n  });\n\n  setImages(genAIImages);          \n  setLoadingStatus(newLoadingStatus);\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<ul class=\"wp-block-list\">\n<li>This function generates the AI-modified images based on the selected <strong><em>styles<\/em><\/strong>.<\/li>\n\n\n\n<li>It loops through the predefined <strong><em>styles<\/em><\/strong> array, applying generative AI transformations to each image using Cloudinary&#8217;s effects:<\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/effects_and_artistic_enhancements#generative_replace\"><strong><em>generativeReplace()<\/em><\/strong><\/a> modifies the clothing items (top and bottom) with the selected style.<\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/effects_and_artistic_enhancements#generative_background_replace\"><strong><em>generativeBackgroundReplace()<\/em><\/strong><\/a> changes the background.<\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/effects_and_artistic_enhancements#generative_restore-1\"><strong><em>generativeRestore()<\/em><\/strong><\/a> enhances the image quality.<\/li>\n\n\n\n<li>After applying these transformations, it resizes the image and adds it to the <strong><em>genAIImages<\/em><\/strong> array.<\/li>\n\n\n\n<li>The <strong><em>handleImageLoading<\/em><\/strong> function is called to track the loading status of each generated image.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">onHandleSelectImage<\/h4>\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> onHandleSelectImage = <span class=\"hljs-function\">(<span class=\"hljs-params\">index: number<\/span>) =&gt;<\/span> {\n  setOpenModal(!openModal);\n  setSelectedImage(index);\n};<\/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<ul class=\"wp-block-list\">\n<li>This function opens or closes the recoloring modal when a user clicks on a generated image.<\/li>\n\n\n\n<li>It also sets the <strong><em>selectedImage<\/em><\/strong> state, which keeps track of which image is currently selected for recoloring.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">onHandleChangeItemsColor<\/h4>\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\">const<\/span> onHandleChangeItemsColor = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> genAIImagesCopy = &#91;...images];\n  <span class=\"hljs-keyword\">const<\/span> tempImage = genAIImagesCopy&#91;selectedImage];\n\n  setLoadingStatus(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> newStatus = &#91;...prev];\n    newStatus&#91;selectedImage] = <span class=\"hljs-literal\">true<\/span>;\n    <span class=\"hljs-keyword\">return<\/span> newStatus;\n  });\n  setOpenModal(<span class=\"hljs-literal\">false<\/span>);    tempImage.effect(generativeRecolor(styles&#91;selectedImage]&#91;selectedItem], color));\n  setImages(genAIImagesCopy);\n  handleImageLoading(tempImage, selectedImage);\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>This function is triggered when a user selects a new color for a clothing item (top or bottom).<\/li>\n\n\n\n<li>It creates a copy of the <strong><em>images<\/em><\/strong> array, applies the <a href=\"https:\/\/cloudinary.com\/documentation\/effects_and_artistic_enhancements#generative_recolor\">generativeRecolor()<\/a> effect to the selected item with the chosen color, and updates the image.<\/li>\n\n\n\n<li>It also sets the loading status for the selected image to show a spinner while the recoloring is processed.<br><\/li>\n<\/ul>\n\n\n\n<p>Let\u2019s now style the app. In your app, replace the code inside the <strong>App.css<\/strong> with the code inside this <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-FashionistaAI\/blob\/main\/src\/App.css\">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 Node.js, 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 <strong>vite.config.js<\/strong> file and replace the content with the following code.<\/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\"><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:8000\"<\/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});<\/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>What we\u2019re doing here is proxying the backend with any path that is <strong>\/api<\/strong> to be forwarded to the target <a href=\"http:\/\/localhost:8000\"><strong>http:\/\/localhost:8000<\/strong><\/a>, which is the address of your backend server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Part 3: Build the Node.js App<\/h2>\n\n\n\n<p>Time to work on the backend. In the root of your React app, create a file called <strong>server.js<\/strong> file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Set Up Your Node.js Server<\/h3>\n\n\n\n<p>In the root of the project you have the <strong>package.json<\/strong>, we will use this same file for our backend. Replace everything that you currently have in the <strong>package.json<\/strong> copy and paste the content of <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-FashionistaAI\/blob\/main\/package.json\">this file<\/a> into your <strong>package.json<\/strong>.<br>In the root of your project create a <strong>.env<\/strong> file, and enter the following:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">CLOUDINARY_CLOUD_NAME=YOUR CLOUDINARY CLOUD NAME\nCLOUDINARY_API_KEY=YOUR CLOUDINARY API KEY\nCLOUDINARY_API_SECRET=CLOUDINARY SECRET<\/code><\/span><\/pre>\n\n\n<p>Copy and paste the following code into your <strong>server.js<\/strong> file.<\/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-comment\">\/* eslint-disable no-undef *\/<\/span>\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'dotenv\/config.js'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> express <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'express'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cors <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cors'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> multer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'multer'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> streamifier <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'streamifier'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> path <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'path'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { fileURLToPath } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"url\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> __filename = fileURLToPath(<span class=\"hljs-keyword\">import<\/span>.meta.url);\n<span class=\"hljs-keyword\">const<\/span> __dirname = path.dirname(__filename);\n\n<span class=\"hljs-keyword\">const<\/span> app = express();\napp.use(express.json());\napp.use(cors());\n\n<span class=\"hljs-comment\">\/\/ Configure Cloudinary with secure URLs and credentials<\/span>\ncloudinary.config({\n  <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  <span class=\"hljs-attr\">cloud_name<\/span>: process.env.CLOUDINARY_CLOUD_NAME,\n  <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n  <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n});\n\n<span class=\"hljs-comment\">\/\/ Configure multer for file upload<\/span>\n<span class=\"hljs-keyword\">const<\/span> storage = multer.memoryStorage();\n<span class=\"hljs-keyword\">const<\/span> upload = multer({ <span class=\"hljs-attr\">storage<\/span>: storage });\n\n<span class=\"hljs-comment\">\/\/ Define a POST endpoint to handle image upload<\/span>\napp.post(<span class=\"hljs-string\">'\/api\/generate'<\/span>, upload.single(<span class=\"hljs-string\">'image'<\/span>), (req, res) =&gt; {\n  <span class=\"hljs-keyword\">if<\/span> (!req.file) {\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">400<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'Image file is required'<\/span> });\n  }\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Uploading image'<\/span>, req.file);\n\n  <span class=\"hljs-keyword\">const<\/span> uploadStream = cloudinary.uploader.upload_stream(\n    {\n        <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"image\"<\/span>,\n    },\n     <span class=\"hljs-keyword\">async<\/span> (error, result) =&gt; {\n      <span class=\"hljs-keyword\">if<\/span> (error) {\n        <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Cloudinary error:'<\/span>, error);\n        <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">500<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: error.message });\n      }\n      \n      <span class=\"hljs-keyword\">const<\/span> resObj = {\n        ...result\n      }\n      <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Image uploaded to Cloudinary:'<\/span>, resObj);\n      res.json(resObj);\n    }\n  );\n\n  streamifier.createReadStream(req.file.buffer).pipe(uploadStream);\n});\n\napp.use(express.static(path.resolve(__dirname, <span class=\"hljs-string\">\"public\"<\/span>)));\n\n<span class=\"hljs-keyword\">const<\/span> PORT = <span class=\"hljs-number\">8000<\/span>;\napp.listen(PORT, () =&gt; {\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`Server is running on port <span class=\"hljs-subst\">${PORT}<\/span>`<\/span>);\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\">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\u2019s explain the code we have on our server.<\/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\">import<\/span> <span class=\"hljs-string\">'dotenv\/config.js'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> express <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'express'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cors <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cors'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> multer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'multer'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> streamifier <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'streamifier'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> path <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'path'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { fileURLToPath } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"url\"<\/span>;<\/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><strong>dotenv\/config.js<\/strong>. Loads environment variables from a <strong>.env<\/strong> file.<\/li>\n\n\n\n<li><strong>express.<\/strong> Web framework for creating the server.<\/li>\n\n\n\n<li><strong>cors<\/strong>. Middleware to enable Cross-Origin Resource Sharing.<\/li>\n\n\n\n<li><strong>cloudinary<\/strong>. For image upload and processing.<\/li>\n\n\n\n<li><strong>multer<\/strong>. Middleware for handling `multipart\/form-data`, used for file uploads.<\/li>\n\n\n\n<li><strong>streamifier<\/strong>. Converts a buffer into a readable stream.<\/li>\n\n\n\n<li><strong>path, fileURLToPath, fs\/promises<\/strong>. Utilities for handling file paths and file operations.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Cloudinary Configuration<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">cloudinary<\/span><span class=\"hljs-selector-class\">.config<\/span>({\n  <span class=\"hljs-attribute\">secure<\/span>: true,\n  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,\n  api_key: process.env.CLOUDINARY_API_KEY,\n  api_secret: process.env.CLOUDINARY_API_SECRET,\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><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<ul class=\"wp-block-list\">\n<li>Configures Cloudinary with secure URLs and credentials from environment variables.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Multer Configuration<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" 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> storage = multer.memoryStorage();\n<span class=\"hljs-keyword\">const<\/span> upload = multer({ <span class=\"hljs-attr\">storage<\/span>: storage });<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><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>Configures Multer to store uploaded files in memory.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" 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\/generate'<\/span>, upload.single(<span class=\"hljs-string\">'image'<\/span>), (req, res) =&gt; {\n  <span class=\"hljs-keyword\">if<\/span> (!req.file) {\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">400<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'Image file is required'<\/span> });\n  }\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Uploading image'<\/span>, req.file);\n\n  <span class=\"hljs-keyword\">const<\/span> uploadStream = cloudinary.uploader.upload_stream(\n    {\n        <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">\"image\"<\/span>,\n    },\n     <span class=\"hljs-keyword\">async<\/span> (error, result) =&gt; {\n      <span class=\"hljs-keyword\">if<\/span> (error) {\n        <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Cloudinary error:'<\/span>, error);\n        <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">500<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: error.message });\n      }\n \n      <span class=\"hljs-keyword\">const<\/span> resObj = {\n        ...result\n      }\n      <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Image uploaded to Cloudinary:'<\/span>, resObj);\n      res.json(resObj);\n    }\n  );\n streamifier.createReadStream(req.file.buffer).pipe(uploadStream);\n});\n   <span class=\"hljs-built_in\">console<\/span>.error(error);\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`error: Internal Server Error`<\/span>;\n  }\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><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>Endpoint to handle image upload.<\/li>\n\n\n\n<li>Uploads the image to Cloudinary.<\/li>\n\n\n\n<li>Returns the Cloudinary object containing the public id for the image.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Static File Serving and Server Initialization<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">app.use(express.static(path.resolve(__dirname, <span class=\"hljs-string\">\"public\"<\/span>)));\n<span class=\"hljs-keyword\">const<\/span> PORT = <span class=\"hljs-number\">8000<\/span>;\napp.listen(PORT, () =&gt; {\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`Server is running on port <span class=\"hljs-subst\">${PORT}<\/span>`<\/span>);\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><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>Serves static files from the &#8220;public&#8221; directory.<\/li>\n\n\n\n<li>Starts the server on port 8000.<\/li>\n<\/ul>\n\n\n\n<p>This code sets up a comprehensive server for handling image uploads using Cloudinary services.<\/p>\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> npm install <\/strong>in the root of your project to install the frontend and backend dependencies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Run the Backend Server<\/h3>\n\n\n\n<p>Open your terminal and run <strong>npm run start. <\/strong>Nodemon will run your express server in Node.js.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Run the Frontend Server<\/h3>\n\n\n\n<p>Open your other terminal, run <strong>npm run dev<\/strong>,<strong> <\/strong>and navigate to <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>FashionistaAI showcases how Cloudinary\u2019s GenAI technologies can be integrated into an application to deliver personalized, dynamic visual experiences. <a href=\"https:\/\/cloudinary.com\/\">Try Cloudinary\u2019s advanced AI<\/a> features to transform static images into dynamic marketing assets and elevate your content today.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Resources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GitHub Repo<\/strong>: \u00a0<a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-FashionistaAI\">Cloudinary-React-Image-to-Blog-AI<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will generate four elegant, streetwear, sporty, and business casual outfits styles to suit your unique preferences.&nbsp; In this blog post we\u2019ll walk you through how we built the app using Cloudinary\u2019s GenAI [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":36334,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[409,383,246],"class_list":["post-36328","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-generative-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 Fashion App Using Cloudinary&#039;s GenAI in React and Node.js<\/title>\n<meta name=\"description\" content=\"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will\" \/>\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\/fashion-app-genai-react-node-js\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a Fashion App Using Cloudinary&#039;s GenAI in React and Node.js\" \/>\n<meta property=\"og:description\" content=\"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-11-20T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-03T23:57:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-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\/fashion-app-genai-react-node-js#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Building a Fashion App Using Cloudinary&#8217;s GenAI in React and Node.js\",\"datePublished\":\"2024-11-20T15:00:00+00:00\",\"dateModified\":\"2025-03-03T23:57:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\"},\"wordCount\":1198,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA\",\"keywords\":[\"Generative AI\",\"Node(JS)\",\"React\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2024\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\",\"url\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\",\"name\":\"Building a Fashion App Using Cloudinary's GenAI in React and Node.js\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA\",\"datePublished\":\"2024-11-20T15:00:00+00:00\",\"dateModified\":\"2025-03-03T23:57:22+00:00\",\"description\":\"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a Fashion App Using Cloudinary&#8217;s GenAI in React and Node.js\"}]},{\"@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 Fashion App Using Cloudinary's GenAI in React and Node.js","description":"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will","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\/fashion-app-genai-react-node-js","og_locale":"en_US","og_type":"article","og_title":"Building a Fashion App Using Cloudinary's GenAI in React and Node.js","og_description":"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will","og_url":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js","og_site_name":"Cloudinary Blog","article_published_time":"2024-11-20T15:00:00+00:00","article_modified_time":"2025-03-03T23:57:22+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-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\/fashion-app-genai-react-node-js#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Building a Fashion App Using Cloudinary&#8217;s GenAI in React and Node.js","datePublished":"2024-11-20T15:00:00+00:00","dateModified":"2025-03-03T23:57:22+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js"},"wordCount":1198,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA","keywords":["Generative AI","Node(JS)","React"],"inLanguage":"en-US","copyrightYear":"2024","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js","url":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js","name":"Building a Fashion App Using Cloudinary's GenAI in React and Node.js","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA","datePublished":"2024-11-20T15:00:00+00:00","dateModified":"2025-03-03T23:57:22+00:00","description":"The FashionistaAI app uses Cloudinary\u2019s GenAI technologies to create a personalized outfit. All you need to do is upload a picture and FashionistaAI will","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/fashion-app-genai-react-node-js#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building a Fashion App Using Cloudinary&#8217;s GenAI in React and Node.js"}]},{"@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\/v1731438389\/cloudinary_fashion_app_React_Node-blog\/cloudinary_fashion_app_React_Node-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36328","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=36328"}],"version-history":[{"count":3,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36328\/revisions"}],"predecessor-version":[{"id":37120,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36328\/revisions\/37120"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/36334"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=36328"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=36328"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=36328"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}