
掌握ChatGPT插件與自定義GPT
你興奮嗎?讓我們從頭開始構(gòu)建它!
在開始構(gòu)建聊天機(jī)器人之前,你需要了解一些基礎(chǔ)知識:
首先,如果您沒有 OpenAI 帳戶,則需要注冊一個(gè) OpenAI 帳戶。登錄后,您將被帶到主頁。
在右上角,單擊 “Dashboard” 菜單。在側(cè)邊欄上,單擊“API Keys”,然后單擊“Create new secret key”按鈕以生成您的密鑰:
復(fù)制密鑰并將其保存在安全的地方,因?yàn)槟院笮枰鼇韺⒛膽?yīng)用程序連接到 OpenAI API。
您可以瀏覽 OpenAI API 參考指南,了解更多關(guān)于如何調(diào)用API、它接受哪些請求以及它給出的響應(yīng)的更多信息。
讓我們轉(zhuǎn)到 spring initializer 以生成樣板代碼:
您可以提供您選擇的組、構(gòu)件、名稱、描述和包。我們使用 Maven 作為構(gòu)建工具,使用 Spring Boot 版本 3.3.3,使用 Jar 作為打包選項(xiàng),并使用 Java 版本 17。
點(diǎn)擊生成按鈕,將下載 zip。解壓縮文件并將它們作為 Maven 項(xiàng)目導(dǎo)入到您最喜歡的 IDE 中(我的是 Intellij)。
你可以使用現(xiàn)有的application.properties文件或創(chuàng)建一個(gè)application.yaml文件。我喜歡使用 Yaml,所以我創(chuàng)建了一個(gè)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"
讓我們創(chuàng)建一個(gè)帶有URL /ai/chat/string的GET API和一個(gè)處理邏輯的方法:
@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);
}
}
使用 maven 命令構(gòu)建并運(yùn)行 Spring Boot 應(yīng)用程序:
./mvnw clean install spring-boot:run
理想情況下,它會在8080端口上運(yùn)行,除非你已自定義端口。確保該端口空閑以便成功運(yùn)行應(yīng)用程序。
你可以使用Postman或Curl命令來測試你的REST API:
curl --location 'http://localhost:8080/ai/chat/string?message=How%20are%20you%3F'
為了本教程,我們將使它非常簡單和容易,所以請?jiān)徫覜]有遵循任何React的最佳實(shí)踐。
我們將使用useState來管理狀態(tài):
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
messages
:它將存儲聊天中的所有消息。每條消息都有文本內(nèi)容和發(fā)送者(要么是’user’(用戶),要么是’ai’(人工智能))。input
:用于存儲用戶在文本框中輸入的內(nèi)容。loading
:當(dāng)聊天機(jī)器人正在等待AI的響應(yīng)時(shí),此狀態(tài)設(shè)置為true,收到響應(yīng)后設(shè)置為false。創(chuàng)建handleSend函數(shù):當(dāng)用戶點(diǎn)擊按鈕或按下Enter鍵發(fā)送消息時(shí)調(diào)用此函數(shù)。
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);
}
};
以下是逐步發(fā)生的事情:
現(xiàn)在,我們來編寫一個(gè)函數(shù),以便用戶在輸入字段中輸入內(nèi)容時(shí)更新輸入狀態(tài):
const handleInputChange = (e) => {
setInput(e.target.value);
};
這個(gè)函數(shù)會監(jiān)聽輸入字段的變化,并將新的輸入值存儲到狀態(tài)中,以便后續(xù)使用。每當(dāng)用戶在輸入框中輸入或刪除字符時(shí),這個(gè)函數(shù)都會被調(diào)用。
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleSend();
}
};
現(xiàn)在讓我們創(chuàng)建 UI 元素來呈現(xiàn)聊天消息:
{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>
))}
此區(qū)塊呈現(xiàn)聊天中的所有消息:
.map()
方法遍歷消息數(shù)組,將每條消息以div
的形式顯示出來。接下來,讓我們創(chuàng)建一些邏輯,根據(jù)一個(gè)標(biāo)志(flag)來顯示加載器:
{loading && (
<div className="message-container ai">
<img src="ai-assistant.png" alt="AI avatar" className="avatar" />
<div className="message ai">...</div>
</div>
)}
當(dāng)AI正在思考(即加載狀態(tài)為true時(shí)),我們顯示一個(gè)加載消息(例如“…”),以便用戶知道響應(yīng)很快就會到來。...
最后,創(chuàng)建一個(gè)按鈕來觸發(fā)發(fā)送消息的操作:
<button onClick={handleSend}>
<FaPaperPlane />
</button>
這個(gè)按鈕在被點(diǎn)擊時(shí)會觸發(fā)handleSend()
函數(shù)。這里使用的圖標(biāo)是一張紙飛機(jī),它是“發(fā)送”按鈕的常見圖標(biāo)。
完整的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 > 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/>
來加載聊天機(jī)器人用戶界面:
function App() {
return (
<div className="App">
<Chatbot />
</div>
);
}
除此之外,我們還使用CSS來讓我們的聊天機(jī)器人看起來更美觀一些。您可以參考App.css
和Chatbot.css
文件。
使用npm命令來運(yùn)行應(yīng)用程序:
npm start
這應(yīng)該在http://localhost:3000
上運(yùn)行前端。現(xiàn)在,應(yīng)用程序已經(jīng)準(zhǔn)備好進(jìn)行測試了。
但是分別運(yùn)行后端和前端有點(diǎn)麻煩。所以,讓我們使用Docker來讓整個(gè)構(gòu)建過程變得更簡單。
讓我們將整個(gè)應(yīng)用程序Docker化,以便能夠輕松地將其打包并部署到任何地方。您可以從Docker官方網(wǎng)站安裝和配置Docker。
我們的聊天機(jī)器人的后端是用Spring Boot構(gòu)建的,因此我們將創(chuàng)建一個(gè)Dockerfile,它將Spring Boot應(yīng)用程序構(gòu)建成一個(gè)可執(zhí)行的JAR文件,并在容器中運(yùn)行它。
讓我們來編寫它的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
:這指定容器應(yīng)基于包含 JDK 17 的輕量級 Alpine Linux 映像,這是運(yùn)行 Spring Boot 所必需的。WORKDIR /app
:這行設(shè)置了容器內(nèi)部的工作目錄為/app
,我們的應(yīng)用程序文件將存放在這里。COPY target/chatbot-backend.jar /app/chatbot-backend.jar
:這行將構(gòu)建好的JAR文件從本地機(jī)器(通常在使用Maven或Gradle構(gòu)建項(xiàng)目后的target
文件夾中)復(fù)制到容器中。EXPOSE 8080
:這行告訴Docker應(yīng)用程序?qū)⒃?080端口監(jiān)聽請求。CMD ["java", "-jar", "chatbot-backend.jar"]
:這行指定了容器啟動(dòng)時(shí)將運(yùn)行的命令。它運(yùn)行啟動(dòng)Spring Boot應(yīng)用程序的JAR文件。我們的聊天機(jī)器人的前端是使用React構(gòu)建的,我們可以通過創(chuàng)建一個(gè)Dockerfile來將其Docker化,這個(gè)Dockerfile將安裝必要的依賴項(xiàng),構(gòu)建應(yīng)用程序,并使用像NGINX這樣的輕量級Web服務(wù)器來提供服務(wù)。
讓我們來編寫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)來構(gòu)建React應(yīng)用。在這個(gè)容器中,我們將安裝所有依賴并構(gòu)建應(yīng)用。WORKDIR /app
:這行設(shè)置了容器內(nèi)部的工作目錄為/app
。COPY package.json package-lock.json ./
:這行將package.json
和package-lock.json
文件復(fù)制到容器中,以便安裝依賴。RUN npm install
:這行在容器中運(yùn)行npm install
命令,安裝package.json
中列出的依賴。COPY . .
:這行將前端源代碼的所有文件復(fù)制到容器中。RUN npm run build
:這行在容器中運(yùn)行npm run build
命令,構(gòu)建React應(yīng)用。構(gòu)建后的文件將位于build
文件夾中。FROM nginx:alpine
:在應(yīng)用構(gòu)建完成后,這行指定了基于nginx Web服務(wù)器的輕量級Alpine Linux鏡像來啟動(dòng)一個(gè)新的容器。COPY --from=build /app/build /usr/share/nginx/html
:這行將第一個(gè)容器中構(gòu)建的React應(yīng)用復(fù)制到nginx容器中,并將其放置在nginx默認(rèn)的服務(wù)文件夾中。EXPOSE 80
:這行將公開端口 80,NGINX 使用它來提供 Web 流量。CMD ["nginx", "-g", "daemon off;"]
:這行以前臺模式啟動(dòng)nginx服務(wù)器,以提供React應(yīng)用的服務(wù)。現(xiàn)在我們已經(jīng)分別為前端和后端創(chuàng)建了Dockerfile,接下來我們將使用docker-compose來協(xié)調(diào)同時(shí)運(yùn)行這兩個(gè)容器。
讓我們在項(xiàng)目根目錄下編寫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:
:這行開始定義了想要運(yùn)行的服務(wù)。
backend
:這個(gè)服務(wù)使用位于./backend
目錄的Dockerfile來構(gòu)建后端,并暴露8080端口。frontend
:這個(gè)服務(wù)使用位于./frontend
目錄的Dockerfile來構(gòu)建前端。它將主機(jī)的3000端口映射到容器內(nèi)的80端口depends_on:
:這行確保前端服務(wù)在啟動(dòng)之前等待后端服務(wù)準(zhǔn)備就緒。networks:
:這個(gè)部分定義了一個(gè)共享網(wǎng)絡(luò),以便后端和前端可以相互通信。要運(yùn)行整個(gè)應(yīng)用程序(前端和后端),您可以使用以下命令:
docker-compose up --build
此命令將:
現(xiàn)在,你可以訪問 http://localhost:3000
來加載聊天機(jī)器人的用戶界面,并開始向AI提問。
您已成功使用 Spring Boot、React、Docker 和 OpenAI 構(gòu)建了一個(gè)全棧聊天機(jī)器人應(yīng)用程序。
原文鏈接:https://www.freecodecamp.org/news/ai-chatbot-with-spring-react-docker/