Use Node.JS to build your own AI chatbot

Node.js is a free, open-source, cross-platform JavaScript runtime environment that enables developers to create servers, web applications, command-line tools, and scripts. The Windows installation package can be downloaded here: https://nodejs.org/en.

We are going to use VS Code as the development environment, first enter the following command in the command line:

npm init -y

This command initializes the development environment, and after executing it, you can see that a package.json file has been generated in the project folder.

Image

The package.json file is the central configuration file for a Node.js project. It contains metadata about the project and manages its dependencies, scripts, and other configurations.

Main functions:

  • Metadata: Includes project name, version, description, author, and license information.
  • Dependency Management: Lists project dependencies under dependencies and development dependencies under devDependencies. Specifies version ranges for each dependency (e.g., ^1.0.0, ~1.0.0, >=1.0.0).
  • Scripts: Allows you to define custom commands that can be run using npm run . Example: “start”: “node server.js”

Compatibility: Others can use it to install necessary dependencies using npm install.

Enter the following command to install the Express server framework::

    npm install express
    

    Create a public folder in the project directory, and then create index.html, scripts.js, and style.css inside the folder to build the web interface, interaction logic, and style decoration. Additionally, create a .env file to store API keys.。

    Image

    Overall, the Node.js file structure is similar to Flask, and if you are familiar with Flask development, you can easily understand the underlying logic.
    I remember that JavaScript was previously only used for web frontend development, writing interactions and such. I didn’t expect that now it can handle both frontend and backend, enabling full-stack development.
    Create a server.js file in the project root directory to test running the server, with the code as follows::

    const express = require('express');
    const app = express();
    app.get('/', (req, res) => {
      res.send('Hello World!');
    });
    const PORT = 3000;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
    

    To run this code, simply enter node + filename in the terminal.

    Image

    The server is successfully running on local port 3000.
    Open a browser and enter localhost:3000 to see Hello World!, indicating that the server is running successfully.

    Image

    Next, optimize the code to call index.html:

    const express = require('express');
    const path = require('path');
    const app = express();
    const port = 3000;
    // Serve static files from the 'public' directory
    app.use(express.static(path.join(__dirname, 'public')));
    // Start the server
    app.listen(port, () => {
      console.log(`Server running at http://localhost:${port}`);
    });
    

    Write a simple index.html file:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Hello World App</title>
      <link rel="stylesheet" href="style.css">
    </head>
    <body>
      <h1>Hello, World!</h1>
      <p>Welcome to the enhanced Node.js application.</p>
      <button id="greetButton">Click Me</button>
      <script src="script.js"></script>
    </body>
    </html>
    

    In the script.js file, write simple interaction logic to display “Hello World!” when the button is clicked:

    // Select the button
    const greetButton = document.getElementById('greetButton');
    // Add a click event listener to the button
    greetButton.addEventListener('click', () => {
      alert('Hello, World!');
    });
    

    Press ctrl+c to pause the server, then run it again and open a browser to access localhost:3000:

    Image

    Click “Click Me” to display Hello World!

    Image

    The above is a basic introduction to Node.js Express framework server development, which is relatively easy to get started with. Next, let’s look at how to build a simple AI chat website using this framework, taking ChatGPT as an example.
    First, install new dependency packages::

    npm install body-parser openai dotenv
    

    OpenAI needs no introduction, body-parser is a middleware used to handle various data types like JSON and text. dotenv is used to read API keys.
    Server-side server.js code is as follows:

    const express = require('express');
    const path = require('path');
    const bodyParser = require('body-parser');
    const OpenAI = require('openai');
    require('dotenv').config();
    const app = express();
    const port = 3000;
    // Configure OpenAI API
    const openai = new OpenAI({
        apiKey: process.env.OPENAI_API_KEY
      });
    // Middleware
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(bodyParser.json());
    // API endpoint to handle AI response
    app.post('/ask', async (req, res) => {
        const userPrompt = req.body.prompt;
        try {
          const response = await openai.chat.completions.create({
            model: 'gpt-4',
            messages: [{ 
              role: 'user', 
              content: userPrompt  
            }],
          });
          const aiMessage = response.choices[0].message.content;
          res.json({ reply: aiMessage });
        } catch (error) {
          console.error('Error:', error);
          res.status(500).json({ error: 'Failed to get response from AI' });
        }
      });
    // Start the server
    app.listen(port, () => {
      console.log(`Server running at http://localhost:${port}`);
    });
    

    Those require statements are like Python’s import, importing various modules. Then read the OpenAI API key from .env. The core program is this section, inputting a prompt as a user and calling the GPT-4o model.

          const response = await openai.chat.completions.create({
            model: 'gpt-4o',
            messages: [{ 
              role: 'user', 
              content: userPrompt  
    

    HTML code:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ChatGPT Web App</title>
      <link rel="stylesheet" href="style.css">
    </head>
    <body>
      <h1>Chat with AI</h1>
      <textarea id="userPrompt" placeholder="Enter your prompt here..."></textarea>
      <button id="askButton">Ask AI</button>
      <div id="responseContainer">
        <h3>Response:</h3>
        <p id="aiResponse"></p>
      </div>
      <script src="script.js"></script>
    </body>
    </html
    

    Interaction logic script.js:

    const askButton = document.getElementById('askButton');
    const userPrompt = document.getElementById('userPrompt');
    const aiResponse = document.getElementById('aiResponse');
    askButton.addEventListener('click', async () => {
      const prompt = userPrompt.value;
      if (!prompt.trim()) {
        aiResponse.textContent = 'Please enter a prompt.';
        return;
      }
      try {
        const response = await fetch('/ask', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ prompt }),
        });
        const data = await response.json();
        if (response.ok) {
          aiResponse.textContent = data.reply;
        } else {
          aiResponse.textContent = 'Error: ' + (data.error || 'Failed to fetch response.');
        }
      } catch (error) {
        console.error('Error:', error);
        aiResponse.textContent = 'An error occurred. Please try again.';
      }
    });
    

    CSS style code:

    body {
        font-family: Arial, sans-serif;
        text-align: center;
        margin-top: 50px;
        background-color: #f4f4f9;
        color: #333;
      }
      
      h1 {
        color: #007bff;
      }
      
      textarea {
        width: 80%;
        height: 100px;
        margin: 10px 0;
        padding: 10px;
        font-size: 16px;
        border: 1px solid #ddd;
        border-radius: 5px;
      }
      
      button {
        background-color: #007bff;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        font-size: 16px;
        cursor: pointer;
      }
      
      button:hover {
        background-color: #0056b3;
      }
      
      #responseContainer {
        margin-top: 20px;
      }
      
      #responseContainer h3 {
        margin-bottom: 5px;
      }
      
      #aiResponse {
        font-size: 16px;
        color: #555;
      }  
    

    Running interface:

    Image

    Image

    This AI only completes a single conversation without context memory. To implement context memory, you can call some memory-related functions from Langchain. The updated server-side code is as follows, with no need to modify the frontend and interaction logic code:

    const { ChatOpenAI } = require("@langchain/openai");
    const { BufferMemory } = require("langchain/memory");
    const { ConversationChain } = require("langchain/chains");
    const bodyParser = require('body-parser');
    const express = require('express');
    const path = require('path');
    const app = express();
    const port = 3000;
    require('dotenv').config();
    // Middleware
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(bodyParser.json());
    const chatModel = new ChatOpenAI({
      openAIApiKey: process.env.OPENAI_API_KEY,
      modelName: 'gpt-4',
      temperature: 0.7
    });
    const memory = new BufferMemory();
    const chain = new ConversationChain({ 
      llm: chatModel, 
      memory: memory 
    });
    app.post('/ask', async (req, res) => {
      try {
        const response = await chain.call({
          input: req.body.prompt
        });
        res.json({ reply: response.response });
      } catch (error) {
        console.error('Error:', error);
        res.status(500).json({ error: 'Failed to get response' });
      }
    });
    // Start the server
    app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
      });
    

    Test results:

    Image
    Image
    Image