Build a Next.js Interactive Web-Based Text Summarizer

Written by

in

In today’s fast-paced digital world, we’re constantly bombarded with information. Sifting through lengthy articles, reports, and documents to extract the core ideas can be a time-consuming task. Imagine a tool that could automatically condense any text into its essential points, saving you valuable time and effort. In this tutorial, we’ll build a simple yet effective text summarizer using Next.js, a powerful React framework, and the OpenAI API. This project will not only introduce you to the fundamentals of Next.js but also demonstrate how to integrate external APIs to create dynamic and useful web applications. By the end of this guide, you’ll have a fully functional text summarizer that you can use for your own needs or expand upon with further features.

Why Build a Text Summarizer?

Text summarization is a practical application with numerous benefits. Consider these scenarios:

  • Research: Quickly grasp the key arguments of a research paper without reading the entire document.
  • News Consumption: Get the gist of news articles to stay informed efficiently.
  • Content Review: Summarize lengthy articles for quick review and comprehension.
  • Learning: Condense study materials for easier memorization and understanding.

Building a text summarizer teaches valuable skills in front-end development, API integration, and natural language processing (NLP) concepts, making it an excellent learning project for both beginners and intermediate developers.

Prerequisites

Before we begin, ensure you have the following:

  • Node.js and npm (or yarn): Make sure you have Node.js and npm (or yarn) installed on your system. You can download them from the official Node.js website.
  • Basic JavaScript/React Knowledge: Familiarity with JavaScript and React fundamentals will be helpful.
  • OpenAI API Key: You’ll need an OpenAI API key to access their summarization models. You can sign up for an account at the OpenAI website and obtain an API key. Please note that the OpenAI API is a paid service, and you will be charged based on your usage.
  • Text Editor or IDE: A code editor like VS Code or Sublime Text.

Setting Up the Next.js Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app text-summarizer

This command will create a new Next.js project named “text-summarizer”. Navigate into the project directory:

cd text-summarizer

Next, install the required packages. We’ll need the `openai` package to interact with the OpenAI API and potentially some styling libraries. For this tutorial, we’ll keep the styling simple, but you can add libraries like Tailwind CSS or Bootstrap later on if you wish.

npm install openai

or

yarn add openai

Project Structure

Your project directory should look something like this:

text-summarizer/
├── node_modules/
├── pages/
│   ├── _app.js
│   └── index.js
├── public/
├── .gitignore
├── next.config.js
├── package-lock.json
├── package.json
└── README.md

The core of our application will reside in the `pages/index.js` file. We’ll also add a `.env.local` file to store our OpenAI API key securely.

Setting Up Environment Variables

Create a file named `.env.local` in the root directory of your project. This file will store your OpenAI API key. Add the following line, replacing `YOUR_OPENAI_API_KEY` with your actual API key:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

Important: Never commit your `.env.local` file to your version control system (e.g., Git). This file contains sensitive information that should be kept private.

Building the User Interface (UI)

Let’s start by designing the UI for our text summarizer. Open `pages/index.js` and replace its content with the following code:

import { useState } from 'react';

export default function Home() {
  const [inputText, setInputText] = useState('');
  const [summary, setSummary] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleInputChange = (event) => {
    setInputText(event.target.value);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);
    setError('');
    setSummary('');

    // Add API call logic here

    setLoading(false);
  };

  return (
    <div className="container">
      <h1>Text Summarizer</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="inputText">Enter Text:</label>
        <textarea
          id="inputText"
          value={inputText}
          onChange={handleInputChange}
          rows="10"
          cols="50"
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Summarizing...' : 'Summarize'}
        </button>
        {error && <p className="error">{error}</p>}
      </form>
      {summary && (
        <div className="summary-container">
          <h2>Summary:</h2>
          <p>{summary}</p>
        </div>
      )}
    </div>
  );
}

This code sets up the basic structure of our UI. It includes:

  • A text area for the user to input the text.
  • A button to trigger the summarization process.
  • A display area to show the summarized text.
  • State variables to manage the input text, the summary, the loading state, and any potential errors.

Now, let’s add some basic styling. You can add this CSS to your `pages/_app.js` file or create a separate CSS file and import it. For simplicity, we’ll add inline styles to the `index.js` file. Update the `pages/index.js` file with this CSS (inside a <style> tag):

import { useState } from 'react';

export default function Home() {
  const [inputText, setInputText] = useState('');
  const [summary, setSummary] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleInputChange = (event) => {
    setInputText(event.target.value);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);
    setError('');
    setSummary('');

    // Add API call logic here

    setLoading(false);
  };

  return (
    <div className="container">
      <style jsx>{`
        .container {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding: 20px;
          font-family: sans-serif;
        }

        h1 {
          margin-bottom: 20px;
        }

        form {
          display: flex;
          flex-direction: column;
          width: 80%;
          max-width: 600px;
        }

        label {
          margin-bottom: 5px;
        }

        textarea {
          margin-bottom: 10px;
          padding: 10px;
          border: 1px solid #ccc;
          border-radius: 4px;
          font-size: 16px;
          font-family: inherit;
        }

        button {
          padding: 10px 20px;
          background-color: #4CAF50;
          color: white;
          border: none;
          border-radius: 4px;
          cursor: pointer;
          font-size: 16px;
        }

        button:disabled {
          background-color: #cccccc;
          cursor: not-allowed;
        }

        .error {
          color: red;
          margin-top: 10px;
        }

        .summary-container {
          margin-top: 20px;
          border: 1px solid #ddd;
          padding: 15px;
          border-radius: 4px;
          width: 80%;
          max-width: 600px;
        }
      `}</style>
      <h1>Text Summarizer</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="inputText">Enter Text:</label>
        <textarea
          id="inputText"
          value={inputText}
          onChange={handleInputChange}
          rows="10"
          cols="50"
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Summarizing...' : 'Summarize'}
        </button>
        {error && <p className="error">{error}</p>}
      </form>
      {summary && (
        <div className="summary-container">
          <h2>Summary:</h2>
          <p>{summary}</p>
        </div>
      )}
    </div>
  );
}

Now, run your Next.js development server:

npm run dev

or

yarn dev

Open your browser and navigate to `http://localhost:3000`. You should see the basic UI of your text summarizer.

Integrating the OpenAI API

Now, let’s integrate the OpenAI API to perform the text summarization. We’ll use the `openai` package we installed earlier. Update the `handleSubmit` function in `pages/index.js` as follows:

import { useState } from 'react';
import { Configuration, OpenAIApi } from "openai";

export default function Home() {
  const [inputText, setInputText] = useState('');
  const [summary, setSummary] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleInputChange = (event) => {
    setInputText(event.target.value);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);
    setError('');
    setSummary('');

    try {
      const configuration = new Configuration({
        apiKey: process.env.OPENAI_API_KEY,
      });
      const openai = new OpenAIApi(configuration);

      const completion = await openai.createCompletion({
        model: "text-davinci-003", // Or any other suitable model
        prompt: `Summarize the following text:n${inputText}`,
        max_tokens: 150, // Adjust as needed
      });

      setSummary(completion.data.choices[0].text.trim());
    } catch (err) {
      setError('An error occurred while summarizing the text.');
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="container">
      <style jsx>{`
        .container {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding: 20px;
          font-family: sans-serif;
        }

        h1 {
          margin-bottom: 20px;
        }

        form {
          display: flex;
          flex-direction: column;
          width: 80%;
          max-width: 600px;
        }

        label {
          margin-bottom: 5px;
        }

        textarea {
          margin-bottom: 10px;
          padding: 10px;
          border: 1px solid #ccc;
          border-radius: 4px;
          font-size: 16px;
          font-family: inherit;
        }

        button {
          padding: 10px 20px;
          background-color: #4CAF50;
          color: white;
          border: none;
          border-radius: 4px;
          cursor: pointer;
          font-size: 16px;
        }

        button:disabled {
          background-color: #cccccc;
          cursor: not-allowed;
        }

        .error {
          color: red;
          margin-top: 10px;
        }

        .summary-container {
          margin-top: 20px;
          border: 1px solid #ddd;
          padding: 15px;
          border-radius: 4px;
          width: 80%;
          max-width: 600px;
        }
      `}</style>
      <h1>Text Summarizer</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="inputText">Enter Text:</label>
        <textarea
          id="inputText"
          value={inputText}
          onChange={handleInputChange}
          rows="10"
          cols="50"
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Summarizing...' : 'Summarize'}
        </button>
        {error && <p className="error">{error}</p>}
      </form>
      {summary && (
        <div className="summary-container">
          <h2>Summary:</h2>
          <p>{summary}</p>
        </div>
      )}
    </div>
  );
}

Here’s a breakdown of what’s happening in this updated code:

  1. Import OpenAI: We import `Configuration` and `OpenAIApi` from the `openai` package.
  2. API Key Configuration: We create a new `Configuration` object, passing in our API key from the environment variables (`process.env.OPENAI_API_KEY`).
  3. Creating OpenAI Instance: We create an instance of the `OpenAIApi` class, using the configuration.
  4. API Call: We use the `openai.createCompletion()` method to send a request to the OpenAI API. We pass in the model we want to use (e.g., “text-davinci-003”) and the prompt. The prompt includes the instruction to summarize the text and the input text itself. We also set `max_tokens` to limit the length of the summary.
  5. Handling the Response: We extract the summarized text from the API response (`completion.data.choices[0].text`). The `.trim()` method removes any leading or trailing whitespace.
  6. Error Handling: We include a `try…catch` block to handle potential errors during the API call, setting an error message if something goes wrong.
  7. Loading State: We use the `loading` state variable to disable the button and show a “Summarizing…” message while the API call is in progress.

Now, save the file and test the application. Enter some text in the text area, and click the “Summarize” button. You should see the summarized text appear below.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • API Key Issues:
    • Incorrect API Key: Double-check that you’ve entered your OpenAI API key correctly in your `.env.local` file. Typos are common.
    • Missing API Key: Ensure that the `.env.local` file exists in the root directory and that the `OPENAI_API_KEY` variable is defined.
    • API Key Not Loaded: Make sure your Next.js application is configured to load environment variables from `.env.local`. This is usually handled automatically, but if you’re having trouble, you might need to restart your development server.
  • CORS Errors: If you’re encountering CORS (Cross-Origin Resource Sharing) errors, it means your browser is blocking the request to the OpenAI API. This is usually due to the server not allowing requests from your domain. During development, this is less common with Next.js, but if you deploy your application, you might need to configure CORS on your server-side.
  • Rate Limits: The OpenAI API has rate limits. If you’re exceeding the rate limits, you’ll receive an error. You might need to implement error handling and retry mechanisms in your code. Also, consider the number of requests you are making and the length of the text you are summarizing.
  • Model Selection: The `text-davinci-003` model is used in the example, which is a powerful model, but also has associated costs. You can experiment with other models, but be aware of the different capabilities and costs associated with each. Refer to the OpenAI documentation for the most up-to-date information on available models.
  • Prompt Engineering: The quality of the summary depends on the prompt you provide to the API. Experiment with different prompts to get better results. For example, you can specify the desired length of the summary, the tone, or the specific information you want to extract.
  • Incorrect Package Installation: Double-check that you’ve installed the `openai` package correctly using `npm install openai` or `yarn add openai`.
  • Network Issues: Ensure you have a stable internet connection, as the API call requires an active internet connection.

Enhancements and Future Improvements

This is a basic text summarizer, but there are several ways you can enhance it:

  • User Input for Summary Length: Allow the user to specify the desired length of the summary (e.g., short, medium, long).
  • Customizable Prompts: Allow the user to customize the prompt sent to the OpenAI API to influence the summarization style and focus.
  • Support for Different Models: Provide options for the user to select different OpenAI models.
  • Text Input from URL: Add the ability to summarize text from a URL instead of requiring the user to paste the text. You could fetch the content of the URL using the `fetch` API on the client-side or on the server-side with Next.js API routes.
  • Advanced Summarization Techniques: Explore more advanced summarization techniques, such as extractive summarization (selecting key sentences from the original text) or abstractive summarization (generating new sentences to summarize the text).
  • UI Enhancements: Improve the user interface with better styling, loading animations, and feedback messages. Consider using a UI library like Material UI or Ant Design.
  • Error Handling: Implement more robust error handling to provide informative messages to the user.
  • Rate Limiting: Implement rate limiting on your application to prevent excessive API calls and potential costs.

SEO Best Practices

To ensure your text summarizer ranks well in search results, consider the following SEO best practices:

  • Keyword Research: Identify relevant keywords that users might search for (e.g., “text summarizer,” “summarize text online,” “article summarizer”).
  • Title Tag: Use a descriptive and keyword-rich title tag for your page (<title>Text Summarizer – Summarize Text Online</title>).
  • Meta Description: Write a concise meta description that accurately describes the purpose of your text summarizer (<meta name=”description” content=”Summarize text quickly and easily with our free online text summarizer. Get concise summaries in seconds.”>).
  • Heading Tags: Use heading tags (H1-H6) to structure your content logically and make it easy for search engines to understand the hierarchy of your information.
  • Content Optimization: Write high-quality, informative content that answers users’ questions and provides value. Include relevant keywords naturally throughout your content.
  • Internal Linking: Link to other relevant pages on your website to improve user experience and help search engines understand the relationships between your content.
  • Mobile-Friendliness: Ensure your website is responsive and works well on all devices.
  • Page Speed: Optimize your website for fast loading speeds. This includes optimizing images, minifying CSS and JavaScript, and using a content delivery network (CDN).

Summary / Key Takeaways

In this tutorial, we built a functional text summarizer using Next.js and the OpenAI API. We covered the essential steps, from setting up a Next.js project to integrating the OpenAI API and handling user input. We also discussed common mistakes and provided suggestions for future improvements. By following this guide, you should have a solid understanding of how to build a basic web application with Next.js and how to integrate external APIs. Remember to protect your API keys and be mindful of the costs associated with using the OpenAI API. Text summarization is a valuable skill in today’s information-rich world, and this project serves as a great starting point for further exploration and development in the field of natural language processing.

FAQ

1. How much does it cost to use the OpenAI API?

The OpenAI API is a paid service. The cost depends on the model you use and the number of tokens (words) processed. You can find detailed pricing information on the OpenAI website. Be sure to monitor your usage and set up spending limits to avoid unexpected charges.

2. Can I use this summarizer for commercial purposes?

Yes, you can use the text summarizer for commercial purposes, but you must adhere to the OpenAI API’s terms of service and usage policies. It’s crucial to review these terms carefully. You are responsible for ensuring your use of the API complies with all applicable laws and regulations.

3. What is the difference between “text-davinci-003” and other OpenAI models?

“text-davinci-003” is a powerful language model known for its ability to generate high-quality text, translate languages, write different kinds of creative content, and answer your questions in an informative way. Other models, like the newer GPT-3.5 and GPT-4 models, may offer enhanced performance and features. The best model for your use case depends on your specific needs, the complexity of the task, and your budget. Consider exploring different models to find the one that best suits your requirements.

4. How can I handle long texts that exceed the token limit?

The OpenAI API has token limits to control the length of the input and output. If you need to summarize a very long text that exceeds the token limit, you can try these approaches: (1) Split the text into smaller chunks and summarize each chunk individually, then combine the summaries. (2) Use a model with a higher token limit, if available. (3) Experiment with different summarization techniques, such as reducing the `max_tokens` parameter or using a different model that is more efficient at summarizing. (4) Summarize the text iteratively, summarizing the initial summary to create a more concise version.

5. How can I deploy this Next.js app?

You can deploy your Next.js app to various platforms, such as Vercel (which is the recommended platform for Next.js), Netlify, or AWS. The deployment process typically involves pushing your code to a Git repository and configuring the deployment platform to build and deploy your application. Each platform has its own set of instructions and configurations for deployment.

Building a text summarizer is a great way to explore the power of Next.js and integrate with external APIs. The ability to quickly extract the essence of any text can be a significant advantage in many aspects of our lives. As you continue to refine and improve this application, you’ll gain valuable experience in web development and the exciting field of artificial intelligence.