0

I am learning React and I am trying to create a specialized chatbot using the ChatGPT API along the way. At the moment I am just trying to get a response from the API using axios. I have my API key in a .env, yet I am still getting a 401 error indicating that I need to provide an API key. It works if I hardcode the API key, so there must be some error in reading from the .env. You can find my code for the Chat functionality below.

I initially tried using the openai package along with the createCompletion() method, but that gave an error saying Refused to set unsafe header "User Agent", which I didn't quite understand, so I opted for the current approach. I will provide the code for my attempt with openai at the bottom.

Any help is appreciated, thanks.

Current code using axios:

import React, { useState, useEffect } from "react";
import { PaperAirplaneIcon } from "@heroicons/react/20/solid";
import axios from "axios";
import UserMessage from "./UserMessage";
import BotMessage from "./BotMessage";

const Chat = () => {
  const [messages, setMessages] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [loading, setLoading] = useState(false);

  const handleInputSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    const userMessage = { type: "user", text: inputValue };
    setMessages([...messages, userMessage]);
    const botMessage = await getBotMessage(inputValue);
    setInputValue("");
    setMessages([...messages, botMessage]);
    setLoading(false);
  };

  const getBotMessage = async (userMessage) => {
    try {
      const response = await axios.post(
        "https://api.openai.com/v1/chat/completions",
        {
          messages: [
            { role: "system", content: "You are a helpful assistant." },
            { role: "user", content: userMessage },
          ],
          max_tokens: 256,
          n: 1,
          temperature: 0.85,
          model: "gpt-3.5-turbo",
        },
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${process.env.REACT_APP_OPENAI_API_KEY}`,
          },
        }
      );
      //console.log("response", response.data.choices[0].text);
      const botMessage = { type: "bot", text: response.data.choices[0].text };
      return botMessage;
    } catch (e) {
      console.log(e);
      const botMessage = {
        type: "bot",
        text: "Something went wrong. Try again.",
      };
      return botMessage;
    }
  };

  return (
    <div className="flex flex-col items-center w-full h-full justify-between">
      <h1 className="text-3xl font-bold my-5">Chatbot</h1>
      <div className="w-full">
        {messages.map((message, index) => {
          if (message.type === "user") {
            return <UserMessage key={index} text={message.text} />;
          }
          return <BotMessage key={index} text={message.text} />;
        })}
        <form
          onSubmit={handleInputSubmit}
          className="flex flex-row w-full mb-5 mt-2"
        >
          <input
            className="border-2 rounded-md p-2 w-full"
            type="text"
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
          />
          <button type="submit">
            <PaperAirplaneIcon className="w-6 h-6 text-green-500" />
          </button>
        </form>
      </div>
    </div>
  );
};

export default Chat;

This was my attempt using openai (not my current code):

import React, { useState, useEffect } from "react";
import { PaperAirplaneIcon } from "@heroicons/react/20/solid";
import axios from "axios";
import UserMessage from "./UserMessage";
import BotMessage from "./BotMessage";
const { Configuration, OpenAIApi } = require("openai");

const Chat = () => {
  const [messages, setMessages] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [loading, setLoading] = useState(false);

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

  const handleInputSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    const userMessage = { type: "user", text: inputValue };
    setMessages([...messages, userMessage]);
    const botMessage = await getBotMessage(inputValue);
    setInputValue("");
    setMessages([...messages, botMessage]);
    setLoading(false);
  };

  const getBotMessage = async (userMessage) => {
    try {
      const response = await openai.createCompletion({
        model: "gpt-3.5-turbo",
        prompt: userMessage,
        temperature: 0.85,
        max_tokens: 4000,
      });
      //console.log("response", response.data.choices[0].text);
      const botMessage = { type: "bot", text: response.data.choices[0].text };
      return botMessage;
    } catch (e) {
      console.log(e);
      const botMessage = {
        type: "bot",
        text: "Something went wrong. Try again.",
      };
      return botMessage;
    }
  };

  return (
    <div className="flex flex-col items-center w-full h-full justify-between">
      <h1 className="text-3xl font-bold my-5">Golfdommer</h1>
      <div className="w-full">
        {messages.map((message, index) => {
          if (message.type === "user") {
            return <UserMessage key={index} text={message.text} />;
          }
          return <BotMessage key={index} text={message.text} />;
        })}
        <form
          onSubmit={handleInputSubmit}
          className="flex flex-row w-full mb-5 mt-2"
        >
          <input
            className="border-2 rounded-md p-2 w-full"
            type="text"
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
          />
          <button type="submit">
            <PaperAirplaneIcon className="w-6 h-6 text-green-500" />
          </button>
        </form>
      </div>
    </div>
  );
};

export default Chat;

bragi
  • 183
  • 2
  • 12
  • Is your app using react-scripts? That is, did you create it with Create React App? If not, you have to do something on purpose to load the `.env` file. – T.J. Crowder Apr 19 '23 at 08:41
  • @T.J.Crowder Yes, I created the development environment using `create-react-app` in cmd – bragi Apr 19 '23 at 08:43
  • use dotenv to read from `.env` file `import dotenv from 'dotenv'; dotenv.config();` then use `process.env.REACT_APP_API_KEY`. Note that the variable name starts with REACT_APP_ - this is required for Create React App to load the variables correctly. – AhmadDeel Apr 19 '23 at 09:14

1 Answers1

1

If you have created your React app using create-react-app then you could do the following to configure your API key using environment variables (.env)

  1. Install env-cmd package from npm

  2. Make a file called .env.envName in your project root, For example: For staging you can name it as .env.staging, .env.production and so on to differentiate between variables in each environment.

  3. Inside the env file add your variables in key/value representation with prefix of REACT_APP as follows:

    REACT_APP_API_KEY = "****"

Inside your package.json. change the build scripts as follows:

"scripts": {
    "start": "env-cmd -f .env.staging react-scripts start",
    "build:staging": "env-cmd -f .env.staging react-scripts build",
    "build:production": "env-cmd -f .env.production react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

Note: -f flag is for custom env file paths as the default is in the project root otherwise you should specify the actual path. For example,

"start": "env-cmd -f ../../.env.staging react-scripts start",

Regarding your error Refused to set unsafe header "User Agent", I would suggest you to have a look at this link.

Hope that helps.

inkredusk
  • 919
  • 4
  • 16
  • Thanks for the reply. Though, I realized that having the .env on the frontend wasn't secure, so now I've opted for a Python Flask backend, that can handle the requests for me and provide it to me frontend. This works atm. I appreciate your answer and have upvoted it, but won't be checking if it actually work right now. If I ever get around to that, I will of course return to mark your answer. (Sorry!) – bragi Apr 19 '23 at 09:50
  • Yes I was to mention about it as well. Its better to use a backend and place all `configuration` related things on the backend. If you are using `Flask` please check this link https://flask.palletsprojects.com/en/1.1.x/config/. happy to help you if you need any thing for backend as well. – inkredusk Apr 19 '23 at 10:45