使用 React 和 OpenAI API 构建自己的 ChatGPT 克隆

在本教程中,我们将介绍如何构建自定义聊天机器人应用程序,该应用程序允许我们提出问题并获得高质量的答案。该机器人将记住之前的提示,模拟情境感知对话。

关键要点

  1. 使用 OpenAI 的 ChatGPT 和 React 创建聊天机器人:本教程提供了使用 React 构建自定义聊天机器人应用程序的分步说明,利用 OpenAI 的 ChatGPT 进行高级语言处理。聊天机器人会记住之前的提示,模拟连续的、上下文感知的对话。
  2. 实现用户界面和功能:该应用程序具有用户友好的界面,其中包含消息窗口、输入区域、提交按钮和对话历史记录等组件。它演示了如何构建 React 应用程序、管理状态和处理事件以实现无缝的用户体验。
  3. 集成 API 调用和处理数据:本教程将指导您完成对 OpenAI 的 ChatGPT 进行 API 调用以及处理数据以显示聊天机器人响应的过程。它强调了保护 API 密钥的重要性,尤其是对于生产环境,并提出了一些增强功能,例如使用 Express 进行服务器端操作以及整合持久存储以存储对话历史记录。

在当今快速发展的数字环境中,聊天机器人已成为企业和开发人员寻求改善客户互动和简化用户体验的不可或缺的工具。OpenAI 的 ChatGPT已从一项前沿实验转变为聊天机器人开发领域的强大力量。它迅速崛起的成功令人惊叹,吸引了全球用户。 该项目的演示代码可在CodeSandbox上找到。您必须在文件中提供自己的 OpenAI API 密钥.env才能进行实时测试。要获取一个,请在OpenAI上创建一个帐户,登录,导航到API 密钥并生成一个新的 API 密钥。

规划功能和用户界面

我们的应用程序将基于React,我们将使用OpenAI API访问数据并使用CSS 模块进行样式设置。利用 React 将使我们能够创建动态且响应迅速的用户界面,从而增强整体用户体验。OpenAI API 将使我们能够访问高级语言处理功能,提供数据以创建富有洞察力的交互。此外,CSS 模块将使我们能够保持模块化设计,促进应用程序的高效开发和定制。我们将实现的功能包括:

  • 指定的输入区域,用户可在此制作提示,邀请与上下文相关的询问。
  • 提交按钮允许用户向 API 提交他们的提示,从而启动对话过程。
  • 消息项目将以聊天式消息的形式在对话窗口内展示,增强交互式聊天体验。
  • 用于显示 ChatGPT 回复的消息项将提供对话流。
  • 历史记录功能将列出用户的所有最近提示。这还允许用户重新访问以前的对话。
  • 清除按钮可以删除生成的内容,为新的对话提供一个干净的背景。

下图显示了我们基于组件的线框。

使用 React 和 OpenAI API 构建自己的 ChatGPT 克隆

整个应用程序将被包装在主容器中,主容器将所有元素放在一起。它将进一步分为两列布局。第一列将包含来自用户和 ChatGPT 的所有消息。在列的底部,将有一个输入区域和一个用于提交提示的按钮。第二列将保存所有最近提示的历史记录。在列的底部,将有一个清除按钮,允许用户擦除生成的内容。

选择颜色方案

应用程序设计将优先考虑内容感知的便利性。这将使我们能够提供一些重要的好处:

  • 用户将能够快速理解所呈现的信息,从而获得更加直观和用户友好的体验。
  • 它还将增强可访问性,确保不同背景和能力的个人能够轻松浏览和参与内容。

下图显示了我们的配色方案。

使用 React 和 OpenAI API 构建自己的 ChatGPT 克隆

应用程序的背景将为黑色,而消息、历史记录项和输入表单将为深灰色。消息和输入背景上的文本将为白色,提供良好的对比度并使文本易于阅读。为了给应用程序增加一些亮点,列标题、提交按钮和回复消息头像将使用明亮的浅绿色色调。为了突出清除按钮,将使用柔和的红色色调。这也有助于用户避免意外点击按钮。

设置 React 应用程序

我们将使用create-react-app来创建我们的应用程序。运行npx create-react-app react-chatgpt以创建一个新的 React 项目。等待一分钟以完成设置,然后将工作目录更改为新创建的文件夹并cd react-chatgpt运行npm start以启动开发人员服务器。这应该会在我们的默认浏览器中打开我们的项目。如果没有,请导航到http://localhost:3000以手动打开它。

添加全局样式

我们将添加全局样式,以在应用程序的所有组件中建立一致且统一的视觉外观。打开index.css并包含以下样式规则:

@import url("https://fonts.googleapis.com/css2?family=Varela+Round&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Varela Round", sans-serif;
}

body {
  background-color: #121212;
}

首先,我们导入Varela Round字体,并设置整个应用使用该字体。我们还删除了所有预定义的边距和填充,并进行了设置,box-sizingborder-box使应用在不同浏览器上看起来相同。最后,我们将主体的背景设置为深色,这样我们就可以突出显示应用的内容。

下载媒体

我们需要几个头像来代表来自用户和 OpenAI API 的消息的作者。这样,它们会更容易区分。在目录icons中创建一个新文件夹src,并包含bot.pnguser.png图标。 您可以从此处的icons目录中下载示例,也可以使用来自FlatIcon或Icons8等网站的自定义示例,只要您保留上述文件名即可。

构建组件

首先,我们需要一个与线框设计相匹配的组织良好的文件结构。我们将使用终端创建必要的文件夹和组件文件。每个组件都有自己的 JavaScript 文件用于功能,还有 CSS 文件用于样式。src通过运行更改文件夹中的工作目录cd src,然后运行以下命令:

mkdir components && cd components && touch Message.js Message.module.css Input.js Input.module.css History.js History.module.css Clear.js Clear.module.css

上述命令将首先创建一个/components/文件夹,然后将工作目录更改为该文件夹,并在其中创建所有必要的文件。

消息组件

Message组件将在对话中显示用户提示和 API 响应,促进用户和聊天机器人之间的实时信息交换。打开文件Message.js并包含以下代码:

import bot from "../icons/bot.png";
import user from "../icons/user.png";

import styles from "./Message.module.css";

export default function Message({ role, content }) {
  return (
    <div className={styles.wrapper}>
      <div>
        <img
          src={role === "assistant" ? bot : user}
          className={styles.avatar}
          alt="profile avatar"
        />
      </div>
      <div>
        <p>{content}</p>
      </div>
    </div>
  );
}

首先,我们导入下载的头像图标,然后导入外部 CSS 规则进行样式设置。之后,我们创建组件的包装器Message,其中包含图标和文本内容。我们使用role

prop 条件中显示适当的头像作为图像src。我们还使用 prop content,它将作为来自 OpenAI API 的文本响应和用户输入提示传入。现在让我们设置组件的样式,使其看起来像聊天消息!打开文件Message.module.css并包含以下规则:

.wrapper {
  display: grid;
  grid-template-columns: 60px auto;
  min-height: 60px;
  padding: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  background-color: #1b1b1d;
}

.avatar {
  width: 40px;
  height: 40px;
}

我们将布局分为两列,头像显示在右侧的固定宽度容器中,文本显示在左侧。接下来,我们在消息底部添加一些填充和边距。我们还将消息样式设置为圆形边框,并将背景设置为深灰色。最后,我们将头像图标设置为固定宽度和高度。

输入组件

Input组件将是一个用于捕获用户查询的界面元素,作为用户与聊天机器人交互和互动的手段。打开文件Input.js并包含以下代码:

import styles from "./Input.module.css";

export default function Input({ value, onChange, onClick }) {
  return (
    <div className={styles.wrapper}>
      <input
        className={styles.text}
        placeholder="Your prompt here..."
        value={value}
        onChange={onChange}
      />
      <button className={styles.btn} onClick={onClick}>
        Go
      </button>
    </div>
  );
}

我们首先导入外部样式表来设置组件的样式。我们返回包含用户提示的输入字段和将其提交给 API 的按钮的组件包装器。我们设置输入表单为空时显示的占位符值,并创建 propvalue来保存输入的提示,以及onChange输入值更改后将调用的 prop。对于按钮,onClick用户单击按钮后将调用该 prop。现在让我们设置组件的样式,使输入区域看起来很漂亮,并鼓励用户提供提示!打开文件Input.module.css并包含以下规则:

.wrapper {
  display: grid;
  grid-template-columns: auto 100px;
  height: 60px;
  border-radius: 10px;
  background-color: #323236;
}

.text {
  border: none;
  outline: none;
  background: none;
  padding: 20px;
  color: white;
  font-size: 16px;
}

.btn {
  border: none;
  border-radius: 0 10px 10px 0;
  font-size: 16px;
  font-weight: bold;
  background-color: rgb(218, 255, 170);
}

.btn:hover {
  cursor: pointer;
  background-color: rgb(200, 253, 130);
}

我们将包装器设置为分为两列,按钮的宽度固定,其余可用宽度专用于输入区域。我们还定义了组件的具体高度,为其设置了圆角边框,并将背景设置为深灰色。对于输入区域,我们删除了默认的边框、轮廓、背景并添加了一些填充。我们将文本颜色设置为白色并设置特定的字体大小。

历史组件

History组件将显示过去用户和聊天机器人交互的顺序,为用户提供对话的上下文参考。打开文件History.js并包含以下代码:

import styles from "./History.module.css";

export default function History({ question, onClick }) {
  return (
    <div className={styles.wrapper} onClick={onClick}>
      <p>{question.substring(0, 15)}...</p>
    </div>
  );
}

我们首先导入组件的外部样式规则。然后我们返回包含文本的包装器。文本值将作为questionprop 从用户提示中传入,并且仅显示文本字符串的前 15 个字符。用户将被允许点击历史记录项,我们将传递 proponClick来控制点击行为。现在让我们设置组件的样式,以确保它在视觉上具有吸引力并且适合侧边栏!打开文件History.module.css并包含以下规则:

.wrapper {
  padding: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  background-color: #1b1b1d;
}

.wrapper:hover {
  cursor: pointer;
  background-color: #323236;
}

我们设置了一些填充,在底部添加了边距,并为历史记录项设置了圆角。我们还将背景颜色设置为深灰色。一旦用户将鼠标悬停在项目上,光标将变为指针,背景颜色将变为浅灰色。

Clear 组件

Clear组件将是一个用于重置或清除正在进行的对话的 UI 元素,为用户提供一种快速开始新交互的方法,而无需离开当前界面。打开文件Clear.js并包含以下代码:

import styles from "./Clear.module.css";

export default function Clear({ onClick }) {
  return (
    <button className={styles.wrapper} onClick={onClick}>
      Clear
    </button>
  );
}

我们首先导入外部样式表来设置组件的样式。我们返回允许用户清除应用程序内容的按钮。我们将传递 proponClick来实现所需的行为。现在让我们设置组件的样式,使其脱颖而出,并减少用户意外按下它的机会!打开文件Clear.module.css并包含以下规则:

.wrapper {
  width: 100%;
  height: 60px;
  background-color: #ff9d84;
  border: none;
  border-radius: 10px;
  font-size: 16px;
  font-weight: bold;
}

.wrapper:hover {
  cursor: pointer;
  background-color: #ff886b;
}

我们将按钮设置为填充列的可用宽度,设置特定高度,并将背景颜色设置为淡红色。我们还删除了默认边框,设置了圆角,设置了特定字体大小,并将其设为粗体。悬停时,光标将变为指针,背景颜色将变为深红色。

构建用户界面

在上一节中,我们构建了所有必要的组件。现在让我们将它们放在一起并为应用程序构建用户界面。我们将配置它们的功能,以使用有组织且可重用的代码创建一个功能齐全且可交互的聊天机器人界面。打开文件App.js并包含以下代码:

import { useState } from "react";

import Message from "./components/Message";
import Input from "./components/Input";
import History from "./components/History";
import Clear from "./components/Clear";

import "./styles.css";

export default function App() {
  const [input, setInput] = useState("");
  const [messages, setMessages] = useState([]);
  const [history, setHistory] = useState([]);

  return (
    <div className="App">
      <div className="Column">
        <h3 className="Title">Chat Messages</h3>
        <div className="Content">
          {messages.map((el, i) => {
            return <Message key={i} role={el.role} content={el.content} />;
          })}
        </div>
        <Input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onClick={input ? handleSubmit : undefined}
        />
      </div>
      <div className="Column">
        <h3 className="Title">History</h3>
        <div className="Content">
          {history.map((el, i) => {
            return (
              <History
                key={i}
                question={el.question}
                onClick={() =>
                  setMessages([
                    { role: "user", content: history[i].question },
                    { role: "assistant", content: history[i].answer },
                  ])
                }
              />
            );
          })}
        </div>
        <Clear onClick={clear} />
      </div>
    </div>
  );
}

首先,我们导入useState用于跟踪应用程序数据状态的钩子。然后,我们导入构建的所有组件和用于样式设置的外部样式表。然后,我们创建input状态变量来存储用户提示输入、messages存储用户与 ChatGPT 之间的对话以及history存储用户提示的历史记录。我们还为整个应用程序创建了包含两列的主包装器。每列都有一个标题和内容包装器,其中包括第一列的对话消息、输入区域和提交按钮以及第二列的历史记录项和清除按钮。对话消息将通过映射状态变量和历史记录项生成messages——通过映射history状态变量。我们设置输入onChange属性,以便在用户每次在输入表单中输入任何值时更新input状态变量。一旦用户单击发送按钮,用户提示将被发送到 OpenAI API 以处理并接收回复。对于历史记录项,我们设置了属性,onClick以便messages状态变量更新为特定的提示和答案。最后,对于清除按钮,我们传递onClick一个函数来清除消息和历史记录值,从而清除应用程序数据。

创建应用程序布局

在本节中,我们将安排用户界面组件,以创建直观的结构,实现有效的用户交互。打开App.css

并包括以下样式规则:

.App {
  display: grid;
  grid-template-columns: auto 200px;
  gap: 20px;
  max-width: 1000px;
  margin: 0 auto;
  min-height: 100vh;
  padding: 20px;
}

.Column {
  color: white;
}

.Title {
  padding: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  color: black;
  background-color: rgb(218, 255, 170);
}

.Content {
  height: calc(100vh - 200px);
  overflow-y: scroll;
  margin-bottom: 20px;
}

::-webkit-scrollbar {
  display: none;
}

我们将主应用程序包装器分成两列,使用CSS 网格布局以间隙隔开,并将历史项目的左列设置为固定宽度。接下来,我们将包装器设置为永远不会超过某个宽度,将其置于屏幕中央,使其使用整个屏幕视口高度,并在其中添加一些填充。对于每列的内容,我们将文本颜色设置为白色。对于列标题,我们设置了一些填充,添加了底部边距,并设置了圆角。我们还将标题元素的背景颜色设置为浅绿色,并将文本颜色设置为黑色。我们还通过设置规则来设置列本身的样式,即内容不应超过一定高度,并将内容设置为在超出高度时可滚动。我们还在底部添加了一个边距。我们还隐藏了滚动条,这样我们就不必设置它们的样式来覆盖每个浏览器的默认值。此规则是可选的,我们可以将其省略。

从 OpenAI 获取 API 密钥

如果您尚未在本教程的介绍中为Sandbox设置自己的 API 密钥,请确保在OpenAI网站上创建一个帐户。接下来,登录并导航到API 密钥并生成一个新的 API 密钥。

将密钥复制到剪贴板并打开您的项目。在项目根目录中创建一个新.env文件并粘贴以下密钥的值,如下所示:

REACT_APP_OPENAI_API_KEY=paste-your-code-here

准备对 OpenAI API 的请求调用

通过OpenAI API,我们的聊天机器人将能够向 OpenAI 服务器发送文本提示,然后服务器将处理输入并生成类似人类的响应。这是通过利用在各种文本源上训练过的强大语言模型来实现的。通过为模型提供对话历史记录和当前用户提示,我们的聊天机器人将从 API 接收上下文感知响应。在本节中,我们将准备请求并实现对 API 的调用以接收响应并将数据设置为我们之前定义的状态变量。App.js再次打开并添加以下代码:

// imported modules ...

export default function App() {
  // useState variables ...

  const handleSubmit = async () => {
    const prompt = {
      role: "user",
      content: input,
    };

    setMessages([...messages, prompt]);

    await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.REACT_APP_OPENAI_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "gpt-3.5-turbo",
        messages: [...messages, prompt],
      }),
    })
      .then((data) => data.json())
      .then((data) => {
        const res = data.choices[0].message.content;
        setMessages((messages) => [
          ...messages,
          {
            role: "assistant",
            content: res,
          },
        ]);
        setHistory((history) => [...history, { question: input, answer: res }]);
        setInput("");
      });
  };

  const clear = () => {
    setMessages([]);
    setHistory([]);
  };

  return <div className="App">// returned elements ...</div>;
}

首先,我们创建一个单独的handleSubmit函数,该函数将在用户在输入表单中输入提示并单击“提交”按钮后执行。在里面handleSubmit,我们首先创建一个prompt变量,该变量将角色user和提示本身作为对象保存。角色很重要,因为在存储消息时,我们需要知道哪些是用户消息。然后我们messages使用用户提示更新状态变量。接下来,我们实际调用fetchapi.openai.com/v1/chat/completions端点以访问来自 OpenAI API 的数据。我们指定它是一个POST请求,并使用授权令牌和内容类型设置标头。对于参数body,我们指定要使用的 API 模型,并将messages变量作为来自用户的内容传递。收到响应后,我们将其存储在变量中res。我们将由角色assistant和响应本身组成的对象添加到message状态变量中。我们还使用history对象更新状态变量,并使用question和对应answer作为键。收到响应并更新状态变量后,我们清除input状态变量以准备输入表单以应对下一个用户提示。最后,我们创建一个简单的clear函数来清除messageshistory状态变量,允许用户清除应用程序的数据。

结论

在本教程中,我们学习了如何创建易于使用的用户界面、如何通过组件构建代码、如何处理状态、如何进行 API 调用以及如何处理接收到的数据。通过结合 OpenIAI API 的高级自然语言处理功能和 React 的灵活性,您现在可以创建复杂的聊天机器人应用程序,并可以根据自己的喜好进一步自定义。请注意,本教程将 API 密钥存储在前端,这可能并不安全用于生产。如果要部署该项目,建议创建一个Express服务器并在其中使用 API 密钥。此外,如果您希望历史提示在下次初次启动后可用,您可以存储它们然后从本地存储中读取它们,甚至可以将数据库连接到您的应用并从那里存储和读取数据。

作者:terry,如若转载,请注明出处:https://www.web176.com/news/frontend/28366.html

(0)
打赏 支付宝 支付宝 微信 微信
terryterry
上一篇 2024年6月18日
下一篇 2024年7月1日

相关推荐

发表回复

登录后才能评论