How to Efficiently Organize OpenAI AI Responses Using TypeScript/JavaScript and CSS

I'm using a Next.js framework to connect to the OpenAI API, and I've integrated it seamlessly with an AI npm package. The functionality is incredible, but I've encountered an issue regarding line breaks in the responses.

You can find the AI npm package here: https://www.npmjs.com/package/ai

For example, when I receive this response:

This is a paragraph.

This is a new paragraph.

it appears as a single line without any breaks:

This is a paragraph. This is a new paragraph.

Therefore, my goal is to figure out how to insert appropriate line break <br> tags or surround each paragraph with <p> tags. It's possible that I'm overlooking something obvious, so I thought it'd be worth asking for help since I couldn't find an answer within the chat from GPT itself.

Is there a default method provided by OpenAI to handle this issue?

Here is a reference to some sample code taken directly from the mentioned package:

import OpenAI from 'openai';
import { OpenAIStream, StreamingTextResponse } from 'ai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

export const runtime = 'edge';

export async function POST(req) {
  const { messages } = await req.json();
  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    stream: true,
    messages,
  });
  const stream = OpenAIStream(response);
  return new StreamingTextResponse(stream);
}

// ./app/page.js
'use client';

import { useChat } from 'ai/react';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat();

  return (
    <div>
      {messages.map(m => (
        <div key={m.id}>
          {m.role}: {m.content}
        </div>
      ))}

      <form onSubmit={handleSubmit}>
        <input
          value={input}
          placeholder="Say something..."
          onChange={handleInputChange}
        />
      </form>
    </div>
  );
}

In this example, I'd like to format the "m.content" in a way that includes line breaks where they are currently absent. If you log the "m.content" and inspect its string value in the console, you'll see that the paragraph structure is present; it's just not properly formatted for HTML.

Answer №1

To format the content, you have the option of using different tags for each paragraph:

 const ChatComponent = () => {
  const { messages, input, handleInputChange, handleSubmit } = useChat();
  return (
    <div>
      {messages.map(m => (
       <div key={m.id}>
        {m.role}: {m.content.split('\n').map(paragraph => (<p style={/*...*/}>{paragraph}</p>))}
       </div>
       ))}
       ...
    </div>)
}
export default ChatComponent;

Answer №2

It seems almost silly how simple the solution to this problem is.

{messages.map(m => (
   <div key={m.id} className='pb-2'>
      <div className="font-bold">{m.role}</div>
      <pre className="overflow-x-auto whitespace-pre-wrap">{m.content}</pre>
    </div>
 ))}

Hopefully, this will be beneficial to someone who might have otherwise spent unnecessary time on this issue. By using the <pre> tags, the output code is formatted correctly with proper line breaks and preserved spaces and tabs from the open ai api.

Furthermore, adding a bit of CSS, such as in the example above using tailwind, can ensure that the text wraps where intended instead of extending endlessly to the right of the page.

overflow-x: auto and whitespace: pre-wrap

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What's the best way to determine which of the two forms has been submitted in Django?

On my homepage, I have both a log_in and sign_up form. Initially, the log_in form is displayed by default, but when a user clicks on the Sign Up button, the sign_up form appears. These toggles switch depending on which button the user clicks. from django ...

Guide on transforming a collection of files from formdata into a JavaScript object

I have a dataset containing multiple images associated with the same product id. import client from "@/lib/fetchWrapper"; export default async function addProductImage({ photo, productId, }: { photo: File[]; productId: string; }) { if ...

Unearthing the worth of the closest button that was clicked

I am currently working on a profile management feature where I need to add students to the teacher's database. To achieve this, I am using jQuery and AJAX. However, I am encountering an issue where clicking the "add" button for each student listed on ...

Prevent Second Division from wrapping around floated Division

I am running into a minor issue with the positioning of a div in my current project. +------------------------+ |+-------+ ~~~~ TITLE| <--how can I prevent text from wrapping around || | ~~~~~~~~~~~~~ |\ on the left ...

Problem with escaping special characters in random string HTML

As I was in the process of creating a JavaScript tool to generate random strings, with or without special characters, I stumbled upon an inspiring snippet that caught my attention: (): function randStr(len) { let s = ''; while (len--) s += ...

Fetch data from Firestore when the page loads using the useEffect hook

Below is the simplified code snippet I am currently using: import { useState, useEffect, useContext } from 'react' import { useRouter } from 'next/router' import { firestore } from './firebase-config' import { getDoc, doc } f ...

Why would someone use the `catch` method in Angular $http service when the `then` method already takes two arguments (success and error callbacks)?

When working with the Angular $http service, there is a then method that can take two arguments - one for success and one for error. But why would you use the catch method if there's already an error callback? And what is its purpose? Here's an ...

Tips for understanding nested JSON or array data structure?

My data is stored in a constant called translations and it looks like this: { "item-0": { "_quote-translation": "translation Data", "_quote-translation-language": "English", "_quote-trans ...

Transitioning the font stack from SCSS to JSS (cssinjs)

We are currently implementing a variety of custom fonts with different weights for various purposes. With our entire stack now using Material UI with JSS theming and styling, we aim to eliminate the remaining .scss files in our folder structure. All the f ...

Blue Jay Guarantees: Construct props object on the fly and execute simultaneously

If we take a look at this example: https://github.com/petkaantonov/bluebird/blob/master/API.md#props---promise Promise.props({ pictures: getPictures(), comments: getComments(), tweets: getTweets() }).then(function(result) { console.log(re ...

Enhanced Interactivity: jQuery UI Dialog Button Transforms Position upon Mouse Hover

I am utilizing the jQuery UI dialog feature and implementing buttons using jQuery in the following manner: $("#151").dialog({ autoOpen: false, autoResize: true, buttons: { "OK": function ...

Applying a class change in Vue.js upon mounting

How can I make a button element with a .hover property trigger the hover animation as soon as the page loads? I want to apply a class to the button when the page is mounted and then remove it later. What is the best approach for this? I considered using a ...

What is the best way to customize the appearance of a non-current month cell within the date picker?

I'm currently in the process of developing a registration form for my JavaFX application. I am faced with an issue where I need to disable certain cells in the date picker when they do not belong to the displayed month. Let's take a look at my cu ...

What is the best way to retrieve an element that has been altered in its state?

I encountered a scenario where I want an image to have a border when clicked, and if clicked again, the border should be removed. However, the border should also be removed if another image is clicked instead. I believe there are a couple of approaches to ...

"Tips for SunPass Finesse: Navigating ESLint Errors When Committing Code on

While attempting to commit changes to my dev branch in Gitlab, I encountered errors related to ESLint which caused the commit to be aborted. To troubleshoot, I cloned the repository from the dev branch, made changes, and installed dependencies using &apos ...

Implementing a notification upon submission within a function

I have encountered an issue while trying to implement a customized alert after calling onSubmit. Despite including the alert in my function as shown below, it fails to appear upon clicking the submit button. Interestingly, when I use the regular 'aler ...

Obtain JSON information and integrate it into an HTML document with the help of

I am currently working on a PHP/JSON file named users-json.php. <?php include_once('../functions.php'); if (!empty($_GET['id'])) { $GetID = $_GET['id']; $query = "SELECT Username, Firstname WHERE UserID = :ID"; $stmt = $d ...

How to Position Logo in the Center of MUI AppBar in React

I've been struggling to center align the logo in the AppBar. I can't seem to get the logo to be centered both vertically and horizontally on its own. Here is my code from AppBar.tsx: import * as React from 'react'; import { styled, useT ...

Showing the computation outcome on the identical page

I have implemented a table within my PHP code. In the second column of this table, it typically displays "---". However, once I click the submit button, the same page should now display the calculated result. Here is an example: <table> <tr>& ...

How do I specify a unique directory for pages in Next.js that is not within the src or root folders?

I'm currently facing an issue when trying to set a custom directory in Next JS. Although the default setup dictates that the pages directory should be located at the root or within the src directory, this arrangement doesn't fit my requirements ...