所有文章 > API使用场景 > 如何使用Spring AI、React和Docker构建AI聊天机器人
如何使用Spring AI、React和Docker构建AI聊天机器人

如何使用Spring AI、React和Docker构建AI聊天机器人

嘿,Java开发者们,我有个好消息:Spring 现在正式支持使用 Spring AI 模块构建 AI 应用程序。

在本教程中,我们将使用 Spring BootReactDocker 和 OpenAI 构建一个聊天机器人应用程序。此应用程序将允许用户与 AI 驱动的聊天机器人互动、提出问题并实时接收回复。

本文中提到的整个源代码已经在 GitHub 存储库中提供。

为了让你对我们将要构建的内容有个概念,最终应用程序将如下所示:

使用 Spring AI、React 和 Docker 的聊天机器人应用程序 UI,作者:Vikas Rajput

你兴奋吗?让我们从头开始构建它!

先决条件

在开始构建聊天机器人之前,你需要了解一些基础知识:

  1. 对 Java 和 Spring Boot 有基本的了解。
  2. 对 React 和 CSS 有基本的了解。
  3. 将 JDK、Node Package Manager 和 Docker 安装到您的计算机上。

获取您的 OpenAI 密钥

首先,如果您没有 OpenAI 帐户,则需要注册一个 OpenAI 帐户。登录后,您将被带到主页。

在右上角,单击 “Dashboard” 菜单。在侧边栏上,单击“API Keys”,然后单击“Create new secret key”按钮以生成您的密钥:

如何生成您的 OpenAI 密钥

复制密钥并将其保存在安全的地方,因为您稍后需要它来将您的应用程序连接到 OpenAI API

您可以浏览 OpenAI API 参考指南,了解更多关于如何调用API、它接受哪些请求以及它给出的响应的更多信息。

在 Spring Boot 中构建 REST API

让我们转到 spring initializer 以生成样板代码:

使用 spring 初始化器构建 Spring AI 应用程序

您可以提供您选择的组、构件、名称、描述和包。我们使用 Maven 作为构建工具,使用 Spring Boot 版本 3.3.3,使用 Jar 作为打包选项,并使用 Java 版本 17。

点击生成按钮,将下载 zip。解压缩文件并将它们作为 Maven 项目导入到您最喜欢的 IDE 中(我的是 Intellij)。

在 Spring 中配置您的 OpenAI 密钥

你可以使用现有的application.properties文件或创建一个application.yaml文件。我喜欢使用 Yaml,所以我创建了一个application.yaml文件,我可以在其中放置我所有的 Spring Boot 配置。

将OpenAIKey、Model和Temperature添加到你的application.yaml文件中:

spring:
ai:
openai:
chat:
options:
model: "gpt-3.5-turbo"
temperature: "0.7"
key: "PUT YOUR OPEN_API_KEY HERE"


在application.properties中的类似配置可能如下所示:

spring.ai.openai.chat.options.model=gpt-3.5-turbo
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.key="PUT YOUR OPEN_API_KEY HERE"

构建 ChatController

让我们创建一个带有URL /ai/chat/string的GET API和一个处理逻辑的方法:

@RestController
public class ChatController {

@Autowired
private final OpenAiChatModel chatModel;

@GetMapping("/ai/chat/string")
public Flux<String> generateString(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
return chatModel.stream(message);
}
}
  • 首先,我们在ChatController类上添加@RestController注解以将其标记为我们Spring控制器。
  • 然后,我们注入了OpenAiChatModel类的依赖项。然后,我们注入了OpenAiChatModel类的依赖项。它作为Spring AI依赖项的一部分可以立即使用。
  • OpenAiChatModel类有一个stream(message)方法,该方法接受提示作为字符串并返回一个字符串响应(技术上讲,它是一个Flux,因为我们使用了相同的方法的响应式版本)。
  • 在内部,OpenAiChatModel.stream(message)将调用OpenAI API并从那里获取响应。OpenAI调用将使用你在application.yaml文件中提到的配置文件,因此请确保使用有效的OpenAI密钥。
  • 我们已经创建了一个方法来处理GET API调用,该方法接受消息并返回Flux作为响应。

构建、运行和测试 REST API

使用 maven 命令构建并运行 Spring Boot 应用程序:

./mvnw clean install spring-boot:run

理想情况下,它会在8080端口上运行,除非你已自定义端口。确保该端口空闲以便成功运行应用程序。

你可以使用Postman或Curl命令来测试你的REST API:

curl --location 'http://localhost:8080/ai/chat/string?message=How%20are%20you%3F'

使用 React.js 构建 ChatUI

为了本教程,我们将使它非常简单和容易,所以请原谅我没有遵循任何React的最佳实践。

创建App.js来管理ChatUI表单

我们将使用useState来管理状态:

const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
  • messages:它将存储聊天中的所有消息。每条消息都有文本内容和发送者(要么是’user’(用户),要么是’ai’(人工智能))。
  • input:用于存储用户在文本框中输入的内容。
  • loading:当聊天机器人正在等待AI的响应时,此状态设置为true,收到响应后设置为false。

创建handleSend函数:当用户点击按钮或按下Enter键发送消息时调用此函数。

const handleSend = async () => {
if (input.trim() === '') return;

const newMessage = { text: input, sender: 'user' };
setMessages([...messages, newMessage]);
setInput('');
setLoading(true);

try {
const response = await axios.get('http://localhost:8080/ai/chat/string?message=' + input);
const aiMessage = { text: response.data, sender: 'ai' };
setMessages([...messages, newMessage, aiMessage]);
} catch (error) {
console.error("Error fetching AI response", error);
} finally {
setLoading(false);
}
};

以下是逐步发生的事情:

  • 检查空输入:如果输入字段为空,则函数会提前返回(不发送任何内容)。
  • 用户发送新消息:一条新消息会被添加到消息数组中。这条消息包含用户输入的文本,并被标记为由’user’(用户)发送。
  • 重置输入:发送消息后,输入字段将被清除。
  • 开始加载:在等待AI响应的过程中,加载状态被设置为true,以显示加载指示器。
  • 发起API请求:代码使用axios来请求AI聊天机器人API,并传递用户的消息。当收到响应时,AI的一条新消息会被添加到聊天中。
  • 错误处理:如果获取AI响应时出现问题,则会在控制台记录一个错误。
  • 停止加载:最后,加载状态被关闭。

现在,我们来编写一个函数,以便用户在输入字段中输入内容时更新输入状态:

const handleInputChange = (e) => {
setInput(e.target.value);
};

这个函数会监听输入字段的变化,并将新的输入值存储到状态中,以便后续使用。每当用户在输入框中输入或删除字符时,这个函数都会被调用。

const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleSend();
}
};

现在让我们创建 UI 元素来呈现聊天消息:

{messages.map((message, index) => (
<div key={index} className={`message-container ${message.sender}`}>
<img
src={message.sender === 'user' ? 'user-icon.png' : 'ai-assistant.png'}
alt={`${message.sender} avatar`}
className="avatar"
/>
<div className={`message ${message.sender}`}>
{message.text}
</div>
</div>
))}

此区块呈现聊天中的所有消息:

  • 通过消息映射:使用.map()方法遍历消息数组,将每条消息以div的形式显示出来。
  • 消息样式:根据发送者(用户或AI)的不同,为消息设置不同的类名,从而清晰地表明消息的发送者。
  • 头像图像:每条消息都显示一个小头像,用户和AI的头像图片不同。

接下来,让我们创建一些逻辑,根据一个标志(flag)来显示加载器:

{loading && (
<div className="message-container ai">
<img src="ai-assistant.png" alt="AI avatar" className="avatar" />
<div className="message ai">...</div>
</div>
)}

当AI正在思考(即加载状态为true时),我们显示一个加载消息(例如“…”),以便用户知道响应很快就会到来。...

最后,创建一个按钮来触发发送消息的操作:

<button onClick={handleSend}>
<FaPaperPlane />
</button>

这个按钮在被点击时会触发handleSend()函数。这里使用的图标是一张纸飞机,它是“发送”按钮的常见图标。

完整的Chatbot.js文件如下所示:

import React, { useState } from 'react';
import axios from 'axios';
import { FaPaperPlane } from 'react-icons/fa';
import './Chatbot.css';

const Chatbot = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);

const handleSend = async () => {
if (input.trim() === '') return;

const newMessage = { text: input, sender: 'user' };
setMessages([...messages, newMessage]);
setInput('');
setLoading(true);

try {
const response = await axios.get('http://localhost:8080/ai/chat/string?message=' + input);
const aiMessage = { text: response.data, sender: 'ai' };
setMessages([...messages, newMessage, aiMessage]);
} catch (error) {
console.error("Error fetching AI response", error);
} finally {
setLoading(false);
}
};

const handleInputChange = (e) => {
setInput(e.target.value);
};

const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleSend();
}
};

return (
<div className="chatbot-container">
<div className="chat-header">
<img src="ChatBot.png" alt="Chatbot Logo" className="chat-logo" />
<div className="breadcrumb">Home &gt; Chat</div>
</div>
<div className="chatbox">
{messages.map((message, index) => (
<div key={index} className={`message-container ${message.sender}`}>
<img
src={message.sender === 'user' ? 'user-icon.png' : 'ai-assistant.png'}
alt={`${message.sender} avatar`}
className="avatar"
/>
<div className={`message ${message.sender}`}>
{message.text}
</div>
</div>
))}
{loading && (
<div className="message-container ai">
<img src="ai-assistant.png" alt="AI avatar" className="avatar" />
<div className="message ai">...</div>
</div>
)}
</div>
<div className="input-container">
<input
type="text"
value={input}
onChange={handleInputChange}
onKeyPress={handleKeyPress}
placeholder="Type your message..."
/>
<button onClick={handleSend}>
<FaPaperPlane />
</button>
</div>
</div>
);
};

export default Chatbot;

App.js中使用<Chatbot/>来加载聊天机器人用户界面:

function App() {
return (
<div className="App">
<Chatbot />
</div>
);
}

除此之外,我们还使用CSS来让我们的聊天机器人看起来更美观一些。您可以参考App.cssChatbot.css文件。

运行前端

使用npm命令来运行应用程序:

npm start

这应该在http://localhost:3000上运行前端。现在,应用程序已经准备好进行测试了。

但是分别运行后端和前端有点麻烦。所以,让我们使用Docker来让整个构建过程变得更简单。

如何 Docker 化应用程序

让我们将整个应用程序Docker化,以便能够轻松地将其打包并部署到任何地方。您可以从Docker官方网站安装和配置Docker。

Docker 化后端

我们的聊天机器人的后端是用Spring Boot构建的,因此我们将创建一个Dockerfile,它将Spring Boot应用程序构建成一个可执行的JAR文件,并在容器中运行它。

让我们来编写它的Dockerfile:

# Start with an official image that has Java installed
FROM openjdk:17-jdk-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy the Maven/Gradle build file and source code into the container
COPY target/chatbot-backend.jar /app/chatbot-backend.jar

# Expose the application’s port
EXPOSE 8080

# Command to run the Spring Boot app
CMD ["java", "-jar", "chatbot-backend.jar"]
  • FROM openjdk:17-jdk-alpine:这指定容器应基于包含 JDK 17 的轻量级 Alpine Linux 映像,这是运行 Spring Boot 所必需的。
  • WORKDIR /app:这行设置了容器内部的工作目录为/app,我们的应用程序文件将存放在这里。
  • COPY target/chatbot-backend.jar /app/chatbot-backend.jar:这行将构建好的JAR文件从本地机器(通常在使用Maven或Gradle构建项目后的target文件夹中)复制到容器中。
  • EXPOSE 8080:这行告诉Docker应用程序将在8080端口监听请求。
  • CMD ["java", "-jar", "chatbot-backend.jar"]:这行指定了容器启动时将运行的命令。它运行启动Spring Boot应用程序的JAR文件。

Docker 化前端

我们的聊天机器人的前端是使用React构建的,我们可以通过创建一个Dockerfile来将其Docker化,这个Dockerfile将安装必要的依赖项,构建应用程序,并使用像NGINX这样的轻量级Web服务器来提供服务。

让我们来编写React前端的Dockerfile:

# Use a Node image to build the React app
FROM node:16-alpine AS build

# Set the working directory inside the container
WORKDIR /app

# Copy the package.json and install the dependencies
COPY package.json package-lock.json ./
RUN npm install

# Copy the rest of the application code and build it
COPY . .
RUN npm run build

# Use a lightweight NGINX server to serve the built app
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html

# Expose port 80 for the web traffic
EXPOSE 80

# Start NGINX
CMD ["nginx", "-g", "daemon off;"]
  • FROM node:16-alpine AS build:这行指定了使用轻量级的Node.js镜像(版本16,基于Alpine Linux)来构建React应用。在这个容器中,我们将安装所有依赖并构建应用。
  • WORKDIR /app:这行设置了容器内部的工作目录为/app
  • COPY package.json package-lock.json ./:这行将package.jsonpackage-lock.json文件复制到容器中,以便安装依赖。
  • RUN npm install:这行在容器中运行npm install命令,安装package.json中列出的依赖。
  • COPY . .:这行将前端源代码的所有文件复制到容器中。
  • RUN npm run build:这行在容器中运行npm run build命令,构建React应用。构建后的文件将位于build文件夹中。
  • FROM nginx:alpine:在应用构建完成后,这行指定了基于nginx Web服务器的轻量级Alpine Linux镜像来启动一个新的容器。
  • COPY --from=build /app/build /usr/share/nginx/html:这行将第一个容器中构建的React应用复制到nginx容器中,并将其放置在nginx默认的服务文件夹中。
  • EXPOSE 80:这行将公开端口 80,NGINX 使用它来提供 Web 流量。
  • CMD ["nginx", "-g", "daemon off;"]:这行以前台模式启动nginx服务器,以提供React应用的服务。

Docker Compose 来运行两者

现在我们已经分别为前端和后端创建了Dockerfile,接下来我们将使用docker-compose来协调同时运行这两个容器。

让我们在项目根目录下编写docker-compose.yml文件:

version: '3'
services:
backend:
build: ./backend
ports:
- "8080:8080"
networks:
- chatbot-network

frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- backend
networks:
- chatbot-network

networks:
chatbot-network:
driver: bridge
  • version: '3':这行定义了所使用的Docker Compose的版本。
  • services::这行开始定义了想要运行的服务。
    • backend:这个服务使用位于./backend目录的Dockerfile来构建后端,并暴露8080端口。
    • frontend:这个服务使用位于./frontend目录的Dockerfile来构建前端。它将主机的3000端口映射到容器内的80端口
  • depends_on::这行确保前端服务在启动之前等待后端服务准备就绪。
  • networks::这个部分定义了一个共享网络,以便后端和前端可以相互通信。

运行应用程序

要运行整个应用程序(前端和后端),您可以使用以下命令:

docker-compose up --build

此命令将:

  • 构建前端和后端映像。
  • 启动两个容器(后端在8080端口,前端通常映射到主机的3000端口,但由Nginx在容器内80端口提供服务)。
  • 设置网络,以便两个服务可以相互通信。

现在,你可以访问 http://localhost:3000来加载聊天机器人的用户界面,并开始向AI提问。

祝贺 🎉

您已成功使用 Spring Boot、React、Docker 和 OpenAI 构建了一个全栈聊天机器人应用程序。

原文链接:https://www.freecodecamp.org/news/ai-chatbot-with-spring-react-docker/

#你可能也喜欢这些API文章!