随着聊天机器人和虚拟助手的使用不断增加,许多企业和开发人员正在寻找创建自己的人工智能驱动的聊天机器人的方法。ChatGPT就是这样一个聊天机器人,它由OpenAI创建,能够进行类似人类的对话,并回答各种问题。
要建造什么?
在本教程中,你将学习如何使用React和OpenAI API构建一个ChatGPT克隆应用程序。如果你想在周末尝试做一个有趣的、有吸引力的项目,这是一个深入了解React和OpenAI的好机会。
你还将学习如何从你的GitHub仓库直接部署到应用托管平台。下面是ChatGPT克隆应用程序的Demo演示。
如果你想更仔细地检查这个项目,你可以访问其GitHub仓库。
另外,你也可以克隆React应用启动项目,它带有基本元素,如样式、Font Awesome CDN链接、OpenAI包和基本结构,以帮助你开始工作。
要求/前提条件如下:
本教程被设计成一种 “跟随” 的体验。因此,建议你具备以下条件,以便轻松地进行编码:
- 对HTML、CSS和JavaScript有基本的了解
- 对React有一定的了解
- 在你的电脑上安装Node.js和npm或yarn
本文将从OpenAI API简述,及为何选取React进行开发及具体的开发实践、服务器部署等多个方面,进行非常详尽的ChatGPT克隆开发说明。
目录
你要建造什么?
要求/前提条件如下:
什么是OpenAI API?
为什么是React?
如何用React和OpenAI API建立ChatGPT克隆版
设置ChatGPT克隆应用程序
添加功能和整合OpenAI API
如何将你的React应用程序部署到服务器上
推送你的代码到GitHub
将你的ChatGPT克隆应用部署到服务器上
小结
什么是OpenAI API?
OpenAI API是一个基于云的平台,授予开发者通过API访问OpenAI的语言模型,如GPT-3。它允许开发者将自然语言处理功能,如文本补全、情感分析、总结和翻译添加到他们的应用程序中,而无需开发和训练他们的模型。
要使用OpenAI的API,开发者必须在OpenAI网站上创建一个账户并获得一个API密钥。API密钥用于验证API请求和跟踪使用情况。
一旦获得了API密钥,开发者就可以使用API向语言模型提交文本并接收响应。
为什么是React?
React是一个用于构建用户界面的流行JavaScript库。根据2022年Stack Overflow的开发者调查,它是第二大最常用的网络技术,拥有42.62%的市场份额。
React允许开发者创建代表用户界面不同部分的声明性组件。这些组件是用一种叫做JSX的语法定义的,它是JavaScript和HTML的结合。
由于其庞大的组件库和工具包的生态系统,开发人员可以轻松地与OpenAI API等API合作和集成,以建立复杂的聊天界面,这也是它成为构建ChatGPT克隆应用程序的最佳选择。
那么,我们应如何设置你的React开发环境?具体如下:
安装React或创建React项目的最好方法是用create-react-app来安装它。一个先决条件是在你的机器上安装Node.js。为了确认你已经安装了Node,在终端运行以下命令。
node -v
如果它带出了一个版本,那么它就存在。要使用npx,你需要确保你的Node版本不低于v14.0.0,你的NPM版本不低于v5.6;否则,你可能需要通过运行 npm update -g
来更新它。一旦你了解了npm,你现在可以通过运行下面的命令来建立一个React项目:
npx create-react-app chatgpt-clone
注意:”chatgpt-clone” 是我们正在创建的应用程序名称,但你可以把它改成你选择的任何名称。
安装过程可能需要几分钟的时间。一旦成功,你可以导航到该目录并安装Node.js OpenAI包,它提供了从Node.js访问OpenAI API的便利,使用下面的命令:
npm install openai
现在你可以运行 npm start
,看到你的应用程序在localhost:3000上运行。
当使用 create-react-app
命令创建一个React项目时,它会自动构建一个文件夹结构。与你有关的主要文件夹是 src 文件夹,它是进行开发的地方。这个文件夹默认包含许多文件,但你应该只关注App.js、index.js和index.css文件。
- App.js:App.js文件是React应用程序的主要组件。它通常代表顶层组件,渲染应用程序中的所有其他组件。
- index.js:这个文件是你的React应用程序的入口点。它是应用程序打开时加载的第一个文件,负责将App.js组件渲染到浏览器上。
- index.css:这个文件负责定义你的React应用程序的整体风格和布局。
如何用React和OpenAI API建立ChatGPT克隆版
ChatGPT克隆应用程序将由两个组件组成,使应用程序更容易理解和维护。这两个组件是:
- 表单部分:这个组件包括一个文本区域字段和一个按钮,供用户与聊天机器人互动。
- 回答部分:问题和相应的答案将被存储在一个数组中,并显示在这个部分。你将按时间顺序循环浏览该数组,先显示最新的。
设置ChatGPT克隆应用程序
在本教程中,让我们首先建立应用程序的接口,然后你可以实现功能,使你的应用程序与OpenAI API进行交互。首先创建你将在本教程中使用的两个组件。为了适当的组织,你将在src文件夹中创建一个components文件夹,所有的组件都将存放在这里。
表单部分组件
这是一个简单的表单,由一个 textarea
和一个提交 button
组成。
// components/FormSection.jsxconst FormSection = () => {return (<div className="form-section"><textarearows="5"className="form-control"placeholder="Ask me anything..."></textarea><button className="btn">Generate Response 🤖</button></div>)}export default FormSection;
当你把它导入你的App.js文件时,这个表单应该是这个样子的:
Info:本教程的重点在于构建和部署你的应用程序。所以你可以将src/index.css文件中的样式复制到你自己的项目中,以获得相同的结果/应用。
回答部分组件
这个部分是显示所有问题和答案的地方。当你把它导入你的App.js文件时,这个部分将是这样的。
你将从一个数组和循环中获取这些问题和答案,使你的代码更容易阅读和维护。
// components/AnswerSection.jsx
const AnswerSection = () => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
<div className="answer-section">
<p className="question">Who is the founder of OpenAi?</p>
<p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
</div>
</>
)
}
export default AnswerSection;
主页
现在你已经创建了这两个组件,但当你运行你的应用程序时,什么也不会出现,因为你需要将它们导入你的App.js文件。对于这个应用程序,你将不实现任何形式的路由,这意味着App.js文件将作为你的应用程序的主页组件/页面。
你可以在导入组件之前添加一些内容,比如你的应用程序的标题和描述。
// App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any queries
you may have, and I will do my utmost to offer you a reliable
response. Kindly keep in mind that I am a machine and operate solely
based on programmed algorithms.
</p>
</div>
<FormSection />
<AnswerSection />
</div>
);
};
export default App;
在上面的代码中,这两个组件被导入并添加到应用程序中。当你运行你的应用程序时,你的应用程序将是这个样子:
添加功能和整合OpenAI API
你现在有了你的应用程序的用户界面。下一步是使应用程序发挥作用,以便它能与OpenAI API互动并获得响应。首先,你需要从你的表单中获取提交时的值,因为它将被用来查询OpenAI API。
从表单中获取数据
在React中,存储和更新数据的最佳方式是使用状态。在功能组件中,useState()
钩子是用来处理状态的。你可以创建一个状态,将表单中的值分配给该状态,并在其值发生变化时更新它。让我们先把 useState()
钩子导入FormSection.jsx组件,然后创建一个状态来存储和更新 newQuestions
。
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
// Form to submit a new question
)
}
export default FormSection;
接下来,你可以把 textarea
的值分配给状态,并创建一个 onChange()
事件,在输入值发生变化时更新状态:
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>
最后,你可以创建一个 onClick()
事件,在提交按钮被点击时加载一个函数。这个方法将在App.js文件中创建,并作为props传入FormSection.jsx组件中,其参数为 newQuestion
和 setNewQuestion
值。
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>
你现在已经创建了一个状态来存储和更新表单的值,添加了一个方法,该方法作为道具从App.js文件中传递,并处理了点击事件。这就是最终代码的模样:
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
<div className="form-section">
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>
</div>
)
}
export default FormSection;
下一步将是在App.js文件中创建一个方法来处理与OpenAI API互动的整个过程。
与OpenAI API交互
要与OpenAI API互动并在React应用程序中获得API密钥,你必须创建一个OpenAI API账户。你可以使用你的谷歌账户或电子邮件在OpenAI网站上注册一个账户。要生成API密钥,点击网站右上角的Personal;会出现一些选项;点击View API keys。
点击Create new secret key按钮,将密匙复制到某个地方,因为你会在这个应用程序中使用它来与OpenAI进行交互。现在你可以通过导入openai包(你已经安装了)和配置方法来初始化OpenAI。然后用你生成的密钥创建一个配置,用它来初始化OpenAI。
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
return (
// Render FormSection and AnswerSection
);
};
export default App;
在上面的代码中,OpenAI的API密钥被存储为.env文件中的一个环境变量。你可以在你的应用程序的根目录下创建一个.env文件,并将密钥存储到变量 REACT_APP_OPENAI_API_KEY
。
// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…
现在你可以继续在App.js文件中创建 generateResponse
方法,并传入你已经创建的表单中预期的两个参数,以处理请求并从API获得响应。
// src/App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const generateResponse = (newQuestion, setNewQuestion) => {
// Set up OpenAI API and handle response
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
你现在可以向OpenAI API发送请求。OpenAI API可以执行许多操作,如问答(Q&A)、语法纠正、翻译等等。对于这些操作中的每一项,其选项都是不同的。例如,问答的引擎值是 text-davinci-00
,而SQL翻译的引擎值是 code-davinci-002
。请随时查看OpenAI的例子文档,了解各种例子和它们的选项。
在本教程中,我们只使用Q&A,这是选项的样子:
{
model: "text-davinci-003",
prompt: "Who is Obama?",
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ["\"],
}
Note: 上面代码改变了prompt值。
Prompt是由表单发送的问题。这意味着你需要从你作为参数传入 generateResponse
方法的表单输入中接收它。要做到这一点,你将定义选项,然后使用传播操作符来创建一个完整的选项,其中包括prompt:
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
在这一点上,剩下的就是通过 createCompletion
方法向OpenAI发送一个请求,以获得响应。
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
console.log(response.data.choices[0].text);
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
在上面的代码中,答案的文字将显示在你的控制台。请自由地通过提出任何问题来测试你的应用程序。最后一步是创建一个保存问题和答案数组的状态,然后将这个数组作为一个道具发送到AnswerSection组件。这就是App.js的最终代码的样子:
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
if (response.data.choices) {
setStoredValues([
{
question: newQuestion,
answer: response.data.choices[0].text,
},
...storedValues,
]);
setNewQuestion('');
}
};
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any
queries you may have, and I will do my utmost to offer you a
reliable response. Kindly keep in mind that I am a machine and
operate solely based on programmed algorithms.
</p>
</div>
<FormSection generateResponse={generateResponse} />
<AnswerSection storedValues={storedValues} />
</div>
);
};
export default App;
现在你可以编辑AnswerSection组件,让它从App.js接收props值,并使用JavaScript Map()
方法查看 storedValues
数组:
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;
当你运行你的应用程序并通过提问来测试它时,答案会显示在下面。但是你会注意到复制按钮没有工作。你需要给按钮添加一个 onClick()
事件,这样它就会触发一个方法来处理这个功能。你可以使用 navigator.clipboard.writeText()
方法来处理这个功能。这就是AnswerSection组件现在的样子:
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
const copyText = (text) => {
navigator.clipboard.writeText(text);
};
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div
className="copy-icon"
onClick={() => copyText(value.answer)}
>
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;
当你运行你的应用程序时,你的ChatGPT克隆应用程序将完美运行。你现在可以部署你的应用程序,在线访问它,并与朋友分享。
如何将你的React应用程序部署到服务器上
仅仅建立这个应用程序并把它留在你的本地计算机上是不够的。你要在网上分享它,这样别人就可以访问它。让我们看看如何使用GitHub和Kinsta来做这件事。
推送你的代码到GitHub
要推送代码到GitHub,可以使用Git命令,这是一种可靠而有效的方式来管理代码变更,进行项目协作,并维护版本历史。
推送代码的第一步是创建一个新的仓库,登录你的GitHub账户,点击屏幕右上角的+按钮,从下拉菜单中选择New repository。
给你的资源库起个名字,添加描述(可选),并选择你希望它是公开的还是私有的。点击Create repository来创建它。
一旦你的仓库被创建,确保你从仓库的主页上获得仓库的 URL,你将需要它来推送你的代码到 GitHub。
打开你的终端或命令提示符,导航到包含你的项目的目录。逐一运行下面的命令,将你的代码推送到GitHub仓库:
git init
git add .
git commit -m "my first commit"
git remote add origin [repository URL]
git push -u origin master
git init
初始化本地的 Git 仓库,git add .
将当前目录及其子目录下的所有文件添加到新的 Git 仓库。git commit -m "my first commit"
将修改提交到仓库,并附上简短的信息。git remote add origin [repository URL]
将仓库的 URL 设置为远程仓库, git push -u origin master
将代码推送到远程仓库(origin)的主分支。
提示:你可以把 “my first commit” 换成你自己的简短信息,描述你所做的修改,把”[repository URL]”换成你的 GitHub 仓库的 URL。一旦你的代码被推送到GitHub,你就可以把你的仓库部署到服务器了。
将你的ChatGPT克隆应用部署到服务器上
要将你的版本库部署到服务器(以Kinsta为例),请遵循以下步骤:
- 在 “My Kinsta” 仪表板上登录或创建您的Kinsta账户。
- 点击左侧边栏的Applications,然后点击Add service。
- 从下拉菜单中选择Application,将React应用部署到Kinsta。
- 在出现的模式中选择你想部署的仓库。如果你有多个分支,你可以选择一个你想部署的分支,并为应用程序指定一个名称。在25个可用的data center location中选择一个,Kinsta会自动检测一个启动命令。
- 最后,向GitHub这样的公共主机推送API密钥并不安全,它是作为environment variable添加到本地的。在托管时,你也可以使用相同的变量名和密钥作为其值将其添加为环境变量。
你的应用程序将开始部署,在几分钟内,将提供一个链接来访问你的应用程序的部署版本。在这种情况下,这是https://chatgpt-clone-g9q10.kinsta.app/
Note:你可以启用自动部署,这样Kinsta会在你改变代码库并推送到GitHub时重新部署你的应用程序。
小结
OpenAI API可用于构建广泛的潜在应用,从客户支持和个人助理到语言翻译和内容创建。
在本教程中,你已经学会了如何用React和OpenAI构建一个ChatGPT克隆应用。你可以将这个应用/功能整合到其他应用中,为用户提供类似人类的对话体验。
用OpenAI API可以做的事情还有很多,以及如何改进这个克隆应用。例如,你可以实现本地存储,这样即使你刷新浏览器,以前的问题和答案也不会消失。
有了Kinsta的免费试用和兴趣层,你可以很容易地开始使用我们的应用托管,而不需要任何费用。那么为什么不试一试,看看你能创造什么呢?