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

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

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

相关推荐
Larcher29 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐42 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭1 小时前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信1 小时前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程