How to Create an “AI Quotes Generator” With OpenAI and JavaScript

On this tutorial, we’ll discover ways to create an “AI Quotes Generator” app with JavaScript. This app will display learn how to fetch information from the OpenAI API and generate partaking quotes for various classes or customized moods.

HTML Construction

The HTML construction will encompass the next parts:

  • A button on the prime proper will open a modal that lets customers add their OpenAI API key.
  • An enter that lets customers add a customized temper
  • A number of choices populated with classes
  • A button which, when clicked, will generate quotes from the OpenAI API.

As we’ve accomplished earlier than, we’ll use the Bootstrap framework to do a variety of the heavy lifting the place the UI is worried. The HTML Construction will seem like this:

1
<div class="position-absolute top-0 end-0 mt-2 me-3">
2
   <button
3
      id="api"
4
      kind="button"
5
      class="btn btn-primary"
6
      data-bs-toggle="modal"
7
      data-bs-target="#myModal"
8
      >
9
   Add API Key
10
   </button>
11
</div>
12
<div class="container mt-5">
13
   <div class="message alert alert-danger text-center" position="alert"></div>
14
   <div
15
      class="modal fade"
16
      id="myModal"
17
      tabindex="-1"
18
      aria-labelledby="exampleModalLabel"
19
      aria-hidden="true"
20
      >
21
      <div class="modal-dialog ">
22
         <div class="modal-content">
23
            <div class="modal-header">
24
               <h5 class="modal-title" id="exampleModalLabel">
25
                  Your API Key stays saved domestically in your browser
26
               </h5>
27
            </div>
28
            <div class="modal-body">
29
               <div class="form-group">
30
                  <label for="apikey">API KEY</label>
31
                  <enter kind="textual content" class="form-control" id="apikey" />
32
               </div>
33
            </div>
34
            <div class="modal-footer">
35
               <button
36
                  kind="button"
37
                  class="btn btn-secondary"
38
                  data-bs-dismiss="modal"
39
                  >
40
               Shut
41
               </button>
42
               <button kind="button" class="btn btn-primary">Save</button>
43
            </div>
44
         </div>
45
      </div>
46
   </div>
47
   <h1 class="header text-center display-2 fw-bold">AI Quote Generator</h1>
48
   <!-- Foremost -->
49
   <div class="d-md-flex h-md-100 my-5 align-items-center">
50
      <div class="col-md-6 p-0 h-md-100">
51
         <div class="d-md-flex align-items-center h-100 p-5 text-center justify-content-center category-wrapper">
52
            <div class="pt-5 pb-5">
53
               <p class="fs-5">
54
                  Create the proper quote based mostly in your present temper..
55
               </p>
56
               <enter
57
                  id="enter"
58
                  title="temper"
59
                  kind="textual content"
60
                  placeholder="Enter your present temper"
61
                  class="form-control mb-4 mx-auto w-75 text-center"
62
                  fashion="width: 60%; show: inline-block"
63
                  />
64
            </div>
65
         </div>
66
      </div>
67
      <div class="col-md-6 p-0 h-md-100">
68
         <div class="d-md-flex align-items-center h-md-100 p-5 text-center justify-content-center vstack">
69
            <p class="fs-5">
70
               ..or select from our customized classes
71
            </p>
72
            <div
73
               class="quotes row justify-content-center mt-8 mb-4"
74
               >
75
               <!-- classes will go right here -->
76
            </div>
77
         </div>
78
      </div>
79
   </div>
80
   <!-- Finish Foremost -->
81
   <div class="quotes-container text-center mt-4">
82
      <button
83
         id="generate"
84
         class="generate-btn btn btn-primary"
85
         kind="submit"
86
         >
87
      Generate Quotes
88
      </button>
89
      <div class="d-flex justify-content-center mt-3">
90
         <div id="loader" class="spinner-border" position="standing">
91
         </div>
92
      </div>
93
   </div>
94
</div>
95
</div>
96
<div class="container text-center mt-5 mb-4">
97
   <div id="end result" class="row">
98
      <!-- generate quotes will go right here -->
99
   </div>
100
</div>

We are going to populate the quote classes dynamically with JavaScript, and as soon as we get the quotes from the OpenAI API, they are going to be populated within the outcomes container. 

For this mission, we’ll additionally use Bootstrap’s jQuery instruments to allow the modal performance. Please embody the CDN hyperlinks within the header.

1
<!-- Bootstrap CSS -->
2
<hyperlink href="https://cdn.jsdelivr.internet/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="nameless" />
3
<!-- jQuery -->
4
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
5
<!-- Bootstrap JavaScript (requires jQuery and Popper.js) -->
6
<script src="https://cdn.jsdelivr.internet/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="nameless"></script>
7
<script src="https://cdn.jsdelivr.internet/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="nameless"></script>

CSS Styling

Due to Bootstrap, we gained’t want quite a lot of customized types. However let’s add the customized CSS types we do want, together with the DM Mono net font.

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

3
physique {
4
  font-family: "DM Mono", monospace;
5
}
6
.form-group {
7
  margin: 2rem 0;
8
}
9
label {
10
  margin-bottom: 1rem;
11
}
12
@media (min-width: 768px) {
13
  .category-wrapper {
14
    border-right: 2px strong #999;
15
  }
16
}
17

18
#loader,
19
.message,
20
.radio-group enter[type="radio"]{
21
  show: none;
22
}
23
   

Storing API KEY on Native Storage

For the applying to operate as anticipated, customers should add their API KEY to native storage to make sure persistence and safety. To attain this, we have now the “Add API KEY” button on the prime proper. The button is configured with the data-bs-target attribute set to myModal indicating that clicking it’ll set off the modal with the id “myModal” to be displayed.

1
<button
2
   id="api"
3
   kind="button"
4
   class="btn btn-primary"
5
   data-bs-toggle="modal"
6
   data-bs-target="#myModal"
7
   >
8
Add API Key
9
</button>

As soon as the modal is proven to the consumer, we’ll use jQuery to connect an occasion listener for the proven.bs.modal occasion. Within the occasion operate, we’ll do the next:

  • Get the API key worth from the consumer.
  • save the worth to native storage,
  • cover the modal
1
$("#myModal").on("proven.bs.modal", operate () {
2
  
3
  const saveButton = doc.querySelector("#myModal .btn-primary");
4
  const apiKeyInput = doc.querySelector("#apikey");
5

6
  saveButton.addEventListener("click on", operate () {
7
    const apiKeyValue = apiKeyInput.worth;
8
    localStorage.setItem("API_KEY", apiKeyValue);
9
    $("#myModal").modal("cover");
10
  });
11
});

So once you click on the “Add API KEY”  button, the modal will likely be displayed like this:

The following step is to outline and map our customized classes to the interface. Listed below are the classes. Be happy to outline your individual.

1
const classes = [
2
  "motivation",
3
  "life",
4
  "hope",
5
  "funny",
6
  "love",
7
  "philosophy",
8
  "sadness",
9
];

Let’s get the component with the category quotes that can home the classes.

1
const quotes = doc.querySelector(".quotes");

Subsequent, we’ll use the map() methodology to generate an HTML markup of a label and an enter radio component for every class; the radio enter component will comprise the id and worth of the class, whereas the label will comprise the title of the class.

1
const mappedCategories = classes.map((class) => {
2
  capitalizeText = class.charAt(0).toUpperCase() + class.slice(1);
3
      return `<enter
4
        kind="radio"
5
        class="btn-check"
6
        title="temper"
7
        id="${class}"
8
        worth="${class}"
9
        autocomplete="off"
10
      />
11
      <label
12
        class="btn btn-secondary align-items-center justify-content-center fs-5"
13
        for="${class}"
14
      >${capitalizeText}</label>`;
15
});
16
quotes.innerHTML = mappedCategories.be a part of("");

Now the app appears like this:

OpenAI API Configuration 

We’ve applied the add API Key performance. Now, let’s get the important thing from the OpenAI web site. If you happen to don’t have an account, go to the OpenAI website and join free. 

When you present the required particulars, navigate to the documentation. Click on API KEY on the highest left , create your API key , copy and paste the important thing and retailer it in a safe location.

Utilizing the API Key

Create an async operate known as getData(), which takes two parameters, specifically immediate and API KEY,

1
const getData = async (immediate, API_KEY) => {
2
    
3
}

Contained in the operate, we need to use fetch() operate to make a request to the OpenAI API and show the generated response to the consumer. Contained in the getData() operate, add a try-catch block with the next code.

1
const getData = async (immediate, API_KEY) => {
2
  
3
  attempt {
4
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
5
      methodology: "POST",
6
      headers: {
7
        Authorization: `Bearer ${API_KEY}`,
8
        "Content material-Kind": "utility/json",
9
      },
10
      physique: JSON.stringify({
11
        mannequin: "gpt-3.5-turbo",
12
        messages: [
13
          {
14
            role: "user",
15
            content: `Generate 10 quotes about ${prompt}`,
16
          },
17
        ],
18
        temperature: 0.7,
19
      }),
20
    });
21
    const information = await response.json();
22

23
    return information;
24
  } catch (error) {
25

26
    return error;
27
  }
28
};

That is all of the code we have to get information from OpenAI . Let’s break down the code.

  • We use the fetch() operate contained in the attempt block to make an async POST request to the desired url. 
  • Within the request physique, we specify gpt-3.5-turbo because the mannequin for use; 
  • The OpenAI API additionally expects an Authorization header containing the API KEY, and the physique of the request ought to be a JSON object containing parameters such because the mannequin, immediate, and  temperature (signifies randomness of the responses; increased values point out extra randomness of the responses).
  • Lastly, we return the response.json object. In case of any errors, we additionally return the error object.

The info response appears like this;

As you possibly can see, the info we have to show to the consumer is contained within the selections array. The info will likely be formatted earlier than being exhibited to the consumer.

The getData() operate will likely be known as when the consumer clicks the generate quotes button. Let’s add an occasion listener to the generate button.

1
const generateBtn = doc.querySelector(".generate-btn");
2
generateBtn.addEventListener("click on", async (e) => {
3
  e.preventDefault();
4
  
5
  }

When the press occasion happens, we need to execute a operate that does the next:

  • Get the API KEY from native storage.
  • If no API KEY is discovered on native storage, we’ll show an error, letting the consumer know they need to add their API KEY.
  • Get the immediate from both a class or a customized immediate.
  • Go the immediate and the APIKEY to the getData() operate.
  • Present a spinner when the applying is fetching the info.
  • After getting a response, cease the spinner.
  • Format the info and show it on bootstrap playing cards.
  • In case of any error, we’ll show the suitable error message.

Replace the occasion listener operate as follows:

1
const generateBtn = doc.querySelector(".generate-btn");
2
generateBtn.addEventListener("click on", async (e) => {
3
  e.preventDefault();
4
  const key = localStorage.getItem("API_KEY");
5

6
  if (!key) {
7
    displayError("","Please add your OPENAI API Key, The KEY will likely be saved domestically in your browser");
8
    return;
9
  }
10

11
  let immediate = "";
12
  let radio = doc.querySelector('enter[name="mood"]:checked');
13

14
  if (doc.querySelector('enter[name="mood"]:checked')) {
15
    radio = doc.querySelector('enter[name="mood"]:checked');
16
    immediate = radio.worth;
17
  } else {
18
    CustomInput = doc.getElementById("enter");
19
    immediate = CustomInput.worth; 
20
  }
21

22
  if (!immediate) {
23
    displayError(immediate,'Please select a class or present a customized temper"');
24
    return;
25
  }
26
  
27
  loader.fashion.show = "block";
28

29
  const information = await getData(immediate, key);
30

31
  if (information.selections) {
32
    const container = doc.getElementById("end result");
33
    //    information from aync
34
    const quotesArray = information.selections[0].message.content material.cut up("n");
35
    const mappedArray = quotesArray.map((quote) => {
36
      const trimmedQuote = quote.exchange(/^d+.|"$/g, "").trim();
37

38
      return ` <div class="col-sm-6 mt-5 mb-4">
39
            <div class="card">
40
              <div class="card-body">
41
                <p class="card-text">${trimmedQuote}</p></div>
42
            </div>
43
        </div>
44
        `;
45
    });
46

47
    container.innerHTML = mappedArray.be a part of("");
48
    
49
  } else {
50
    displayError("",information.error.message )
51
    
52
  }
53
  CustomInput.worth = "";
54
});

Let’s break down what’s taking place above:

  • First we stop the default nature of the browser by setting e.preventDefault()
  • const key = localStorage.getItem("API_KEY"); will get the API KEY from native storage.
  • If no secret’s discovered, we’ll go an error message to the displayError() operate.
  • let immediate = ""; declares an empty string that can retailer the worth of the immediate from the consumer.
  • if (doc.querySelector('enter[name="mood"]:checked')){...} : checks if the consumer has chosen a class and if true, the worth of the chosen radio enter is assigned to the immediate.
  • Within the else assertion, the immediate would be the customized enter worth if the consumer has entered a customized temper.
  • If the worth of the immediate is null or undefined,  it signifies that the consumer has not offered a immediate (both by choosing a temper class or coming into a customized temper), we’ll show an error message.
  • After all of the validation has handed, we’ll show a spinner component with loader.fashion.show = "block";

getData() Operate

Subsequent, we’ll name the await getData() operate and go the immediate and the API key. Because the operate is an asynchronous operate, we use await to make sure the execution is delayed till the info fetching is profitable.

As we noticed earlier, the info object returned by the API appears like this:

The content material we want is contained within the selections[0].message object.

  • information.selections[0].message.content material.cut up("n"); creates an array of the quotes known as quotesArray by splitting it the place n seems.
  • The quotesArray now incorporates all of the quotes, all we have to do is use the map() methodology and for every quote, take away any main or trailing whitespace with quote.exchange(/^d+.|"$/g, "").trim(); and return an HTML markup for every quote represented by a Bootstrap card.
  • Lastly, we set the innerHTML of the quotes container to the concatenated HTML markup of every quote.
  • In case of an error from the API,  displayError("",information.error.message ) shows the returned error message.

Error Dealing with

Relatively than repeating the error dealing with course of, the displayError() operate will deal with that. It takes the valueText and a messageText as parameters, checks if the valueText is null or undefined and shows the error message contained in messageText .

The error message is displayed for 4 seconds after which hidden from the consumer.

1
operate displayError(valueText,messageText) {
2
  const message = doc.querySelector(".message");
3
  if (valueText === "") {
4
  
5
    message.textContent = messageText;
6
    message.fashion.show = "block";
7
  }
8
  setTimeout(() => {
9
    message.textContent = "";
10
    message.fashion.show = "none";
11
  }, 4000);
12
  return;
13
}

For the ultimate clean-up, let’s be certain that if the consumer begins typing in to the customized  enter subject, any beforehand chosen class (through radio buttons) will likely be deselected.

1
const inputField = doc.getElementById("enter");
2
inputField.addEventListener("enter", () => {
3
  const radio = doc.querySelector('enter[name="mood"]:checked');
4
  if (radio) {
5
    radio.checked = false;
6
  }
7
});

Conclusion

Whew! That was so much to absorb, however the finish result’s price it, and also you’ll have realized so much. We lined the steps wanted to make your individual AI Quote Generator App with JavaScript. Now, you possibly can combine AI into your utility to generate distinctive content material!

Let’s remind ourselves of the ultimate product.

Trending Merchandise
[product_category category=”trending” per_page=”8″ columns=”2″ orderby=”date” order=”desc”].

We will be happy to hear your thoughts

Leave a reply

MyStudioCafe
Logo
Compare items
  • Total (0)
Compare
0