人工智能(AI)最近一直在掀起波澜,ChatGPT的Chat completions彻底改变了互联网。
你可以用它做很多事情:起草电子邮件或其他文章,回答关于一组文件的问题,创建对话代理,给你的软件一个自然语言界面,辅导各种科目,翻译语言,等等。本教程使用Chat completions功能建立一个AI聊天应用程序的基本知识,使每个程序员都能轻松上手。它并不像看起来那样艰难。在你跟随本教程时,你会看到这一点。
您将学到以下内容:
本教程将以?gpt-3.5-turbo?模型为基础。
本教程需要JavaScript、CSS、React和Node.js的基本知识。你还需要一个OpenAI平台的账户,chatGPT就在这个平台上。它是免费的,所以你可以在这里创建一个。
本节将重点介绍创建一个只在终端使用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模块导入?Configuration
?和?OpenAIApi
?,从?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
?对象的新实例。在它里面,你将输入你的?organization
?和?apiKey
?的值。你可以在设置中找到你的组织的详细信息,在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聊天
很好! 这是一个交互式CLI聊天。这对少数人(如工程师)很有用,但它有很好的安全性,因为它是在服务器端。但其他可能不了解如何使用CLI应用程序的人呢?他们将需要一些更容易使用的、具有更好的用户界面(UI)和用户体验(UX)的东西。下一节将重点介绍使用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)个参数(e
?和?message
),像这样:
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
):
{
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的情况下按预期工作
这看起来很酷!但添加一些造型会让它看起来像WhatsApp或Messenger一样吸引人。用以下内容替换?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工作
用React和ChatGPT创建一个聊天机器人的工作就这样结束了。它并不像听起来那么困难。但像这样的前端应用最好是用于演示,而不是生产。这样创建应用程序的问题是,前端将API密钥暴露给网络攻击。
要解决这个问题,明智的做法可能是将API Key和Organisation Id保存在云端某个安全的地方并引用它,或者为你的应用程序建立一个具有更好安全性的后端。下面的部分将致力于解决这个问题。
本节现在将加入前几节的力量,建立一个更安全的应用程序,同时表现出更好的用户界面和用户体验。
我们将改进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的输出
代码的后端部分就这样结束了。下一部分将使用刚刚创建的端点(?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
如果你在?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工作
恭喜你完成了这个项目!全栈聊天机器人的工作更多,但它帮助我们分离了关注点,建立了一个更安全和有吸引力的应用程序,并为用户提供了更好的体验。所以,这些努力是值得的。你可以在GitHub上找到这一部分的代码。
本教程希望向你展示,任何具有基本编程知识的人都可以构建人工智能驱动的软件。你学会了如何使用React和Nodejs构建一个聊天机器人,我们还讨论了每种技术的利弊。最后,我们建立了一个既实用、安全又有视觉吸引力的解决方案。读完本教程后,你现在可以探索AI的功能,如图像处理和音频互动。花点时间浏览一下文档,看看你可以如何扩展我们在这里涉及的内容。