如何用OpenAI、ChatGPT、Node.js和React搭建一个AI聊天机器人

如何用OpenAI、ChatGPT、Node.js和React搭建一个AI聊天机器人

人工智能(AI)最近一直在掀起波澜,ChatGPTChat completions彻底改变了互联网。

你可以用它做很多事情:起草电子邮件或其他文章,回答关于一组文件的问题,创建对话代理,给你的软件一个自然语言界面,辅导各种科目,翻译语言,等等。本教程使用Chat completions功能建立一个AI聊天应用程序的基本知识,使每个程序员都能轻松上手。它并不像看起来那样艰难。在你跟随本教程时,你会看到这一点。

您将学到以下内容:

  • 如何只用Node.js创建一个CLI聊天应用程序。
  • 如何只用React建立一个聊天应用。
  • 如何结合React和Node.js来创建更好的聊天AI软件。

本教程将以 gpt-3.5-turbo 模型为基础。

前提条件

本教程需要JavaScript、CSS、React和Node.js的基本知识。你还需要一个OpenAI平台的账户,chatGPT就在这个平台上。它是免费的,所以你可以在这里创建一个。

如何用Node.js创建一个CLI聊天AI应用程序

本节将重点介绍创建一个只在终端使用Node.js运行的聊天应用程序。

首先,为该项目创建一个目录:

mkdir nodejs-chatgpt-tutorial

导航到该文件夹:

cd nodejs-chatgpt-tutorial

初始化该项目:

npm init -y

这将创建一个 package.json 文件来跟踪项目的细节

在该文件中添加以下一行代码:

"type": "module"

这将使你能够使用ES6模块的导入语句。用以下命令安装OpenAI

npm i openai

创建一个文件,所有的代码都在其中。命名为 index.js

touch index.js

OpenAI模块导入 ConfigurationOpenAIApi ,从 readline 模块导入readline

import { Configuration, OpenAIApi } from "openai";
import readline from "readline";

像这样建立OpenAI的配置:

const configuration = new Configuration({
organization: "org-0nmrFWw6wSm6xIJXSbx4FpTw",
apiKey: "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",
});

这段代码创建了一个 Configuration 对象的新实例。在它里面,你将输入你的 organizationapiKey 的值。你可以在设置中找到你的组织的详细信息,在API密钥中找到你的apiKey信息。如果你没有现有的API Key,你可以创建它。在配置后输入以下代码,创建一个新的OpenAI API实例:

const openai = new OpenAIApi(configuration);

你将在整个项目中使用它。

输入下面的代码来测试 createChatCompletion 函数:

openai
.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: "Hello" }],
})
.then((res) => {
console.log(res.data.choices[0].message.content);
})
.catch((e) => {
console.log(e);
});

这段代码调用 createChatCompletion 函数,触发一个端点( https://api.openai.com/v1/chat/completions )。该函数接受一个参数对象(使用中的chatGPT model 和用户与AI之间的 messages 数组。我们将在下一节中研究如何使用 messages 数组来保存聊天历史并改进应用程序)。每个消息都是一个对象,包含 role(即谁发送了该消息。如果是来自人工智能,该值可以是助理,如果是来自人类的消息,该值可以是用户)和 content(发送的信息)。最后,代码打印了来自人工智能的响应( res.data.choice[0].message.content )。用这个命令在终端运行该文件:

node index

这将在几秒钟后返回人工智能的响应。这就是创建聊天机器人的全部内容!但通过请求用户输入信息而不是将信息内容硬编码到代码中,使应用程序更具互动性将是很有帮助的。readline模块将在这方面帮助我们。要使其具有互动性,请删除你最后输入的代码,并添加以下内容:

const userInterface = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

这段代码在终端创建了一个用户界面,允许用户输入他们的问题。

接下来,用下面的代码提示用户输入一个信息:

userInterface.prompt();

最后,输入以下代码:

userInterface.on("line", async (input) => {
await openai
.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: input }],
})
.then((res) => {
console.log(res.data.choices[0].message.content);
userInterface.prompt();
})
.catch((e) => {
console.log(e);
});
});

在上面的代码中

  • 当用户输入东西并点击 Enter 时,上面的代码会触发一个回调函数。
  • 它将用户输入的任何内容作为 input
  •  input 的内容现在被用作 content
  • 在显示人工智能的响应后,在 then 块中提示用户输入另一条信息。

查看GitHub上的所有代码。运行该文件并与人工智能进行对话。它将看起来像下面的图片:

与AI的CLI聊天

与AI的CLI聊天

很好! 这是一个交互式CLI聊天。这对少数人(如工程师)很有用,但它有很好的安全性,因为它是在服务器端。但其他可能不了解如何使用CLI应用程序的人呢?他们将需要一些更容易使用的、具有更好的用户界面(UI)和用户体验(UX)的东西。下一节将重点介绍使用React构建这种应用程序。

如何使用React创建一个聊天应用程序

本节旨在帮助前端开发者快速掌握ChatGPT API,以创建一个聊天应用程序,并构建一个更好的用户界面,给用户带来更好的体验。你可以把在这里获得的知识应用于其他前端框架或库。

首先要做的是设置一个基本的React模板。我将使用Vite来实现这一目的。你可以用Vite来搭建任何现代JavaScript前端项目的脚手架。使用下面的命令:

npm create vite@latest

该命令将提示你为你的项目创建一个名称和文件夹,并选择一个框架或库(本教程使用React)。之后,你将导航到该文件夹,并运行以下命令:

npm install
npm run dev

这些命令将安装必要的依赖性,并在 5173 端口启动本地服务器,接下来,用以下命令安装OpenAI

npm i openai

这个模块提供了我们创建聊天应用程序所需的所有权限。现在我们准备开始写代码了!导航到 src/App.jsx 文件,删除其所有内容。然后添加以下导入语句:

import { useState } from "react";
import { Configuration, OpenAIApi } from "openai";

上面的代码导入了用于设置配置值的 Configuration 和用于让我们访问Chat completions的 OpenAIApi 。之后,像这样建立配置:

const configuration = new Configuration({
organization: "org-0nmrFWw6wSm6xIJXSbx4FpTw",
apiKey: "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",
});

这段代码创建了一个 Configuration 对象的新实例。在它里面,你输入你的 organization 和 apiKey 的值。你可以在设置中找到你的组织的详细信息,你的apiKey信息在API密钥中。如果你没有现有的API密钥,你可以创建它。在配置后输入以下代码,创建一个新的OpenAI API实例:

const openai = new OpenAIApi(configuration);

我们将在整个项目中使用它。创建并导出一个默认函数:

function App() {
return (
<main>
<h1>Chat AI Tutorial</h1>
<main/>
);
}
export default App;

这个函数将容纳其余的代码。在 return 语句之前设置以下状态:

  const [message, setMessage] = useState("");
const [chats, setChats] = useState([]);
const [isTyping, setIsTyping] = useState(false);
  • message 将保存从应用程序发送至人工智能的信息。
  • chats 数组将记录双方(用户和人工智能)发送的所有信息。
  • isTyping 变量将通知用户,机器人是否正在打字。

在h1标签下输入以下几行代码

      <div className={isTyping ? "" : "hide"}>
<p>
<i>{isTyping ? "Typing" : ""}</i>
</p>
</div>

上面的代码将显示 Typing ,只要用户在等待AI的响应。创建一个表单,用户可以在其中输入信息,将下面的代码添加到 main 元素中:

      <form action="" onSubmit={(e) => chat(e, message)}>
<input
type="text"
name="message"
value={message}
placeholder="Type a message here and hit Enter..."
onChange={(e) => setMessage(e.target.value)}
/>
</form>

这段代码创建了一个有一个输入的表单。每当点击 Enter 键提交表单时,就会触发 chat 函数。聊天函数将接受两(2)个参数(emessage),像这样:

const chat = async (e, message) => {
}

在该函数中输入以下几行:

    e.preventDefault();
if (!message) return;
setIsTyping(true);

上面的代码防止 form 重新加载网页,检查提交前是否输入了信息,并将 isTyping 设置为 true ,以表明应用程序已经开始处理所提供的输入。ChatGPT有一个信息的格式。它采取以下模式:

{role: user | assistant, content: message to be sent

每条信息(content)都必须显示谁发送的。当聊天是来自人工智能时,角色是 assistant,但如果是来自人类,则是 user 。因此,在发送消息之前,一定要正确地格式化它,并像这样把它添加到数组(chats)中:

    let msgs = chats;
msgs.push({ role: "user", content: message });
setChats(msgs);
setMessage("");

上面的最后一行清除了输入,以便用户输入另一个音符。现在我们将通过使用下面的代码触发 createChatCompletion 函数来调用 createChatCompletion 端点:

  await openai
.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content:
"You are a EbereGPT. You can help with graphic design tasks",
},
...chats,
],
})

createChatCompletion 函数至少需要两(2)个参数(model 和 messages):

  • 模型指定了正在使用的chatGPT的版本。
  • 消息是迄今为止用户和人工智能之间的所有消息的列表,以及一个系统消息,让人工智能了解它能提供什么样的帮助。
          {
role: "system",
content:
"You are a EbereGPT. You can help with graphic design tasks",
}

你可以把内容改成任何适合你的东西。messages 不一定要在数组中包含一个以上的对象。它可以只是一条消息。但是当它是一个数组时,它提供了一个消息历史,人工智能可以依靠它在未来给出更好的回复,而且它使用户打字更少,因为可能没有必要一直过度描述。 createChatCompletion 函数返回一个承诺。所以使用 then...catch... 块来获取响应。

      .then((res) => {
msgs.push(res.data.choices[0].message);
setChats(msgs);
setIsTyping(false);
})
.catch((error) => {
console.log(error);
});

这段代码将从人工智能返回的消息添加到聊天数组中,并将 isTyping 设置为 false ,表示人工智能已经完成了回复。你现在应该在每次发送消息时收到反馈(Typing):

聊天应用程序在人工智能即将作出反应时给予反馈

聊天应用程序在人工智能即将作出反应时给予反馈

现在是显示聊天历史给用户看的时候了。在 h1 标签下面输入以下代码:

      <section>
{chats && chats.length
? chats.map((chat, index) => (
<p key={index} className={chat.role === "user" ? "user_msg" : ""}>
<span>
<b>{chat.role.toUpperCase()}</b>
</span>
<span>:</span>
<span>{chat.content}</span>
</p>
))
: ""}
</section>

上面的代码循环浏览 chats ,并将它们一个接一个地显示给用户。它把 role 的大写字母和消息的 content 并排输出。以下是输出结果的样子:

聊天机器人在没有CSS的情况下按预期工作

聊天机器人在没有CSS的情况下按预期工作

这看起来很酷!但添加一些造型会让它看起来像WhatsAppMessenger一样吸引人。用以下内容替换 src/index.css 文件的内容:

:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
text-align: center;
position: sticky;
top: 0;
background-color: #242424;
}
main{
max-width: 500px;
margin: auto;
}
p{
background-color: darkslategray;
max-width: 70%;
padding: 15px;
border-radius: 50px;
}
p span{
margin: 5px;
}
p span:first-child{
margin-right: 0;
}
.user_msg{
text-align: right;
margin-left: 30%;
display: flex;
flex-direction: row-reverse;
}
.hide {
visibility: hidden;
display: none;
}
form{
text-align: center;
position: sticky;
bottom: 0;
}
input{
width: 100%;
height: 40px;
border: none;
padding: 10px;
font-size: 1.2rem;
}
input:focus{
outline: none;
}

并删除 src/App.css 文件中的所有样式。

你可以在GitHub上找到完整的代码。现在应用程序应该有一个新的外观:

聊天机器人如期使用CSS工作

聊天机器人如期使用CSS工作

用React和ChatGPT创建一个聊天机器人的工作就这样结束了。它并不像听起来那么困难。但像这样的前端应用最好是用于演示,而不是生产。这样创建应用程序的问题是,前端将API密钥暴露给网络攻击。

要解决这个问题,明智的做法可能是将API Key和Organisation Id保存在云端某个安全的地方并引用它,或者为你的应用程序建立一个具有更好安全性的后端。下面的部分将致力于解决这个问题。

如何结合React和Node.js来制作一个全栈式的聊天AI软件

本节现在将加入前几节的力量,建立一个更安全的应用程序,同时表现出更好的用户界面和用户体验。

我们将改进Node部分,使用服务器来暴露一个端点供前端使用,并简化前端与后台的交互,而不是直接联系OpenAI

如何设置项目

这一部分将创建项目所需的文件夹和文件。创建项目目录:

mkdir react-node-chatgpt-tutorial

导航到该文件夹:

cd react-node-chatgpt-tutorial

使用Vite安装React,并将文件夹命名为 frontend 。使用这个命令:

npm create vite@latest

之后,你将浏览到该文件夹并运行以下命令:

npm install
npm run dev

这些命令将安装必要的依赖,并在 5173 端口启动本地服务器。创建后台文件夹:

mkdir backend

现在导航到后端文件夹,用这个命令初始化项目:

npm init -y

这将创建一个 package.json 文件来跟踪项目的细节。在该文件中添加以下一行代码:

"type": "module"

这将使ES6模块导入语句的使用成为可能。用下面的命令安装OpenAI和其他依赖项:

npm i openai body-parser cors express

创建一个文件,所有的代码都在其中。命名为 index.js

touch index.js

这就完成了项目的设置。现在有两个文件夹(frontend 和 backend)。

如何搭建服务器

这一部分将着重于创建一个本地服务器,以监听 8000 端口。

首先要做的是像这样导入必要的模块:

import { Configuration, OpenAIApi } from "openai";
import express from "express";
import bodyParser from "body-parser";
import cors from "cors";

接下来,设置 express 、监听 port、用于接收输入的 body-parser 以及允许前端和后端自由通信的 cors 。使用下面的代码:

const app = express();
const port = 8000;
app.use(bodyParser.json());
app.use(cors());

最后,输入以下代码:

app.listen(port, () => {
console.log(`listening on port ${port}`);
});

这就完成了服务器的设置。当你运行 index.js 时,你应该得到以下输出:

listening on port 8000

如何创建端点

在这一部分,我们将建立一个端点,该端点将使用请求体接收来自前端的消息,并向调用者返回一个响应。开始时,我们要像前几节那样建立配置参数:

const configuration = new Configuration({
organization: "org-0nmrFWw6wSm6xIJXSbx4FpTw",
apiKey: "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",
});
const openai = new OpenAIApi(configuration);

接下来,使用下面的代码创建一个异步POST路由:

app.post("/", async (request, response) => {
});

这个端点将使用 http://localhost:8000/,在回调函数中,输入以下代码,从请求体( request.body )接收 chats 的输入:

const { chats } = request.body;

现在像我们在React部分做的那样,调用 createChatCompletion 端点:

  const result = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "You are a EbereGPT. You can help with graphic design tasks",
},
...chats,
],
});

这里的区别是,我们没有使用 then...catch... 块,而是将其分配给一个变量( result ),并使用 response.json() 返回响应,如以下代码:

  response.json({
output: result.data.choices[0].message,
});

GitHub上找到这部分的代码。以下是在Postman上测试时的输出:

来自Postman的输出

来自Postman的输出

代码的后端部分就这样结束了。下一部分将使用刚刚创建的端点( http://localhost:8000/ )连接前端和后端。

如何从前端连接到后端

这一部分把我们带到前台,在那里我们将创建一个表单。该表单将通过API端点向后端发送消息,并通过相同的媒介接收响应。导航到 frontend/src/App.jsx 文件并输入以下代码:

import { useState } from "react";
function App() {
const [message, setMessage] = useState("");
const [chats, setChats] = useState([]);
const [isTyping, setIsTyping] = useState(false);
const chat = async (e, message) => {
e.preventDefault();
if (!message) return;
setIsTyping(true);
let msgs = chats;
msgs.push({ role: "user", content: message });
setChats(msgs);
setMessage("");
alert(message);
};
return (
<main>
<h1>FullStack Chat AI Tutorial</h1>
<section>
{chats && chats.length
? chats.map((chat, index) => (
<p key={index} className={chat.role === "user" ? "user_msg" : ""}>
<span>
<b>{chat.role.toUpperCase()}</b>
</span>
<span>:</span>
<span>{chat.content}</span>
</p>
))
: ""}
</section>
<div className={isTyping ? "" : "hide"}>
<p>
<i>{isTyping ? "Typing" : ""}</i>
</p>
</div>
<form action="" onSubmit={(e) => chat(e, message)}>
<input
type="text"
name="message"
value={message}
placeholder="Type a message here and hit Enter..."
onChange={(e) => setMessage(e.target.value)}
/>
</form>
</main>
);
}
export default App;

这段代码与上一节的代码相似。但我们删除了OpenAI的配置,因为我们在本节中不再需要它们。

在这一点上,每当表单被提交时,就会弹出一个警报。这一点一会儿就会改变。在聊天函数中,去掉 alert 信息,然后输入以下内容:

fetch("http://localhost:8000/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
chats,
}),
})
.then((response) => response.json())
.then((data) => {
msgs.push(data.output);
setChats(msgs);
setIsTyping(false);
})
.catch((error) => {
console.log(error);
});

上面的代码调用了我们创建的端点,并传入 chats 数组供其处理。然后它返回一个响应,该响应被添加到 chats 中并显示在用户界面上:

样式设计前的全栈聊天UI

样式设计前的全栈聊天UI

如果你在 frontend/src/index.css 文件中添加以下样式,UI会看起来更好:

:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: 无;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
html, body{
scroll-behavior: smooth;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
text-align: center;
position: sticky;
top: 0;
background-color: #242424;
}
main{
max-width: 800px;
margin: auto;
}
p{
background-color: darkslategray;
max-width: 70%;
padding: 15px;
border-radius: 50px;
}
p span{
margin: 5px;
}
p span:first-child{
margin-right: 0;
}
.user_msg{
text-align: right;
margin-left: 30%;
display: flex;
flex-direction: row-reverse;
}
.hide {
visibility: hidden;
display: none;
}
form{
text-align: center;
position: sticky;
bottom: 0;
}
input{
width: 100%;
height: 40px;
border: none;
padding: 10px;
font-size: 1.2rem;
background-color: rgb(28, 23, 23);
}
input:focus{
outline: none;
}

并删除 frontend/src/App.css 文件中的所有样式。

这一部分的代码在GitHub上。现在,这里是最终的输出:

全栈式聊天机器人如期使用CSS工作

全栈式聊天机器人如期使用CSS工作

恭喜你完成了这个项目!全栈聊天机器人的工作更多,但它帮助我们分离了关注点,建立了一个更安全和有吸引力的应用程序,并为用户提供了更好的体验。所以,这些努力是值得的。你可以在GitHub上找到这一部分的代码。

小结

本教程希望向你展示,任何具有基本编程知识的人都可以构建人工智能驱动的软件。你学会了如何使用React和Nodejs构建一个聊天机器人,我们还讨论了每种技术的利弊。最后,我们建立了一个既实用、安全又有视觉吸引力的解决方案。读完本教程后,你现在可以探索AI的功能,如图像处理和音频互动。花点时间浏览一下文档,看看你可以如何扩展我们在这里涉及的内容。

评论留言