Mini Open-Source Chat Bot Clone

A free‑local Node.js chat bot inspired by OpenBot

Welcome to another official UVF IT guide! In the next 45 minutes you’ll spin up a tiny chat‑bot service that runs entirely on your machine, mimicking the core of OpenBot’s multiplayer chat experience.

We’ll use Node.js, Express, and SQLite – all free‑tier, no external API keys required. By the end you’ll have a REST endpoint that stores and returns messages, plus a minimal web UI to test it.

Before you start

Component Overview
LOCAL STACK HTTP SQL Node.js Express Server API + UI SQLite DB Browser UI HTML + JS
1

Phase 1: Scaffold the project

Create a new folder for the bot, run npm init -y to generate a basic package.json, and install the runtime libraries you’ll need. This gives you a clean, runnable Node.js skeleton to start adding code.

We’ll pull in Express for the HTTP API and better‑sqlite3 for fast, zero‑config SQLite access. All of these packages are free and work offline.

After these steps you can launch node index.js and see a “Hello World” response, confirming the scaffold works.

mkdir mini-chat-bot && cd mini-chat-bot
npm init -y
npm install express better-sqlite3
2

Phase 2: Define the data model (SQLite)

Create a small SQLite file and a messages table that holds each chat entry. The table includes an auto‑increment id, the author name, the message text, and a timestamp so you can order chats chronologically.

We’ll write a tiny script init_db.js that runs once, creates the file if it doesn’t exist, and sets up the schema. Running it is our first proof that the database layer works.

init_db.js

const Database = require('better-sqlite3');
const path = require('path');

// SQLite file lives in the project root
const dbPath = path.resolve(__dirname, 'chat.db');
const db = new Database(dbPath);

// Create messages table if it doesn't exist
const createTable = `
CREATE TABLE IF NOT EXISTS messages (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  author TEXT NOT NULL,
  content TEXT NOT NULL,
  timestamp DATETIME DEFAULT (datetime('now'))
);
`;

db.exec(createTable);
console.log('✅ SQLite database initialized at', dbPath);
3

Phase 3: Build the API & UI server

In this step we spin up a tiny Express server that will act as both our API backend and static file host. We keep messages in memory for simplicity, exposing a GET route to read the chat history and a POST route to add new entries. The server also serves any files placed in a public/ folder, which will later hold our UI page. This keeps the whole clone in a single process and makes local testing painless.

server.js

const express = require('express');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;

// In‑memory store for chat messages
let messages = [];

app.use(express.json());
// Serve static assets from the public folder
app.use(express.static(path.join(__dirname, 'public')));

// GET /messages – return the full chat history
app.get('/messages', (req, res) => {
  res.json(messages);
});

// POST /messages – accept a new message object {author, text}
app.post('/messages', (req, res) => {
  const {author, text} = req.body;
  if (!author || !text) {
    return res.status(400).json({error: 'author and text required'});
  }
  const newMsg = {id: Date.now(), author, text, timestamp: new Date()};
  messages.push(newMsg);
  res.status(201).json(newMsg);
});

app.listen(PORT, () => {
  console.log(`🚀 http://localhost:${PORT}`);
});
4

Phase 4: Add a minimal UI

Now we create a single HTML page that lets a user type a message and see the conversation history. The page lives in public/index.html so Express will serve it automatically. A tiny script polls the /messages endpoint every few seconds, renders the list, and posts new messages when the form is submitted.

The UI is intentionally simple—just a text input, a submit button, and a <ul> that displays each message with its author and timestamp. This keeps the focus on the API plumbing while still giving a usable chat experience.

public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Mini Chat Bot</title>
  <style>
    body {font-family: Arial, sans-serif; margin: 2rem;}
    #messages {list-style: none; padding: 0;}
    #messages li {margin-bottom: 0.5rem;}
  </style>
</head>
<body>
  <h1>Mini Chat Bot</h1>
  <ul id="messages"></ul>
  <form id="msgForm">
    <input type="text" id="author" placeholder="Your name" required />
    <input type="text" id="text" placeholder="Message" required />
    <button type="submit">Send</button>
  </form>

  <script>
    const messagesEl = document.getElementById('messages');
    const form = document.getElementById('msgForm');

    // Fetch and render messages
    async function loadMessages() {
      const res = await fetch('/messages');
      const msgs = await res.json();
      messagesEl.innerHTML = '';
      msgs.forEach(m => {
        const li = document.createElement('li');
        li.textContent = `[${new Date(m.timestamp).toLocaleTimeString()}] ${m.author}: ${m.text}`;
        messagesEl.appendChild(li);
      });
    }

    // Submit a new message
    form.addEventListener('submit', async e => {
      e.preventDefault();
      const author = document.getElementById('author').value.trim();
      const text = document.getElementById('text').value.trim();
      if (!author || !text) return;
      await fetch('/messages', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({author, text})
      });
      document.getElementById('text').value = '';
      loadMessages();
    });

    // Initial load and periodic refresh
    loadMessages();
    setInterval(loadMessages, 5000);
  </script>
</body>
</html>
5

Phase 5: Run & verify locally

With the server and UI in place, it’s time to launch the app. Install Express, start the Node process, and open the browser to the local address. Try sending a message; you should see it appear instantly and remain after you refresh the page, confirming that the API and UI are wired correctly.

If anything looks off, check the console output for the startup banner and inspect the network tab for successful GET/POST calls to /messages. This feedback loop helps you debug quickly while staying in the minimal‑clone mindset.

# Install dependencies (run once)
npm init -y > /dev/null
npm install express > /dev/null

# Start the server
node server.js

Verifying the Stack

CheckCommand / Why it matters
Server starts without errorsnode server.js → console shows '🚀 http://localhost:3000'
GET /messages returns a JSON arraycurl http://localhost:3000/messages → [] or list of messages
New message appears in UI and persists after page reloadOpen http://localhost:3000 in a browser, send a message, refresh page – message remains

What’s next?

You now have a functional local chat bot. Experiment by adding user authentication, WebSocket live updates, or hooking an LLM for AI replies – all still on your own hardware.