在本指南中,我们将探讨如何使用 OpenAI 的 GPT-3 API 和服务器发送事件 (SSE) 在 React Web 应用程序中流式传输实时结果。随着人工智能和机器学习的兴起,OpenAI 的 GPT-3 已成为自然语言处理和文本生成领域最强大、最通用的工具之一。如何在 Windows 和 Mac OS 上查找计算机名称通过将其与 React 的简单性和性能以及 SSE 的实时功能相结合,您可以创建真正出色的 Web 应用程序。
在本分步指南中,我们将带您完成设置 React 环境、集成 OpenAI 的 GPT-3 API 以及使用 SSE 流式传输实时结果的过程。准备好增强您的 Web 应用程序开发技能并创建真正动态且引人入胜的用户体验。
让我们快速浏览一下我们将在本分步指南中构建的 Web 应用程序……
我们正在构建的应用程序将能够提供从 OpenAI 的 GPT-3 语言模型中检索到的实时文本响应。
为了构建这个 Web 应用程序,我们将使用以下技术:
Yarn:Yarn 是 JavaScript 的包管理器。它是广泛使用的 npm(节点包管理器)的替代品,并提供了许多优于它的好处。
Vite:Vite 是一种用于现代 Web 项目的快速、优化的构建工具和开发服务器。它的创建是为了解决传统构建工具面临的一些挑战,例如构建时间慢、包大小大以及设置开发环境的困难。
React:React 是 Facebook 开发的用于构建用户界面的最流行的 JavaScript 库之一。它非常适合构建复杂的动态用户界面。
Chakra UI:Chakra UI 是 React 的 UI 库,它提供了一组可重用和可访问的组件,用于构建现代用户界面。
OpenAI GPT-3 API:OpenAI GPT-3(Generative Pretrained Transformer 3)是OpenAI开发的一种高级语言处理AI模型。它是迄今为止最大、最强大的语言模型之一,能够为广泛的任务生成高质量的文本,包括语言翻译、问答和摘要。我们将使用 API 将模型的一些功能集成到我们的 React Web 应用程序中。
sse.js:是一个小型的 JavaScript 服务器发送事件库,我们可以很好地使用它以流模式与 OpenAI API 通信,并在我们的前端应用程序中接收服务器发送的事件。该库位于:https://github.com/mpetazzoni/sse.js
为了能够从您的 Python 脚本中访问 OpenAI API,我们需要使用 API 密钥。
要检索您的 OpenAI API 密钥,您需要在 https://openai.com/ 创建一个用户帐户并访问 OpenAI 仪表板中的 API 密钥部分以创建一个新的 API 密钥。
此密钥是秘密的,不得与任何其他人共享。稍后在实现 Python 脚本以访问 OpenAI 的 API 时,我们将需要使用此密钥。
现在让我们用 vite 创建一个新的 React 项目。在命令行中键入以下命令以启动创建过程:
$ yarn create vite
接下来系统会提示您输入新的项目名称:
输入 react-openai-sse 并回车继续。然后,Vite 将为您提供一个 JavaScript 框架列表,您可以从中进行选择。使用箭头键选择条目“React”并再次回车:
选择“React”后,系统会要求您指定 React 项目的变体。您有四个选项可供选择:
JavaScript
打字稿
JavaScript + 软件组件
打字稿 + SWC
因此,您可以决定创建一个仅使用普通 JavaScript 或也支持 Typescript 的 React 项目。此外,您可以选择使用 SWC,它是一种新的基于 Rust 的捆绑器,它声称比基于 JS 的捆绑器快得多。对于本文的示例,我们选择选项“JavaScript +SWC”。
选择后,项目设置完成:
您现在可以进入新的项目目录(使用您输入的项目名称:
$ cd react-openai-sse
接下来需要执行yarn命令:
$ yarn
这确保了项目所有需要的依赖项都被下载和安装:
下一步是安装所需的依赖项:Chakra UI 和 sse.js。让我们从 Chakra UI 开始。为了安装 UI 库,您需要在项目文件夹中执行以下命令:
$ yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
其次确保使用以下命令将 sse.js 库安装到我们的项目中:
$ yarn add sse@https://github.com/mpetazzoni/sse.js
在文件 src/App.js 中,您已经可以找到很多默认代码。让我们清理此代码,使其仅包含我们用作起点的 App 组件的空实现:
function App() {
return (
);
}
export default App;
为了为我们的 React 应用程序激活 Chakra UI,我们需要将主要应用程序组件嵌入到
import React from 'react'
import ReactDOM from 'react-dom/client'
import { ChakraProvider } from '@chakra-ui/react'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
)
接下来打开 src/App.jsx。首先让我们在文件顶部添加一个 import 语句,它导入我们将使用的所有 Chakra UI 组件:
import { Heading, Text, Box, Flex, Button, Textarea } from "@chakra-ui/react";
Flex现在通过以下方式将 Chakra UI 的组件添加到 App 组件的返回语句来开始实现用户界面:
return (
);
此代码Flex使用 React 中的 Chakra UI 库创建一个组件。Flex 组件用于创建灵活且响应迅速的布局容器。
代码将Flex容器的宽度和高度分别设置为100vw和100vh。这意味着容器将占据视口的全部宽度和高度。
该alignContent属性设置为center,这会将内容沿容器中心的横轴(垂直)对齐。该justifyContent属性也设置为center,这会将内容沿容器中心的主轴(水平)对齐。
最后,bgGradient属性设置为linear(to-b, orange.100, purple.300)。这会将容器的背景渐变设置为线性渐变,该渐变以 color 开始orange.100并过渡到purple.300.
因此,简而言之,代码创建了一个整页容器,该容器具有居中布局和从橙色过渡到紫色的背景渐变。
在组件内部,Flex我们确实需要添加更多的 Chakra UI 元素,如下面的清单所示:
return (
React & OpenAI
With Server Sent Events (SSE)
This is a React sample web application making use of OpenAI's GPT-3
API to perform prompt completions. Results are received using Server
Sent Events (SSE) in real-time.
{result != "" && (
Result:
{result}
)}
);
此代码Box使用 React 中的 Chakra UI 库创建一个组件。组件Box用于创建布局容器。
该Box组件的属性maxW设置为"2xl"、m设置为"0 auto"和 p 设置为"20px"。这会将容器的最大宽度设置为2xl,将容器水平和垂直居中,0顶部和底部留有边距,左侧和右侧留有边距,并在容器内容周围auto添加填充。20px
然后代码创建几个Heading组件,用于显示不同大小的标题,fontSize属性分别设置为5xl、3xl和lg。第一个 Heading 组件使用该属性设置了背景渐变bgGradient,并使用该属性将文本裁剪为渐变bgClip。
还有两个Text用于显示文本的组件,分别带有fontSizeofxl和lg。使用该属性将文本与容器的中心对齐textAlign。
组件Textarea用于允许用户输入文本,属性value绑定到prompt状态,onChange属性设置到handlePromptChange函数。该placeholder属性向用户提供输入内容的提示。
两个Button组件用于用户交互,一个用于提交提示,另一个用于清除结果。onClick按钮的属性分别绑定到和handleSubmitPromptBtnClicked函数handleClearBtnClicked。提交按钮的属性isLoading用于在处理结果时显示加载状态。
最后,代码有条件地显示一个Box带有标题的组件和一个文本组件以显示 API 调用的结果。仅当结果不是空字符串时才显示结果。
简而言之,这段代码创建了一个居中的布局容器,其中包含标题、文本、文本输入区域和用于用户交互的按钮。如果 API 调用的结果不是空字符串,则会显示该结果。
在下一步中,我们需要编写与 OpenAI API 实现通信逻辑所需的代码。从我们的 React 应用程序中,我们希望将用户输入的文本发送到 HTTP POST Completion 的端点,该端点位于
https://api.openai.com/v1/completions
我们期望从这个端点接收给定提示的文本完成。我们将使用 sse.js 库通过列出服务器发送的事件来接收响应。这将允许我们在逐字生成时接收文本响应。
让我们首先向 App.jsx 添加更多导入语句:
import { useState, useRef, useEffect } from "react";
import { SSE } from "sse";
此代码从 React 库中导入三个钩子:useState、useRef和useEffect。这些钩子允许你在 React 中为你的功能组件添加状态和副作用。
此外,该代码从名为sse. SSE(Server-Sent Events)是客户端和服务器之间实时通信的标准。使用 Server-Sent Events,服务器无需客户端请求即可向客户端发送数据,这对于构建实时应用程序非常有用,例如聊天室、股票行情和其他需要推送更新的类型的应用程序服务器到客户端。
接下来,我们需要使 OpenAI API 密钥在我们的应用程序中可用。在我们基于 Vite 的 React 项目中,我们将使用项目根文件夹中的 .env.local 文件来包含保存 API 密钥的环境变量的定义:
VITE_OPENAI_API_KEY=[INSERT YOUR OPENAI API KEY HERE]
在 App.jsx 中,我们可以通过以下代码行从环境变量中检索密钥:
const API_KEY = import.meta.env.VITE_OPENAI_API_KEY;
让我们继续使用 App 组件函数定义我们的 state 和 ref 变量:
function App() {
let [prompt, setPrompt] = useState("");
let [isLoading, setIsLoading] = useState(false);
let [result, setResult] = useState("");
const resultRef = useRef();
useEffect(() => {
resultRef.current = result;
}, [result]);
...
这段代码定义了一个名为App. 该组件使用多个 React 挂钩来管理其状态和副作用。
钩子useState被使用了三次来管理组件的状态。第一次,它创建一个状态变量prompt及其更新函数setPrompt。的初始值为prompt空字符串。
第二次,它创建了一个状态变量isLoading及其更新函数setIsLoading。isLoading的初始值为false。
第三次,它创建了一个状态变量result及其更新函数setResult。的初始值为result空字符串。
该useRef钩子用于创建一个名为resultRef. Refs 是一种访问 DOM 元素属性的方法,可用于在组件的多个渲染中维护对值的引用。在这种情况下,每次更改时resultRef.current都会分配值,从而有效地使其成为一种持久保存跨渲染值的方法。resultresultresult
钩子useEffect用于在值更改时运行副作用result。副作用是用resultRef.current的新值更新result,允许它在渲染中持续存在。
最后,我们准备好实现与 OpenAI Completion 端点交互所需的逻辑,并使用 sse.js 库接收作为服务器发送事件的答案。handleSubmitPromptBtnClicked此逻辑在每次用户单击“提交提示”按钮时调用的函数中实现:
let handleSubmitPromptBtnClicked = async () => {
if (prompt !== "") {
setIsLoading(true);
setResult("");
let url = "https://api.openai.com/v1/completions";
let data = {
model: "text-davinci-003",
prompt: prompt,
temperature: 0.75,
top_p: 0.95,
max_tokens: 100,
stream: true,
n: 1,
};
let source = new SSE(url, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
method: "POST",
payload: JSON.stringify(data),
});
source.addEventListener("message", (e) => {
if (e.data != "[DONE]") {
let payload = JSON.parse(e.data);
let text = payload.choices[0].text;
if (text != "\n") {
console.log("Text: " + text);
resultRef.current = resultRef.current + text;
console.log("ResultRef.current: " + resultRef.current);
setResult(resultRef.current);
}
} else {
source.close();
}
});
source.addEventListener("readystatechange", (e) => {
if (e.readyState >= 2) {
setIsLoading(false);
}
});
source.stream();
} else {
alert("Please insert a prompt!");
}
};
该函数是一个异步箭头函数,它允许它使用await关键字来等待承诺的解决。
该函数首先检查该prompt值是否不等于空字符串。如果不是,函数继续执行。如果是,则向用户显示警告消息“请插入提示!”。
isLoading然后该函数将to的状态值true和 的状态值设置result为空字符串。
接下来,它构造一个 URL 和一个包含data要发送到 API 端点的数据的对象。
然后它创建该类的一个新实例SSE,这是 sse.js 库的类,用于处理服务器发送的事件。该类使用url、headers、method和payload选项进行实例化。
该函数向source实例添加两个事件侦听器。第一个侦听事件并使用从 API 收到的响应文本message更新 的值resultRef.current和状态值。result第二个侦听事件并在就绪状态更改为 2 或更高时设置toreadystatechange的状态值。isLoadingfalsesource
最后调用实例stream上的方法source发起API请求。
简而言之,此函数使用给定的提示向 OpenAI API 发出 API 请求,并使用响应数据相应地更新状态值和引用。由于我们的 UI 组件绑定到各自的状态变量,因此每次从 OpenAI GPT-3 语言模型接收到新数据块时,网站上的输出都会更新。
最后,我们还需要为清除按钮实现点击事件处理函数:
let handleClearBtnClicked = () => {
setPrompt("");
setResult("");
};
这段代码定义了一个 JavaScript 函数handleClearBtnClicked。该函数是一个箭头函数,是JavaScript中编写匿名函数的简写。单击清除按钮时执行该功能。
该函数在执行时做了两件事:
它调用该setPrompt函数并传递一个空字符串作为参数。是更新React 组件中setPrompt的状态值的状态更新函数。prompt
它调用该setResult函数并传递一个空字符串作为参数。是更新React 组件中setResult的状态值的状态更新函数。result
此函数的目的是清除React 组件状态中的prompt和 的值,从而重置用户界面中的输入和输出。result
最后,我们准备通过在项目文件夹中执行以下命令来启动开发 Web 服务器来测试应用程序:
$ yarn dev
命令行上的响应会告知您运行 Web 服务器的端口:
在浏览器中访问本地 URL 时,您应该能够在浏览器中看到 React 应用程序的输出:
您可以立即开始在文本输入字段中输入您的提示:
单击“提交提示”按钮将启动 OpenAI 请求,一旦从 API 接收到第一块数据,您将能够看到输出:
只要收到最后的数据块并且答案完全可用,该按钮就会指示加载状态
本指南向您展示了如何将 OpenAI 的 GPT-3 API 的强大功能、React 的简单性和性能以及服务器发送事件 (SSE) 的实时功能结合在一起,以创建真正出色的 Web 应用程序。按照分步说明,您现在已经掌握了在您自己的 React Web 应用程序中流式传输实时结果所需的知识和工具。无论您是初学者还是经验丰富的开发人员,本指南都为您提供了将 Web 应用程序开发技能提升到新水平的基础。你还在等什么?立即开始探索并将这些惊人的技术集成到您自己的项目中!