Building a Twilio-Powered App with Next.js and OpenAI GPT-3.

temid

Temidire Oluwasogo

Posted on February 13, 2024

Building a Twilio-Powered App with Next.js and OpenAI GPT-3.

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

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.

Frontend view
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
Enter fullscreen mode Exit fullscreen mode

Next, we will also install the other libraries we need.

npm  install twilio openAiApi react-phone-numbers-input
Enter fullscreen mode Exit fullscreen mode

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>;
Enter fullscreen mode Exit fullscreen mode

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("");
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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} `);
};

Enter fullscreen mode Exit fullscreen mode

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)} `,
);
Enter fullscreen mode Exit fullscreen mode

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 and data.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
Enter fullscreen mode Exit fullscreen mode

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);
}

Enter fullscreen mode Exit fullscreen mode

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" });
}
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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 });
  });
Enter fullscreen mode Exit fullscreen mode

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. The to object property is used to set the destination number to receive the message. It should contain the recipient's number. And the body 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 });
    });
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Inside the sendData function at the bottom, add the following code:

const { err } = myData2;
if (!err) {
  setSent(true);
}
Enter fullscreen mode Exit fullscreen mode

Then below the form element add the following code:

<div>{sent && <div className={styles.alert}>Message sent</div>}</div>;
Enter fullscreen mode Exit fullscreen mode

After that, you can run the entire app using the command npm run dev. You will get a similar one to the one below;

Initial view

Form input

console message

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.

💖 💪 🙅 🚩
temid
Temidire Oluwasogo

Posted on February 13, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related