如何利用OpenAI自主搭建一个AI聊天机器人

人工智能(AI)最近一直在掀起波澜,ChatGPT的Chat 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模块导入 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构建这种应用程序。

      如何使用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 (
      

      Chat AI Tutorial

      ); } export default App;

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

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

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

        {isTyping ? "Typing" : ""}

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

        chat(e, message)}> setMessage(e.target.value)} />

        这段代码创建了一个有一个输入的表单。每当点击 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):

        • 模型指定了正在使用的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 标签下面输入以下代码:

          {chats && chats.length ? chats.map((chat, index) => (

          {chat.role.toUpperCase()} : {chat.content}

          )) : ""}

          上面的代码循环浏览 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保存在云端某个安全的地方并引用它,或者为你的应用程序建立一个具有更好安全性的后端。下面的部分将致力于解决这个问题。

          如何结合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的输出

          代码的后端部分就这样结束了。下一部分将使用刚刚创建的端点( 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 (
          

          FullStack Chat AI Tutorial

          {chats && chats.length ? chats.map((chat, index) => (

          {chat.role.toUpperCase()} : {chat.content}

          )) : ""}

          {isTyping ? "Typing" : ""}

          chat(e, message)}> setMessage(e.target.value)} />
          ); } 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的功能,如图像处理和音频互动。花点时间浏览一下文档,看看你可以如何扩展我们在这里涉及的内容。