In this tutorial we will learn how to use the OpenAI API with the GPT-3.5-turbo/ GPT 4 model.
To do that we will create a back-end server in Node.js that interacts with the OpenAI API and a front-end interface using HTML and JavaScript. By following these steps, you can build powerful applications that leverage the potential of GPT-3.5-turbo.
1)- Sign up and Get Access to the OpenAI API
To get started, sign up for an OpenAI account on their website (https://openai.com/) if you haven’t already.
Once your account created you’ll see this interface:
">
Click on your profile photo in the top right corner
2">
t_8 -->
Click on “View API keys”. Once clicked you will have the following interface:
As you can see, I have already 3 API keys generated, to generate a new API key simply click on “+ Create new secret key” button, you’ll have the following pop-up:
You can give a name to your secret key if you want, if you don’t then there is no problem, you can leave the field empty. After that click on “create secret key” button and the key will be created.
2)- Create the interface using HTML and CSS
Now that we know how to get the API key from OpenAI API, let’s build a simple interface of our project.
Let’s say that we want our website or app to give us a book summary based on the title of the book the user will enter.
So as elements we’ll need an <input/>, where the user will enter the book title, a <button></button> to click on to generate the summary and an area like a <div></div> to display the book summary.
In this project we want our elements to be centered in the middle of the page, so we configured the <body></body> of the page to center all the elements within it.
Indeed, we changed the type of display to flex to make all the elements in one horizontal line. Because the display type flex arranges the elements by default in one horizontal line called the main line.
But as we want the <div></div> to be under the <button></button>, and the <button></button> under the <input/>, which means we want our elements to be arranged vertically and not horizontally, we changed the direction of the flex using flex-direction property and giving it the value of column.
So now the column or the vertical line is the main axis and not the horizontal line.
After that we will center the elements vertically in the center of the page, but before that we should specify the height of the body because our elements are inside the <body></body>.
Indeed, to place the elements at the center of the page, the browser should know what is the height of the page in the first place, to take that height and divided by 2. And the <body></body> is the page, so if we don’t specify a height, how can the browser calculate the middle of the page? That’s why a height of 100 vh is added.
If the elements were wrapped in a <div></div> for example like this:
Then all the CSS added to the body would be added to the <div></div> instead. It is the <div></div> that we would have set the display property to flex and added the align-items and justify-content properties and set a height.
Because in short, whenever we want to center elements in the middle of a page, we add the properties (display, flex-direction, justify-content, align-items, height) to the direct parent element they are wrapped in. In our project the parent element is the body, but in this example above the parent element is the div.
Finally, we added the justify-content and align-items properties and we set them both to center. Justify-content property centers the elements in the main axis of the flex. Here we changed the main axis to column, so justify-content will center the elements in the column, which means vertically.
align-items centers the elements in the secondary axis. Here the secondary axis became the horizontal line so align-items will center the elements according to the horizontal line.
We added also some classic styling to the <input/> and <button></button> elements to change their width, font-weight, color and background-color…
At the end we want to hide the <div></div> on the page, because this <div></div> will contain the summary of the book and so we want it to appear only when the user clicks on the generate button, not every time when the page is loaded.
So we set the display property of the <div></div> to none. This way the <div></div> will not be visible when the page is loaded.
Below is the final interface of the project:
3)- Send Data to the backend
Now that we have finished building the interface it is tie time to send the user data to the backend to be handled by OpenAI API. In other words, once the user will enter the name of the book, we have to send the name of the book to OpenAI API to give us a summary.
T know more about how to send data to the backend using Fetch API and understand the step by step explanation refer to the following link: Send data from the front-end to the backend.
Let’s look at the JavaScript code needed to send data to the backend.
JavaScript
var generateButton=document.querySelector("button"); generateButton.addEventListener("click",()=>{varbookInput=document.querySelector("input");varobj={ bookTitle:bookInput.value};fetch("/book",{ method:"POST", headers:{"Content-type":"application/json"}, body:JSON.stringify(obj)})})
First we added the following instruction var generateButton=document.querySelector("button"); to select the button in HTML code;
After that, we added an event listener to the button which is “click”. Indeed, we want to send data to the backend at the click of the button only: generateButton.addEventListener("click",()=>{ }).
So at the click of the button we want always to select the input where the title of the book will be entered by the user, hence the line of the code: var bookInput=document.querySelector("input").
At the click of the button we want also once the input is selected, to put the value of the input in a variable. The variable will be an object. Hence the line of code: var obj={ bookTitle:bookInput.value }.
Once all this is done we want to send the “obj” variable that contains the title of the book to the backend. To do that we used fetch API.
In this example we will be sending the data to “/book” URL. The URL where we will send the data can be named anything you want. It can be named “/summary” or “/bookSummary” or whatever you want, in this example I chose the name of “/book”.
To send the data to the backend we should define the method to use which is POST method known for that purpose.
The data will be sent in JSON format because in the backend we will be using express to build a server, and express works with JSON data only. So as the data will be sent in JSON format, we should indicate to the server how it should interpret the data. That’s why the “Content-type” (which is the “body”) is set to application/json: headers:{"Content-type":"application/json"}.
To send the data we put it in the body of the request and we convert it into a string representation in JSON format: body:JSON.stringify(obj).
We said that we will send the data to the URL “/book” that will be in the backend, so we should go to the backend and add the “/book” URL.
JavaScript
var express =require("express");var app =express();app.use(express.json());app.listen("3000");app.get("/",(req,res)=>{res.sendFile("index.html",{ root:__dirname});})app.post("/book",(req,res)=>{console.log(req.body);})
Let’s set a server first using express. For that install express to be part of your dependencies using npm i express instruction and create a new file called “server.js” for example where you can add the code above.
The following lines of the code var express = require("express") and var app = express() is to call express module and create express server instance respectively.
app.use(express.json()) is a middleware function used always with express to allow express to interpret JSON format sent by the front-end via fetch API.
app.listen("3000") is to indicate to our web application which port it should listen to.
app.get("/", (req, res) => { res.sendFile("index.html", { root: __dirname }); }) is to start serving our HTML through the backend. "index.html" is the name of the HTML file and { root: __dirname } is its location. Here I have "index.html" file in the root of the folder “draft” that’s why the location is set to { root: __dirname }.
To see the website on the browser just type in Google search bar on the top 127.0.0.1:3000.
And then app.post("/book", (req, res) => console.log(req.body); }) is the code added to configure and add the “/book” URL, this way when the front-end sends the data to “/book” URL, the destination URL “/book” will be found in the backend. And to test if the data will be well received we can console.log it to Node JS console.
If we enter as a title “Awaken the Giant Within You”, as a result in Node JS console we will get: { bookTitle: ‘Awaken the giant within you’ }.
If we want only the book title we should modify the code into: console.log(req.body.bookTitle).
4)- Call OpenAI API, gpt-3.5-turbo model
Now that we have done all this work it is time to call the OpenAI API to give us the book summary.
In this example we will work with gpt-3.5-turbo model.
To start working with OpenAI API you should first install it as dependency. You can install it using npm i openai instruction.
Node JS will install by default the latest version of OpenAI API. At the time of writing this article the latest version is 4.2.0.
Once the openai is installed it is time to connect to it.
JavaScript
var express =require("express");var app =express();var{ OpenAI }=require("openai");app.use(express.json());app.listen("3000");var openai =newOpenAI({apiKey:"sk-XB7pfY4Cv6JuUSk8mRRfT3BlbpFJHM6gKPHqygLGjBn4kOaA"});app.get("/",(req,res)=>{res.sendFile("index.html",{ root:__dirname});})app.post("/book",(req,res)=>{})
So to connect to openai we have to require the OpenAi constructor from the OpenAI module. This is done via this line of code: var { OpenAI } = require("openai").
Then we have to connect to openai with our OpenAI API Key we talked about in the first paragraphs of this blog.
To do that we create a new instance of OpenAI API and we paste our API Key: var openai = new OpenAI({apiKey: "sk-XB7pfY4Cv6JuUSk8mRRfT3BlbpFJHM6gKPHqygLGjBn4kOaA"}).
Now let’s give OpenAI API the prompt we want to give us a book summary.
JavaScript
var express =require("express");var app =express();var{ OpenAI }=require("openai");app.use(express.json());app.listen("3000");var openai =newOpenAI({apiKey:"sk-XB7pfY4Cv6JuUSk8mRRfT3BlbpFJHM6gKPHqygLGjBn4kOaA"});app.get("/",(req,res)=>{res.sendFile("index.html",{ root:__dirname});})app.post("/book",(req,res)=>{varbookSummary=req.body.bookTitle;vargenerateMeta=async(bookSum)=>{varprompt=`Write a thorough yet concise summary of ${bookSum}. concentrate on the most important takeaways and primary points from the book that together will give the user a solid overview and understanding of the book and its topic. To sum up: The book's biggest Takeaway and point in a singular sentence OUTPUT: Markdown format with (<h1>,<h2>,<h3>,<ul>,<ol>,<li>).`;vardescription=awaitopenai.chat.completions.create({ model:"gpt-3.5-turbo", messages: [{ role:"user", content:prompt}], max_tokens:900});returndescription.choices[0].message.content;}varbookSummarized=generateMeta(bookSummary);res.json({ message:bookSummarized})})
In the previous code we have displayed the data received from the front-end (book title) to check if everything was working great using this code: console.log(req.body.bookTitle).
Now instead of console.log we will store this data inside a variable called bookSummary to use it after: var bookSummary = req.body.bookTitle.
After that we will add the OpenAI API function to create a chat completion. The typical function given by openAI API documentation is this:
JavaScript
var generateMeta =async()=>{vardescription=awaitopenai.chat.completions.create({ model:"gpt-3.5-turbo", messages: [{role:"user", content:"Hello!"}],});console.log(chatCompletion.choices[0].message);}
As you can see, calling OpenAI API is an asynchronous operation. So what we have done in our code is we have added an argument to this function which is bookSum, we added the prompt for OpenAI API specifying what should be done and in what format it should give us the summary, we have used gpt-3.5-turbo model, we replaced the content:”Hello!” with the prompt variable because we want it to treat this instruction, we set the max-tokens to 900, meaning the summary you return should not exceed 900 tokens (we can see the tokens as being words for simplicity), and then once finished return the summary content only, not the entire message, hence the line of code: return description.choices[0].message.content.
Then once finished we called the funfction generateMeta and we pass it the book title received from the front-end which is stored in the variable bookSummary : var bookSummarized = generateMeta(bookSummary).
Now that we have the summary of the book stored in bookSummary variable, the server should send it to the front-end so that we can display it in the browser. To do that we will send the variable using the instruction: res.json({message: bookSummarized}).
As noticed, the response sent by the server is in JSON format.
Now let’s go back to the front-end to capture the summary of the book.
In the front-end to capture the response of the server, in other words to display the summary of the book we have to add a .then() method because Fetch API returns a promise. So the JavaScript code will become:
JavaScript
var generateButton=document.querySelector("button");var container=document.querySelector("div"); generateButton.addEventListener("click",()=>{varbookInput=document.querySelector("input");varobj={ bookTitle:bookInput.value};fetch("/book",{ method:"POST", headers:{"Content-type":"application/json"}, body:JSON.stringify(obj)}).then(r=>r.json()).then(data=>{container.style.display="block";container.innerHTML+=`${data.message}`;})})
As the summary should be displayed inside the <div></div> we selected the div: var container=document.querySelector("div").
We used then(r=>r.json()) to extract JSON data from the response of the server.
Once the JSON data is extracted we used another .then() method to display it.
As the style of the div in CSS was display: none, we have to make it appear once we receive the server’s response so that we can see the summary. Hence this line of code: container.style.display="block".
And finally to display the summary inside the div we added this line of code: container.innerHTML+=${data.message}.
Now if we click on the button to generate a summary of a book (let’s say we want to generate a summary of Tony Robbins book: Awaken The Giant Within You) we will have the [object Object] that will appear as below:
And that is because we said that OpenAI API works asynchronously, which means to provide a response we have to wait a little bit, it is not an immediate response that we get. But when we were sending the response of the server to the front-end, the response is sent immediately, via the code: res.json({message: bookSummarized}). We did not tell the server to wait for the response to be generated and then send it to the front-end.
So to to do that we will go back to the server.js file and we will add an await instruction to generateMeta() function.
If we add an await instruction we have to add async keyword to the top function to indicate that the response provided by the server is an asynchronous operation. So the code becomes:
JavaScript
var express =require("express");var app =express();var{ OpenAI }=require("openai");app.use(express.json());app.listen("3000");var openai =newOpenAI({apiKey:"sk-XB7pfY4Cv6JuUSk8mRRfT3BlbpFJHM6gKPHqygLGjBn4kOaA"});app.get("/",(req,res)=>{res.sendFile("index.html",{ root:__dirname});})app.post("/book",async(req,res)=>{varbookSummary=req.body.bookTitle;vargenerateMeta=async(bookSum)=>{varprompt=`Write a thorough yet concise summary of ${bookSum}. concentrate on the most important takeaways and primary points from the book that together will give the user a solid overview and understanding of the book and its topic. To sum up: The book's biggest Takeaway and point in a singular sentence OUTPUT: Markdown format with (<h1>,<h2>,<h3>,<ul>,<ol>,<li>).`;vardescription=awaitopenai.chat.completions.create({ model:"gpt-3.5-turbo", messages: [{ role:"user", content:prompt}], max_tokens:900});returndescription.choices[0].message.content;}varbookSummarized=awaitgenerateMeta(bookSummary);res.json({ message:bookSummarized})})
Now if you enter the name of the book Awaken The Giant Within You and click on “Generate” and wait a little bit, you will be able to see the summary like this:
var express =require("express");var app =express();var{ OpenAI }=require("openai");app.use(express.json());app.listen("3000");var openai =newOpenAI({apiKey:"sk-XB7pfY4Cv6JuUSk8mRRfT3BlbpFJHM6gKPHqygLGjBn4kOaA"});app.get("/",(req,res)=>{res.sendFile("index.html",{ root:__dirname});})app.post("/book",async(req,res)=>{varbookSummary=req.body.bookTitle;vargenerateMeta=async(bookSum)=>{varprompt=`Write a thorough yet concise summary of ${bookSum}. concentrate on the most important takeaways and primary points from the book that together will give the user a solid overview and understanding of the book and its topic. To sum up: The book's biggest Takeaway and point in a singular sentence. OUTPUT: Markdown format with (<h1>,<h2>,<h3>,<ul>,<ol>,<li>).`;vardescription=awaitopenai.chat.completions.create({ model:"gpt-3.5-turbo", messages: [{ role:"user", content:prompt}], max_tokens:900});returndescription.choices[0].message.content;}varbookSummarized=awaitgenerateMeta(bookSummary);res.json({ message:bookSummarized})})