<div class="position-absolute top-0 end-0 mt-2 me-3">
      <button
        id="api"
        type="button"
        class="btn btn-primary"
        data-bs-toggle="modal"
        data-bs-target="#myModal"
      >
        Add API Key
      </button>
    </div>
    <div class="container mt-5">
      <div class="message alert alert-danger text-center" role="alert"></div>

      <div
        class="modal fade"
        id="myModal"
        tabindex="-1"
        aria-labelledby="exampleModalLabel"
        aria-hidden="true"
      >
        <div class="modal-dialog ">
          <div class="modal-content">
            <div class="modal-header">
              <h5 class="modal-title" id="exampleModalLabel">
                Your API Key remains stored locally in your browser
              </h5>
            </div>
            <div class="modal-body">
              <div class="form-group">
                <label for="apikey">API KEY</label>
                <input type="text" class="form-control" id="apikey" />
              </div>
            </div>
            <div class="modal-footer">
              <button
                type="button"
                class="btn btn-secondary"
                data-bs-dismiss="modal"
              >
                Close
              </button>
              <button type="button" class="btn btn-primary">Save</button>
            </div>
          </div>
        </div>
      </div>
      
      <h1 class="header text-center display-2 fw-bold">AI Quote Generator</h1>

      
      <!-- Main -->
<div class="d-md-flex h-md-100 my-5 align-items-center">
  
  <div class="col-md-6 p-0 h-md-100">
    <div class="d-md-flex align-items-center h-100 p-5 text-center justify-content-center category-wrapper">
      <div class="pt-5 pb-5">
        
        <p class="fs-5">
          Create the perfect quote based on your current mood..
        </p>
        
        <input
          id="input"
          name="mood"
          type="text"
          placeholder="Enter your current mood"
          class="form-control mb-4 mx-auto w-75 text-center"
          style="width: 60%; display: inline-block"
        />
        
      </div>
    </div>
  </div>
  
  <div class="col-md-6 p-0 h-md-100">
    <div class="d-md-flex align-items-center h-md-100 p-5 text-center justify-content-center vstack">
      
       <p class="fs-5">
          ..or choose from our custom categories
        </p>

        <div class="quotes justify-content-center">
        </div>
      
    </div>
  </div>
  
</div>
<!-- End Main -->
      
      
      <div class="quotes-container text-center mt-4">


        <button
          id="generate"
          class="generate-btn btn btn-primary"
          type="submit"
        >
          Generate Quotes
        </button>
          
            <div class="d-flex justify-content-center mt-3">      
              <div id="loader" class="spinner-border" role="status">
              </div>             
            </div>
          
        </div>
      </div>
    </div>

    <div class="container text-center mt-5 mb-4">
      <div id="result" class="row">
        <!-- <div class="col-lg-6 mt-5 mb-4">
          <div class="card">
            <div class="card-body">
              <p class="card-text">
                With supporting text below text below as a naturaltext below as
                a natural as a natural text below as a natural lead-in to
                additional content.
              </p>
            </div>
          </div>
        </div>
        <div class="col-md-6 mt-5 mb-4">
          <div class="card">
            <div class="card-body">
              <p class="card-text">
                With supporting text below as a natural lead-in to additional
                content.
              </p>
            </div>
          </div>
        </div> -->
      </div>
    </div>

 
@import url("https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap");

body {
  font-family: "DM Mono", monospace;
}
.form-group {
  margin: 2rem 0;
}
label {
  margin-bottom: 1rem;
}
@media (min-width: 768px) {
  .category-wrapper {
    border-right: 2px solid #999;
  }
}

#loader,
.message,
.radio-group input[type="radio"]{
  display: none;
}
   
$("#myModal").on("shown.bs.modal", function () {
  
  const saveButton = document.querySelector("#myModal .btn-primary");
  const apiKeyInput = document.querySelector("#apikey");

  saveButton.addEventListener("click", function () {
    const apiKeyValue = apiKeyInput.value;
    localStorage.setItem("API_KEY", apiKeyValue);
    $("#myModal").modal("hide");
  });
});


function displayError(valueText,messageText) {
  const message = document.querySelector(".message");
  if (valueText === "") {
  
    message.textContent = messageText;
    message.style.display = "block";
  }
  setTimeout(() => {
    message.textContent = "";
    message.style.display = "none";
  }, 4000);
  return;
}


const loader = document.getElementById("loader");
const getData = async (prompt, API_KEY) => {
  
  try {
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "gpt-3.5-turbo",
        messages: [
          {
            role: "user",
            content: `Generate 10 quotes about ${prompt}`,
          },
        ],
        temperature: 0.7,
      }),
    });
    const data = await response.json();
    
    loader.style.display = "none";
    return data;
  } catch (error) {
    loader.style.display = "none";
    return data;
  }
};

const categories = [
  "motivation",
  "life",
  "hope",
  "funny",
  "love",
  "philosophy",
  "sadness",
];

const quotes = document.querySelector(".quotes");

const mappedCategories = categories.map((category) => {
  capitalizeText = category.charAt(0).toUpperCase() + category.slice(1);
  return `
  <input
    type="radio"
    class="btn-check"
    name="mood"
    id="${category}"
    value="${category}"
    autocomplete="off"
  />

  <label
    class="btn btn-secondary align-items-center justify-content-center"
    for="${category}"
  >${capitalizeText}</label>


      `;
});

quotes.innerHTML = mappedCategories.join("");
const generateBtn = document.querySelector(".generate-btn");
generateBtn.addEventListener("click", async (e) => {
  e.preventDefault();
  const key = localStorage.getItem("API_KEY");
  

  if (!key) {
  

    displayError("","Please add your OPENAI API Key, The KEY will be stored locally on your browser");
    return;
  }

  let prompt = "";
  let radio = document.querySelector('input[name="mood"]:checked');

  if (document.querySelector('input[name="mood"]:checked')) {
    radio = document.querySelector('input[name="mood"]:checked');
    prompt = radio.value;
  } else {
    CustomInput = document.getElementById("input");
    prompt = CustomInput.value;
    
  }


  if (!prompt) {
    displayError(prompt,'Please choose a category or provide a custom mood"');
    return;
  }
  
  loader.style.display = "block";

  const data = await getData(prompt, key);

  if (data.choices) {
    const container = document.getElementById("result");

    //    data from aync
    const quotesArray = data.choices[0].message.content.split("\n");
    

    const mappedArray = quotesArray.map((quote) => {
      const trimmedQuote = quote.replace(/^\d+\.|"$/g, "").trim();

      return ` <div class="col-sm-6 mt-5 mb-4">
            <div class="card">
              <div class="card-body">
                <p class="card-text">${trimmedQuote}</p></div>
            </div>
        </div>
        `;
    });

    container.innerHTML = mappedArray.join("");
    
  } else {
    
    displayError("",data.error.message )

    
  }
  CustomInput.value = "";
});

const inputField = document.getElementById("input");
inputField.addEventListener("input", (e) => {
  e.preventDefault();

  const radio = document.querySelector('input[name="mood"]:checked');
  if (radio) {
    radio.checked = false;
  }
});

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.