基于Node.js和Socket.IO搭建的简易AI聊天机器人

基于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......

快来动手试试吧,打造一个属于你自己的聊天机器人!🤖✨

文章或功能有什么需要改进的地方,可以尽情提出来噢!

相关推荐
zhangjr057525 分钟前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
不爱学习的YY酱37 分钟前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
木子七1 小时前
vue2-vuex
前端·vue
麻辣_水煮鱼1 小时前
vue数据变化但页面不变
前端·javascript·vue.js
BY—-组态1 小时前
web组态软件
前端·物联网·工业互联网·web组态·组态
一条晒干的咸魚1 小时前
【Web前端】实现基于 Promise 的 API:alarm API
开发语言·前端·javascript·api·promise
WilliamLuo2 小时前
MP4结构初识-第一篇
前端·javascript·音视频开发
Beekeeper&&P...2 小时前
web钩子什么意思
前端·网络
啵咿傲2 小时前
重绘&重排、CSS树&DOM树&渲染树、动画加速 ✅
前端·css
前端Hardy2 小时前
HTML&CSS:数据卡片可以这样设计
前端·javascript·css·3d·html