Building a Twilio-Powered App with Next.js and OpenAI GPT-3.
Temidire Oluwasogo
Posted on February 13, 2024
In this article, you will learn how to create a Twilio-powered app with OpenAI’s GPT-3 using Twilio Programmable SMS. The app will be created using Next.js. Next.js is a powerful React framework that comes with its server-side functions and also has API routes that are used to handle HTTP requests between the server and client. Next.js is fully capable of handling both front-end and back-end functionalities and communication.
Project Overview
In this article, the project we will be building is a Meeting Invite app. We will use Next.js to create both the front-end and back-end due to its server-side and client-side capabilities. We will also make use of the OpenAI GPT-3 text-Davinci-003 engine, to generate the meeting text body and finally, we will make use of the Twilio Programmable SMS API to send SMS messages to the desired phone numbers. You can get the whole project from GitHub and follow along. Though we will go through all the steps to build the project.
Prerequisites
In other to go ahead with the article you will need the following:
Visual Studio code editor
- A Twilio account
- An OpenAI account
- React-phone-number-input
- OpenAI Api key
- Twilio
With all that stated let's begin creating the app.
Working on the front end
The first step is to create the front end but before that here is a snapshot of the project below.
The front end is not the most beautiful but it will do for our project.
In other to create the Next.js app, you have to use the following command:
npx create-next-app meeting-invite-app
Next, we will also install the other libraries we need.
npm install twilio openAiApi react-phone-numbers-input
Or if you cloned from the repo you can use the command npm install
.
After installing the necessary dependencies, open the Next.js app in VS code.
Then open the index.js
file located in the pages folder and write the following code:
First, import PhoneNumber from react-phone-number-input,
import PhoneNumber from 'react-phone-number-input'
Next, input the following lines of code:
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.formContent}>
<div className={styles.header}>
<h1>Meeting Inviter</h1>
</div>
<div>
<form className={styles.inputForm} onSubmit={sendData} method="POST">
<input
className={styles.input}
type="text"
name="employeeName"
placeholder="Name of employee"
onChange={(e) => setEmployeeName(e.target.value)}
/>
<PhoneInput
className={styles.phoneNumber}
placeholder="Enter Employee number"
value={phoneNumber}
onChange={setValue}
/>
<input
className={styles.input}
type="text"
name="messageBody"
placeholder="Enter meeting title"
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
className={styles.textArea}
placeholder="Enter meeting descreiption"
rows="20"
cols="50"
onChange={(e) => setMessageBody(e.target.value)}
/>
<button className={styles.button} type="submit">
Send
</button>
</form>
<div>{sent && <div className={styles.alert}>Message sent</div>}</div>
</div>
</div>
</div>;
The code above is used to create a simple form for our front end and in the code you will notice some functions used to get the values from our form. Those functions are the state functions and we haven’t imported our useState
hook to handle them. To do so we have to import the useState
hook and destructure it as follows:
import { useState } from "react";
const [employeeName, setEmployeeName] = useState("");
const [phoneNumber, setValue] = useState("");
const [title, setTitle] = useState("");
const [messageBody, setMessageBody] = useState("");
Now the front end is okay the only thing remaining is to add a CSS file. You can do that by importing the CSS module into the index file.
import styles from '../styles/Home.module.css'
After that, you can run the file with npm run dev
.
Getting and sending form data
Now that we have our front end we have to work on how to get our data from the form and send it to the Next.js backend which is the API route. In other to do that since the states have already been created, we need a function to get the values from the states and send them to the specific API
route which will handle the data. If you look at the code above we, inside the form element, there is an onSubmit
and a method
property that will run the sendData
function and set the HTTP request method to POST.
Now you have to create the sendData
function by writing the following code:
const sendData = async (event) => {
event.preventDefault();
// get data from the react state hooks
const data1 = {
name: employeeName,
messageTitle: title,
message: messageBody,
};
const mainObject1 = JSON.stringify(data1);
const endPoint1 = "/api/textAI";
//Set the parameters to be sent to the textAI api route
const params1 = {
method: "POST",
body: mainObject1,
};
//Get the response sent back from textAI API route
const response = await fetch(endPoint1, params1);
const myData = await response.json();
const { textData } = myData;
console.log(`This data is from openAIApi: ${textData} `);
};
The code above is a function that gets the name, message title, and message from the state hooks and sends them as part of the object body to the textAI.js
API route. The function also handles the response which is from the API route.
We still have another API routes to handle in the code, which is the data.js API route. In other to handle the request and response write the following code in the same function below the last line of code above:
//Get the data to be sent to the data.js api route
const data2 = {
number: phoneNumber,
text: textData,
};
const mainObject2 = JSON.stringify(data2);
const endPoint2 = "api/data";
//Set the parameters to be sent to the data api route
const params2 = {
method: "POST",
body: mainObject2,
};
//Get the response from the data api route
const response2 = await fetch(endPoint2, params2);
const myData2 = await response2.json();
console.log(
`This is the Twilio response to the frontend: ${JSON.stringify(myData2)} `,
);
The code above gets the number and the generated output text gotten from the textAI.js
API route and sends it to the data.js
API route which also sends back a response to the front end.
The function sendData
is called when the send button is clicked.
Working on the API routes
Now that the function sendData
is created on the front end, let us set work on the API routes that will handle the data gotten from the front end and send back a response to the back end. This is where the main app functionality will occur.
We will create two API routes named:
- textAI.js
- data.js
You can name your API any name you like. But for this article let us stick to the names above.
You might wonder, what do
textAI.js
anddata.js
do? Well,textAI.js
is the API route that handles the data gotten from the front end and sends it to the OpenAI to generate text and then send it back to the front end as a response.
While data.js
gets the generated text and the phone number from the front end and makes an API call to Twilio and Twilio then sends the generated text to the phone number.
Now let us work on our api route. To do so, enter into the pages folder, inside the folder enter into the api
folder then create two files named text.js
and data.js
.
After creating the files, go to your terminal or shell and install the Twilio and OpenAI library using the command:
npm install twilio openai
Also, you need an environment variable to store your API keys. To create it, in the root directory of your next js app create a file named .env.local
this file will hold all your API keys.
Making an API call to OPenAI
Now, let us make an API call to OpenAI. To do so you have to import the OpenaiAPI from the openai
library and also configure it to initialize your API key. Inside the textAI.js
file write the following code:
import { Configuration, OpenAIApi } from "openai";
export default async function postMethod(req, res) {
const { name, message, messageTitle } = JSON.parse(req.body);
const configuration = new Configuration({
apiKey: process.env.openAiKey,
});
const openai = new OpenAIApi(configuration);
}
The code above enables you to make use of the OpenAI library. You will need to import OpenAIApi
and Configuration functions from the openai
library. The configuration method enables you to configure the openai
library to use your API key.
While the OpenAIApi
function enables you to initialize the configuration which holds the API key.
Next, you need to get the data coming from the request body of the front end and send it for text generation and also send back a response by writing the following code inside the postMethod
function:
//Edit the message to send to OpenAI
const prompt = `${message} to ${name} with title ${messageTitle}`;
try {
//Send the prompt with the necessary parameters
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt,
temperature: 0,
max_tokens: 100,
n: 1,
});
//Get the response from OpenAI GPT-3
const textOutput = response.data.choices;
const textData = textOutput[0].text;
console.log(textOutput);
console.log("main data: ", textData);
//Send a response back to the front end
res.status(200).json({ textData });
} catch (error) {
console.error(error);
res.status(500).json({ error: "An error occured while fetcing from openAI" });
}
In the code above the function openai.createCompletion
was used to add the parameters and make a call to GPT-3 text-DaVinci-003
engine. This engine or model is used to generate text based on input. The input is structured as in a string literal and assigned to the variable prompt.
Prompt
is the input that is sent to GPT-3 for text generation.
Temperature is the amount of randomness set.
Max_tokens
represents the number of units of inputs or outputs that can be generated. n
refers to the number of tokens.
If you run the app you will get the generated text from OpenAI GPT-3. It was destructured in the sendData function in index.js and set to the generatedText state.
Sending the message using Twilio API
This is another main part of the application. Here you have to request the Twilio API to send the generated text to the recipient's phone number.
In other to do this, open the data.js
file and import the Twilio library using the code:
import twilio from "twilio";
After that, you need to get your Twilio API key
and accountSID
. Also, make sure you put them in the .env.local
file.
const authToken = process.env.AuthToken;
const accountSID = process.env.AccountSID;
const client = twilio(accountSID, authToken);
Next, you need to write the code to make the call to Twilio.
//Get the data from the front-end request body
const { number, text } = JSON.parse(req.body);
//Send the text
client.messages
.create({
from: "+13157125351",
to: number,
body: text,
})
//Send back a response
.then((message) => {
res.status(200).json({ messageSId: message.sid });
})
.catch((err) => {
res.status(500).json({ err: err.message });
});
You use the function client.messages.create()
to tell the Twilio API to send a message to the recipient. Inside the function there is an object parameter as follows:
- From
- To
- Body
The
from
object property is used to set your Twilio number. You get a Twilio number once you sign up for Twilio. The number will be able to send SMS messages and also place calls. Theto
object property is used to set the destination number to receive the message. It should contain the recipient's number. And thebody
object is used to set the message to be sent to the recipient.
Note: Do not omit any of the parameters else it won’t send.
The above code will look like the one below:
import twilio from "twilio";
export default async function postMethod(req, res) {
const authToken = process.env.AuthToken;
const accountSID = process.env.AccountSID;
const client = twilio(accountSID, authToken);
//Get the data from the front-end request body
const { number, text } = JSON.parse(req.body);
//Send the text
client.messages
.create({
from: "+13157125351",
to: number,
body: text,
})
//Send back a response
.then((message) => {
res.status(200).json({ messageSId: message.sid });
})
.catch((err) => {
res.status(500).json({ err: err.message });
});
}
After writing the code above, we just have to add one thing to our front end which is to show a text when the message is successfully sent.
To do that, we have to create a div that will show the text message sent
You can add styles to it though, but you don't need to worry the GitHub repository with the complete styles used for this project will be added.
To make the message pop up we need to do what is called conditional rendering. To do so, open the index.js
file, create a state to handle the rendering;
const [sent, setSent] = useState(false);
Inside the sendData function at the bottom, add the following code:
const { err } = myData2;
if (!err) {
setSent(true);
}
Then below the form element add the following code:
<div>{sent && <div className={styles.alert}>Message sent</div>}</div>;
After that, you can run the entire app using the command npm run dev
. You will get a similar one to the one below;
Conclusion
In this article, you learned to build a Twilio-powered app using Next.js and OpenAI GPT-3. The app can send text generated from GPT-3 and send it to the recipient’s phone number by using Twilio Programmable SMS.
Remember in other to use the Twilio programmable SMS you have to create an account on Twilio. When you create an account you get a phone number and free credits. In case the free credits are exhausted or maybe your free trial expires you have to then upgrade to a paid plan. With the paid plan you get even more capabilities.
You can also check the Twilio programmable SMS API for more information and also check out OpenAI API documentation for more information on how to use their API.
Posted on February 13, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.