Thumbnail

AI Image Generator Using HTML, CSS and JavaScript

Introduction :

The AI Image Generator project is a web application that allows users to generate images based on textual descriptions. It utilizes the OpenAI API to convert user input into images. The interface is built using HTML, CSS, and JavaScript, offering a seamless user experience where users can input a prompt, select the number of images they want, and view the generated images in a gallery. The application also provides download options for the generated images.

Explanation :

HTML Structure

The HTML defines the layout of the web page, including:

  • A section for the image generator form, where users can enter a prompt and select the number of images.
  • A section for displaying the generated images in a gallery format.
  • A script tag to link the JavaScript file responsible for the functionality.

CSS Styling

The CSS styles enhance the visual appeal and usability of the application:

  • It sets a background image and style for the image generator section.
  • It styles the input form, buttons, and image gallery for a clean and modern look.
  • It includes responsive design elements to ensure the application works well on different screen sizes.

JavaScript Logic

The JavaScript code handles the core functionality of the application:

  1. Form Submission Handling: Captures user input when the form is submitted and prevents the default form submission behavior.
  2. API Interaction: Sends a request to the OpenAI API with the user’s prompt and the desired number of images. It handles the API response and processes the image data.
  3. Dynamic Image Card Creation: Generates HTML markup for image cards, including a loading state while waiting for the API response.
  4. Image Display and Download: Updates the image cards with the generated images and provides download links for each image.

Key Functions and Their Purpose

  1. generateAiImages(userPrompt, userImageQuantity):

    • Sends a POST request to the OpenAI API with the user’s prompt and the number of images to generate.
    • Processes the API response, updating the image gallery with the generated images.
  2. updateImageCard(imgDataArray):

    • Updates the image cards in the gallery with the actual images generated by the API.
    • Removes the loading state from the image cards and sets up the download links.
  3. Form Submission Event Listener:

    • Captures the user’s input prompt and the selected number of images.
    • Generates the initial HTML for the image cards with a loading indicator.
    • Calls the generateAiImages function to fetch and display the generated images.

Error Handling

The JavaScript includes error handling to alert users if the image generation process fails. This ensures users are informed of issues such as network errors or invalid API responses, enhancing the robustness of the application.

Purpose and Benefits

The purpose of the AI Image Generator is to provide an intuitive and efficient tool for generating images based on textual descriptions. This can be useful for a variety of applications, including:

  • Content creation for blogs and social media.
  • Generating visual aids for educational materials.
  • Providing creative visualizations for design projects.

By integrating with the OpenAI API, the application leverages advanced AI capabilities to produce high-quality images, making the tool both powerful and user-friendly.

SOURCE CODE:

HTML (index.html)

				
					<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Image Generator </title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <section class="image-generator">
        <div class="conatent">
            <h1>AI Image Generator Tool JavaScript</h1>
            <p>Convert your text into an image within a second using this JavaScript powered AI Image Generator</p><div class='code-block code-block-6' style='margin: 8px 0; clear: both;'> <script type="litespeed/javascript" data-src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2145094925886663"
     crossorigin="anonymous"></script> <ins class="adsbygoogle"
     style="display:block; text-align:center;"
     data-ad-layout="in-article"
     data-ad-format="fluid"
     data-ad-client="ca-pub-2145094925886663"
     data-ad-slot="5699863678"></ins> <script type="litespeed/javascript">(adsbygoogle=window.adsbygoogle||[]).push({})</script></div>

            <form action="#" class="generate-form">
                <input type="text" class="prompt-input" placeholder="Describe what you want to generate" required>
                <div class="controls">
                    <select class="img-quantity" name="" id="">
                        <option value="1">1 Image</option>
                        <option value="2">2 Images</option>
                        <option value="3">3 Images</option>
                        <option value="4" selected>4 Images</option>
                    </select>
                    <button type="submit" class="generate-btn">Generate</button>
                </div>
            </form>
        </div>
    </section>

    <section class="image-gallery">
        <div class="img-card ">
            <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/img-1.jpg" alt="img">
            <a href="images/img-1.jpg" class="download-btn" download>
                <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" h data-src="images/download.svg" alt="download-icon">
            </a>
        </div>
        <div class="img-card">
            <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/img-2.jpg" alt="img">
            <a href="images/img-2.jpg" class="download-btn" download>
                <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/download.svg" alt="download-icon">
            </a>
        </div>
        <div class="img-card">
            <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/img-3.jpg" alt="img">
            <a href="images/img-3.jpg" class="download-btn" download <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/download.svg" alt="download-icon">
            </a>
        </div>
        <div class="img-card">
            <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/img-4.jpg" alt="img">
            <a href="images/img-4.jpg" class="download-btn" download>
                <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/download.svg" alt="download-icon">
            </a>
        </div>

    </section> <script type="litespeed/javascript" data-src="app.js"></script> <script data-no-optimize="1">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).LazyLoad=e()}(this,function(){"use strict";function e(){return(e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,a=arguments[e];for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function i(t){return e({},it,t)}function o(t,e){var n,a="LazyLoad::Initialized",i=new t(e);try{n=new CustomEvent(a,{detail:{instance:i}})}catch(t){(n=document.createEvent("CustomEvent")).initCustomEvent(a,!1,!1,{instance:i})}window.dispatchEvent(n)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,bt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,bt,e)}function r(t){return s(t,null),0}function u(t){return null===c(t)}function d(t){return c(t)===vt}function f(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function _(t,e){nt?t.classList.add(e):t.className+=(t.className?" ":"")+e}function v(t,e){nt?t.classList.remove(e):t.className=t.className.replace(new RegExp("(^|\\s+)"+e+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")}function g(t){return t.llTempImage}function b(t,e){!e||(e=e._observer)&&e.unobserve(t)}function p(t,e){t&&(t.loadingCount+=e)}function h(t,e){t&&(t.toLoadCount=e)}function n(t){for(var e,n=[],a=0;e=t.children[a];a+=1)"SOURCE"===e.tagName&&n.push(e);return n}function m(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function E(t){return!!t[st]}function I(t){return t[st]}function y(t){return delete t[st]}function A(e,t){var n;E(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[st]=n)}function k(a,t){var i;E(a)&&(i=I(a),t.forEach(function(t){var e,n;e=a,(t=i[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function L(t,e,n){_(t,e.class_loading),s(t,ut),n&&(p(n,1),f(e.callback_loading,t,n))}function w(t,e,n){n&&t.setAttribute(e,n)}function x(t,e){w(t,ct,l(t,e.data_sizes)),w(t,rt,l(t,e.data_srcset)),w(t,ot,l(t,e.data_src))}function O(t,e,n){var a=l(t,e.data_bg_multi),i=l(t,e.data_bg_multi_hidpi);(a=at&&i?i:a)&&(t.style.backgroundImage=a,n=n,_(t=t,(e=e).class_applied),s(t,ft),n&&(e.unobserve_completed&&b(t,e),f(e.callback_applied,t,n)))}function N(t,e){!e||0<e.loadingCount||0<e.toLoadCount||f(t.callback_finish,e)}function C(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function M(t){return!!t.llEvLisnrs}function z(t){if(M(t)){var e,n,a=t.llEvLisnrs;for(e in a){var i=a[e];n=e,i=i,t.removeEventListener(n,i)}delete t.llEvLisnrs}}function R(t,e,n){var a;delete t.llTempImage,p(n,-1),(a=n)&&--a.toLoadCount,v(t,e.class_loading),e.unobserve_completed&&b(t,n)}function T(o,r,c){var l=g(o)||o;M(l)||function(t,e,n){M(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";C(t,a,e),C(t,"error",n)}(l,function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_loaded),s(e,dt),f(n.callback_loaded,e,a),i||N(n,a),z(l)},function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_error),s(e,_t),f(n.callback_error,e,a),i||N(n,a),z(l)})}function G(t,e,n){var a,i,o,r,c;t.llTempImage=document.createElement("IMG"),T(t,e,n),E(c=t)||(c[st]={backgroundImage:c.style.backgroundImage}),o=n,r=l(a=t,(i=e).data_bg),c=l(a,i.data_bg_hidpi),(r=at&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),L(a,i,o)),O(t,e,n)}function D(t,e,n){var a;T(t,e,n),a=e,e=n,(t=It[(n=t).tagName])&&(t(n,a),L(n,a,e))}function V(t,e,n){var a;a=t,(-1<yt.indexOf(a.tagName)?D:G)(t,e,n)}function F(t,e,n){var a;t.setAttribute("loading","lazy"),T(t,e,n),a=e,(e=It[(n=t).tagName])&&e(n,a),s(t,vt)}function j(t){t.removeAttribute(ot),t.removeAttribute(rt),t.removeAttribute(ct)}function P(t){m(t,function(t){k(t,Et)}),k(t,Et)}function S(t){var e;(e=At[t.tagName])?e(t):E(e=t)&&(t=I(e),e.style.backgroundImage=t.backgroundImage)}function U(t,e){var n;S(t),n=e,u(e=t)||d(e)||(v(e,n.class_entered),v(e,n.class_exited),v(e,n.class_applied),v(e,n.class_loading),v(e,n.class_loaded),v(e,n.class_error)),r(t),y(t)}function $(t,e,n,a){var i;n.cancel_on_exit&&(c(t)!==ut||"IMG"===t.tagName&&(z(t),m(i=t,function(t){j(t)}),j(i),P(t),v(t,n.class_loading),p(a,-1),r(t),f(n.callback_cancel,t,e,a)))}function q(t,e,n,a){var i,o,r=(o=t,0<=pt.indexOf(c(o)));s(t,"entered"),_(t,n.class_entered),v(t,n.class_exited),i=t,o=a,n.unobserve_entered&&b(i,o),f(n.callback_enter,t,e,a),r||V(t,n,a)}function H(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function B(t,i,o){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?q(t.target,t,i,o):(e=t.target,n=t,a=i,t=o,void(u(e)||(_(e,a.class_exited),$(e,n,a,t),f(a.callback_exit,e,n,t))));var e,n,a})}function J(e,n){var t;et&&!H(e)&&(n._observer=new IntersectionObserver(function(t){B(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function K(t){return Array.prototype.slice.call(t)}function Q(t){return t.container.querySelectorAll(t.elements_selector)}function W(t){return c(t)===_t}function X(t,e){return e=t||Q(e),K(e).filter(u)}function Y(e,t){var n;(n=Q(e),K(n).filter(W)).forEach(function(t){v(t,e.class_error),r(t)}),t.update()}function t(t,e){var n,a,t=i(t);this._settings=t,this.loadingCount=0,J(t,this),n=t,a=this,Z&&window.addEventListener("online",function(){Y(n,a)}),this.update(e)}var Z="undefined"!=typeof window,tt=Z&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),et=Z&&"IntersectionObserver"in window,nt=Z&&"classList"in document.createElement("p"),at=Z&&1<window.devicePixelRatio,it={elements_selector:".lazy",container:tt||Z?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"litespeed-loading",class_loaded:"litespeed-loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},ot="src",rt="srcset",ct="sizes",lt="poster",st="llOriginalAttrs",ut="loading",dt="loaded",ft="applied",_t="error",vt="native",gt="data-",bt="ll-status",pt=[ut,dt,ft,_t],ht=[ot],mt=[ot,lt],Et=[ot,rt,ct],It={IMG:function(t,e){m(t,function(t){A(t,Et),x(t,e)}),A(t,Et),x(t,e)},IFRAME:function(t,e){A(t,ht),w(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){A(t,ht),w(t,ot,l(t,e.data_src))}),A(t,mt),w(t,lt,l(t,e.data_poster)),w(t,ot,l(t,e.data_src)),t.load()}},yt=["IMG","IFRAME","VIDEO"],At={IMG:P,IFRAME:function(t){k(t,ht)},VIDEO:function(t){a(t,function(t){k(t,ht)}),k(t,mt),t.load()}},kt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,i=this._settings,o=X(t,i);{if(h(this,o.length),!tt&&et)return H(i)?(e=i,n=this,o.forEach(function(t){-1!==kt.indexOf(t.tagName)&&F(t,e,n)}),void h(n,0)):(t=this._observer,i=o,t.disconnect(),a=t,void i.forEach(function(t){a.observe(t)}));this.loadAll(o)}},destroy:function(){this._observer&&this._observer.disconnect(),Q(this._settings).forEach(function(t){y(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;X(t,n).forEach(function(t){b(t,e),V(t,n,e)})},restoreAll:function(){var e=this._settings;Q(e).forEach(function(t){U(t,e)})}},t.load=function(t,e){e=i(e);V(t,e)},t.resetStatus=function(t){r(t)},Z&&function(t,e){if(e)if(e.length)for(var n,a=0;n=e[a];a+=1)o(t,n);else o(t,e)}(t,window.lazyLoadOptions),t});!function(e,t){"use strict";function a(){t.body.classList.add("litespeed_lazyloaded")}function n(){console.log("[LiteSpeed] Start Lazy Load Images"),d=new LazyLoad({elements_selector:"[data-lazyloaded]",callback_finish:a}),o=function(){d.update()},e.MutationObserver&&new MutationObserver(o).observe(t.documentElement,{childList:!0,subtree:!0,attributes:!0})}var d,o;e.addEventListener?e.addEventListener("load",n,!1):e.attachEvent("onload",n)}(window,document);</script><script data-no-optimize="1">var litespeed_vary=document.cookie.replace(/(?:(?:^|.*;\s*)_lscache_vary\s*\=\s*([^;]*).*$)|^.*$/,"");litespeed_vary||fetch("/wp-content/plugins/litespeed-cache/guest.vary.php",{method:"POST",cache:"no-cache",redirect:"follow"}).then(e=>e.json()).then(e=>{console.log(e),e.hasOwnProperty("reload")&&"yes"==e.reload&&(sessionStorage.setItem("litespeed_docref",document.referrer),window.location.reload(!0))});</script><script data-optimized="1" type="litespeed/javascript" data-src="https://foolishdeveloper.com/wp-content/litespeed/js/e06f9a8e9f9b4d7bb2f81f2339980ae8.js?ver=8928e"></script><script>const litespeed_ui_events=["mouseover","click","keydown","wheel","touchmove","touchstart"];var urlCreator=window.URL||window.webkitURL;function litespeed_load_delayed_js_force(){console.log("[LiteSpeed] Start Load JS Delayed"),litespeed_ui_events.forEach(e=>{window.removeEventListener(e,litespeed_load_delayed_js_force,{passive:!0})}),document.querySelectorAll("iframe[data-litespeed-src]").forEach(e=>{e.setAttribute("src",e.getAttribute("data-litespeed-src"))}),"loading"==document.readyState?window.addEventListener("DOMContentLoaded",litespeed_load_delayed_js):litespeed_load_delayed_js()}litespeed_ui_events.forEach(e=>{window.addEventListener(e,litespeed_load_delayed_js_force,{passive:!0})});async function litespeed_load_delayed_js(){let t=[];for(var d in document.querySelectorAll('script[type="litespeed/javascript"]').forEach(e=>{t.push(e)}),t)await new Promise(e=>litespeed_load_one(t[d],e));document.dispatchEvent(new Event("DOMContentLiteSpeedLoaded")),window.dispatchEvent(new Event("DOMContentLiteSpeedLoaded"))}function litespeed_load_one(t,e){console.log("[LiteSpeed] Load ",t);var d=document.createElement("script");d.addEventListener("load",e),d.addEventListener("error",e),t.getAttributeNames().forEach(e=>{"type"!=e&&d.setAttribute("data-src"==e?"src":e,t.getAttribute(e))});let a=!(d.type="text/javascript");!d.src&&t.textContent&&(d.src=litespeed_inline2src(t.textContent),a=!0),t.after(d),t.remove(),a&&e()}function litespeed_inline2src(t){try{var d=urlCreator.createObjectURL(new Blob([t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1")],{type:"text/javascript"}))}catch(e){d="data:text/javascript;base64,"+btoa(t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1"))}return d}</script></body>

</html>
				
			

CSS (style.css)

				
					/* Importing Google font - Poppins */
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}

.image-generator {
  height: 40vh;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  background-color: #565656;
  background-size: cover;
  background-position: center;
}

.image-generator::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  opacity: 0.5;
  background: #121212;
}

.image-generator .content {
  position: relative;
  color: #fff;
  padding: 0 15px;
  max-width: 760px;
  text-align: center;
}

.image-generator h1 {
  font-size: 2.5rem;
  font-weight: 700;
}

.image-generator p {
  margin-top: 10px;
  font-size: 1.35rem;
}

.image-generator .generate-form {
  height: 56px;
  padding: 6px;
  display: flex;
  margin-bottom: 15px;
  background: #fff;
  align-items: center;
  border-radius: 30px;
  margin-top: 45px;
  justify-content: space-between;
}

.generate-form .prompt-input {
  width: 100%;
  height: 100%;
  outline: none;
  padding: 0 17px;
  border: none;
  background: none;
  font-size: 1rem;
  border-radius: 30px;
}

.generate-form .controls {
  display: flex;
  height: 100%;
  gap: 15px;
}

.generate-form .img-quantity {
  outline: none;
  border: none;
  height: 44px;
  background: none;
  font-size: 1rem;
}

.generate-form .generate-btn {
  font-size: 1rem;
  outline: none;
  border: none;
  font-weight: 500;
  color: #fff;
  cursor: pointer;
  height: 100%;
  padding: 0 25px;
  border-radius: 30px;
  background: #4949E7;
}

.generate-form .generate-btn[disabled] {
  opacity: 0.6;
  pointer-events: none;
}

.generate-form button:hover {
  background: #1d1de2;
}

.image-gallery {
  display: flex;
  gap: 15px;
  padding: 0 15px;
  flex-wrap: wrap;
  justify-content: center;
  margin: 50px auto;
  max-width: 1250px;
}

.image-gallery .img-card {
  display: flex;
  position: relative;
  align-items: center;
  justify-content: center;
  background: #f2f2f2;
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 1 / 1;
  width: 285px;
}

.image-gallery .img-card img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.image-gallery .img-card.loading img {
  width: 80px;
  height: 80px;
}

.image-gallery .img-card .download-btn {
  bottom: 15px;
  right: 15px;
  height: 36px;
  width: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  background: #fff;
  border-radius: 50%;
  position: absolute;
  opacity: 0;
  pointer-events: none;
  transition: 0.2s ease;
}

.image-gallery .img-card .download-btn img {
  width: 14px;
  height: 14px;
}

.image-gallery .img-card:not(.loading):hover .download-btn {
  opacity: 1;
  pointer-events: auto;
}

@media screen and (max-width: 760px) {
  .image-generator {
    height: 45vh;
    padding-top: 30px;
    align-items: flex-start;
  }

  .image-generator h1 {
    font-size: 1.8rem;
  }

  .image-generator p {
    font-size: 1rem;
  }

  .image-generator .generate-form {
    margin-top: 30px;
    height: 52px;
    display: block;
  }

  .generate-form .controls {
    height: 40px;
    margin-top: 15px;
    justify-content: end;
    align-items: center;
  }

  .generate-form .generate-btn[disabled] {
    opacity: 1;
  }

  .generate-form .img-quantity {
    color: #fff;
  }

  .generate-form .img-quantity option {
    color: #000;
  }

  .image-gallery {
    margin-top: 20px;
  }

  .image-gallery .img-card:not(.loading) .download-btn {
    opacity: 1;
    pointer-events: auto;
  }
}

@media screen and (max-width: 500px) {
  .image-gallery .img-card {
    width: 100%;
  }
}
				
			

JavaScript (app.js)

				
					const generateForm = document.querySelector(".generate-form");
const ImageGallery = document.querySelector(".image-gallery");

const OPENAI_API_KEY = "ENTER YOUR API KEY HERE FROM OPENAI API SITE"

async function generateAiImages(userPrompt, userImageQuantity) {

    function updateImageCard(imgDataArray) {
        imgDataArray.forEach((imgObject, index) => {
            const imgCard = ImageGallery.querySelectorAll(".img-card")[index];
            const imgElement = imgCard.querySelector("img");
            const downloadBtn = imgCard.querySelector(".download-btn");


            const aiGeneratedImg = `data:image/jpeg;base64,${imgObject.b64_json}`;
            imgElement.src = aiGeneratedImg;

            imgElement.onload = () => {
                imgCard.classList.remove("loading");
                downloadBtn.setAttribute("href", aiGeneratedImg);
                downloadBtn.setAttribute("download", `${userPrompt}.jpg`);
            }
        });
    }

    try {
        const response = await fetch("https://api.openai.com/v1/images/generations", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${OPENAI_API_KEY}`
            },
            body: JSON.stringify({
                prompt: userPrompt,
                n: parseInt(userImageQuantity),
                size: "512x512",
                response_format: "b64_json"
            })



        });

        if (!response.ok) throw new Error("Failed to generate Images")
        const { data } = await response.json();
        console.log(data);
        updateImageCard([...data])

    } catch (error) {
        alert(error.message)
    }
}

generateForm.addEventListener("submit", function (event) {
    // user input and image quantity values from the form 
    event.preventDefault()
    const userPrompt = event.srcElement[0].value;
    const userImageQuantity = event.srcElement[1].value;

    // creating HTML markup for image cars with loading state 
    const imgCardMarkup = Array.from({ length: userImageQuantity }, function () {
        return (
            `  <div class="img-card loading">
            <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/loader.svg" alt="img">
            <a href="#" class="download-btn">
                <img data-lazyloaded="1" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" decoding="async" data-src="images/download.svg" alt="download-icon">
            </a>
            </div>`
        )
    }


    ).join("");

    // console.log(imgCardMarkup)

    ImageGallery.innerHTML = imgCardMarkup;
    generateAiImages(userPrompt, userImageQuantity);





})

				
			

OUTPUT:

OUTPUT