基于Node.js和Socket.IO搭建的简易AI聊天机器人
最近刚好在巩固node.js,因此尝试使用Node.js、Socket.IO和OpenAI的Moonshot AI搭建了一个简易的聊天机器人。
Github地址 :github.com/weierliteln...
效果图:
一、功能介绍
该简易聊天机器人能够实现与用户的实时互动,通过OpenAI的Moonshot AI加持,提供智能又充满趣味的回复。
二、实现原理
技术选型
为了打造这个聊天机器人,我选用了以下技术栈:
- 后端:Node.js、Express框架、Socket.IO
- 前端:HTML、CSS、JavaScript、Bootstrap
- 智能回复:OpenAI API,特别是Moonshot AI(或换成其他的AI模型)
实现步骤
(1)搭建项目结构
用Node.js初始化一个项目文件夹。然后,安装以下必要的依赖包:
- express:用于搭建我们的HTTP服务器。
- socket.io:实现客户端和服务器之间的实时通信。
- openai:调用OpenAI API。
(2)编写前端代码
前端部分是一个聊天界面,具有发送消息的功能。我们会用Bootstrap来快速搭建一个美观的界面,然后用Socket.IO客户端来与服务器进行实时对话。
HTML
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ChatAI</title>
<link href="./bootstrap-5.3.0-alpha1-dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="box">
<nav class="navbar bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand">ChatAI</a>
<div class="d-flex" role="search">
<span>三山四水</span>
<img src="./pictures/orange.jpg" alt="">
</div>
</div>
</nav>
<div class="body-box">
</div>
<div class="mb-3 bottom-box">
<textarea maxlength="100"></textarea>
<span class="text-count">0/100字</span>
<button class="btn btn-outline-success" type="button" onclick="sendMessage()">发送</button>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="./bootstrap-5.3.0-alpha1-dist/js/bootstrap.min.js"></script>
<script>
const socket = io('http://localhost:3000');
const textarea = document.querySelector('textarea');
const button = document.querySelector('button');
// 发送消息
function sendMessage() {
const message = textarea.value;
socket.emit('sendMessage', {
message
});
textarea.value = '';
const div = document.querySelector('.body-box');
const user = document.createElement('div');
user.className = 'user';
user.innerHTML = `<div class="right">
<div>
<img src="./pictures/orange.jpg" alt="">
</div>
<div>
<span>${new Date().toLocaleString()}</span>
<p class="text-box">${message}</p>
</div>
</div>`;
div.appendChild(user);
}
// 接收服务器发送的消息
socket.on('receiveMessage', (data) => {
const div = document.querySelector('.body-box');
const robot = document.createElement('div');
robot.className = 'robot';
robot.innerHTML = `<div class="right">
<img src="./pictures/pink.jpg" alt="">
<div>
<span>${new Date().toLocaleString()}</span>
<p class="text-box">${data.message}</p>
</div>
</div>
`;
div.appendChild(robot);
});
textarea.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
textarea.value = '';
});
textarea.addEventListener('input', () => {
const value = textarea.value;
const length = value.length;
const textCount = document.querySelector('.text-count');
textCount.innerText = `${length}/100字`;
textCount.style.color = length > 100 ? 'red' : '#198754';
});
</script>
</body>
</html>
css
css
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
}
.box {
width: 100%;
height: 100vh;
background-color: #f3f4f8;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.navbar {
width: 100%;
padding: 10px 5%;
}
.navbar span {
display: block;
margin-right: 10px;
color: #198754;
height: 50px;
line-height: 50px;
}
.bottom-box {
position: relative;
width: 90%;
height: 10%;
display: flex;
justify-content: space-between;
left: 50%;
transform: translateX(-50%);
}
.bottom-box textarea {
width: 90%;
height: 100%;
border-radius: 5px;
border: none;
padding: 10px 20px;
resize: none;
}
textarea:focus {
outline: none;
border: 1px solid #198754;
}
.bottom-box button {
height: 100%;
width: 9%;
border-radius: 5px;
font-size: 20px;
/* border: 1px solid #ccc; */
background-color: #198754;
color: #fff;
position: absolute;
right: 0;
bottom: 0;
}
.body-box {
width: 90%;
height: 75%;
overflow-y: auto;
background-color: #fff;
padding: 20px;
margin: 20px auto;
}
.body-box::-webkit-scrollbar {
width: 10px;
}
.body-box::-webkit-scrollbar-thumb {
background-color: #198754;
border-radius: 10px;
}
.body-box::-webkit-scrollbar-track {
background-color: #fff;
}
.body-box .right {
display: flex;
}
.user {
display: flex;
justify-content: flex-end;
}
.robot {
display: flex;
justify-content: flex-start;
}
img {
display: block;
background-color: #843c3c;
width: 50px !important;
height: 50px !important;
border-radius: 50%;
margin-right: 10px;
object-fit: cover;
}
.user .right img {
margin-left: 10px;
}
.user .right div {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.right div:nth-child(2) {
width: 80%;
}
.right {
display: flex;
}
.user .right {
flex-direction: row-reverse;
}
.user span {
text-align: right;
}
.text-box {
background-color: #198754;
color: #fff;
padding: 10px;
border-radius: 10px;
word-wrap: break-word;
max-width: 80%;
}
.right span {
display: block;
font-size: 12px;
color: #ccc;
margin-left: 10px;
}
.user .right span {
margin-right: 10px;
}
.text-count {
position: absolute;
right: 11%;
bottom: 5px;
color: #198754;
font-size: 12px;
}
(3)编写后端代码
后端部分主要实现以下功能:
- 启动HTTP服务器和Socket.IO服务器。
- 接收客户端发送的消息。
- 调用Moonshot AI来获取智能回复。
- 将智能回复发送回客户端,完成对话。
js
const { Server } = require("socket.io");
const express = require("express");
const http = require("http");
const OpenAI = require("openai");
const socketIO = require("socket.io");
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
app.use(express.static("public"));
const client = new OpenAI({
apiKey: "这里填你自己的API_KEY",// 替换为你的KIMI提供的API_KEY
baseURL: "https://api.moonshot.cn/v1",
});
//这里也可以自定义角色
const systemMessages = [
{
role: "system",
content: "你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。",
},
]
let messages = []
async function makeMessages(input, n = 20) {
messages.push({
role: "user",
content: input,
});
let newMessages = [];
newMessages = systemMessages.concat(newMessages);
if (messages.length > n) {
messages = messages.slice(-n);
}
newMessages = newMessages.concat(messages);
return newMessages;
}
async function chat(input) {
const completion = await client.chat.completions.create({
model: "moonshot-v1-8k",
messages: await makeMessages(input),
temperature: 0.3
});
const assistantMessage = completion.choices[0].message
messages.push(assistantMessage);
return assistantMessage.content;
}
io.on("connection", (socket) => {
// 向客户端发送消息
chat("你好").then(reply => {
console.log(reply);
socket.emit("receiveMessage", {
message: reply,
});
})
})
io.on("connection", (socket) => {
console.log("a user connected");
//从客户端接收消息
socket.on('sendMessage', data => {
console.log(data)
chat(data.message).then(reply => {
console.log(reply);
socket.emit("receiveMessage", {
message: reply,
});
});
})
})
server.listen(3000, () => {
console.log("listening on *:3000");
});
三、结语
本文只是简单地介绍了如何搭建一个聊天页面,并且让我们的聊天机器人能够响应你的消息。但是,这只是一个开始!如果你对这个项目感兴趣,不妨尝试一下以下改进:
- 流式输入输出:让聊天体验更加流畅,就像真人在和你聊天一样。
- 消息存入数据库:这样你就可以查看历史记录,回忆起你和机器人的每一次对话。
- ect......
快来动手试试吧,打造一个属于你自己的聊天机器人!🤖✨
文章或功能有什么需要改进的地方,可以尽情提出来噢!