Chatbox Widget

Widget chat AI có thể nhúng vào bất kỳ website nào

WebSocket & SSE Function Calling Multi-LLM Support Persistent History

1 Quick Start - Bắt đầu nhanh

Demo: Click vào nút chat ở góc dưới bên phải để test chatbot. Lịch sử chat sẽ được lưu lại khi bạn refresh trang.

Cài đặt dependencies

npm install

Cấu hình API Key

Copy file .env.example thành .env và thêm API key:

cp .env.example .env
# Trong file .env
OPENAI_API_KEY=sk-your-api-key-here

# Tùy chọn: Cấu hình System Message
SYSTEM_MESSAGE="Bạn là trợ lý ảo của công ty ABC..."

Khởi động server

npm start      # Production
npm run dev    # Development (auto-reload)

Nhúng vào website

Thêm 1 dòng code này vào website của bạn:

<script src="http://localhost:3000/widget.js"
        data-server="http://localhost:3000"
        data-title="Chat Support"
        data-welcome="Xin chào! Tôi có thể giúp gì cho bạn?"></script>

2 Cấu hình Widget

Data Attributes

Tất cả cấu hình được truyền qua data attributes trong thẻ script:

Attribute Mô tả Mặc định
data-server URL của backend server *Bắt buộc Current origin
data-title Tiêu đề hiển thị trên header "Chat Support"
data-subtitle Trạng thái hiển thị dưới tiêu đề "Online"
data-welcome Tin nhắn chào mừng "Hello! How can I help?"
data-placeholder Placeholder cho ô nhập tin nhắn "Type your message..."
data-primary-color Màu chủ đạo (hex) #007bff
data-use-websocket Sử dụng WebSocket (false = dùng SSE) true
data-auto-open Tự động mở chat khi load trang false
data-persist-history Lưu lịch sử chat vào localStorage true
data-quick-actions Các nút gợi ý (phân cách bằng dấu phẩy) -
data-functions Giới hạn functions được sử dụng Tất cả
data-bot-avatar URL hình đại diện của AI (hiển thị bên trái) Icon SVG mặc định
data-user-avatar URL hình đại diện của người dùng (hiển thị bên phải) Icon SVG mặc định

Ví dụ cấu hình đầy đủ

<script src="https://your-domain.com/widget.js"
        data-server="https://your-domain.com"
        data-title="Hỗ trợ khách hàng"
        data-subtitle="Online 24/7"
        data-welcome="Chào bạn! Tôi là Lisa, trợ lý ảo. Bạn cần hỗ trợ gì?"
        data-placeholder="Nhập tin nhắn..."
        data-primary-color="#10b981"
        data-quick-actions="Báo giá,Tư vấn sản phẩm,Liên hệ hỗ trợ"
        data-auto-open="false"
        data-persist-history="true"
        data-bot-avatar="https://example.com/bot.png"
        data-user-avatar="https://example.com/user.png"></script>

3 Tính năng

Real-time Streaming

Hỗ trợ cả WebSocket và Server-Sent Events (SSE) để stream response từ LLM theo thời gian thực.

Function Calling

LLM có thể gọi các function tùy chỉnh để lấy dữ liệu, thực hiện hành động hoặc tích hợp với hệ thống của bạn.

Persistent History

Lịch sử chat được lưu vào localStorage, giữ nguyên khi refresh trang. Tự động xóa sau 24 giờ.

Easy Integration

Chỉ cần 1 thẻ script để nhúng. Hoạt động với mọi website: WordPress, React, Vue, HTML thuần.

Multi-LLM Support

Hỗ trợ OpenAI, Anthropic Claude, hoặc bất kỳ API tương thích OpenAI (Ollama, LM Studio...)

Mobile Responsive

Thiết kế responsive, hiển thị đẹp trên cả desktop và mobile. Fullscreen trên mobile.

4 Cấu hình Server (.env)

LLM Providers

Server hỗ trợ nhiều LLM provider. Chọn 1 trong các cấu hình sau:
# OpenAI Configuration
LLM_PROVIDER=openai
OPENAI_API_KEY=sk-your-api-key-here
OPENAI_MODEL=gpt-4o-mini  # hoặc gpt-4o, gpt-4-turbo
# Anthropic Claude Configuration
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-your-api-key-here
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
# Custom/Ollama Configuration
LLM_PROVIDER=custom
CUSTOM_LLM_ENDPOINT=http://localhost:11434/v1
CUSTOM_LLM_MODEL=llama2
CUSTOM_API_KEY=not-needed  # Ollama không cần API key

System Message

Tùy chỉnh tính cách và hành vi của AI:

# Cách 1: Trong file .env
SYSTEM_MESSAGE="Bạn là Lisa, trợ lý bán hàng của công ty Bizgenie. Bạn hỗ trợ khách hàng tư vấn các giải pháp chuyển đổi số. Luôn trả lời bằng tiếng Việt."

# Cách 2: Trong file src/services/llm.js (dòng 7)
const DEFAULT_SYSTEM_MESSAGE = `Nội dung system message...`;

Các cấu hình khác

# Server
PORT=3000
HOST=localhost

# CORS - Danh sách domain được phép truy cập
ALLOWED_ORIGINS=http://localhost,https://your-website.com

# WebSocket heartbeat interval (ms)
WS_HEARTBEAT_INTERVAL=30000

PostgreSQL Database

Cấu hình database để lưu trữ lịch sử chat trên server:

# PostgreSQL Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=chatbox
DB_USER=postgres
DB_PASSWORD=your_password_here
Setup Database: Chạy file database/schema.sql để tạo các bảng cần thiết:
psql -U postgres -d chatbox -f database/schema.sql

5 Function Calling

LLM có thể tự động gọi các function khi cần. Các function có sẵn:

get_current_time calculate search_knowledge_base submit_contact_form get_weather

Thêm Function mới

Chỉnh sửa file src/services/functions.js:

// Thêm function mới vào object registeredFunctions
const registeredFunctions = {
  // Function lấy thông tin sản phẩm
  get_product_info: {
    definition: {
      type: 'function',
      function: {
        name: 'get_product_info',
        description: 'Lấy thông tin chi tiết về sản phẩm',
        parameters: {
          type: 'object',
          properties: {
            product_id: {
              type: 'string',
              description: 'Mã sản phẩm'
            }
          },
          required: ['product_id']
        }
      }
    },
    handler: async ({ product_id }) => {
      // Logic lấy thông tin từ database
      return {
        id: product_id,
        name: 'Sản phẩm ABC',
        price: 1000000,
        stock: 50
      };
    }
  }
};

Ví dụ prompt để test

  • "Mấy giờ rồi?" - Gọi get_current_time
  • "Tính 15% của 250" - Gọi calculate
  • "Thời tiết Hà Nội" - Gọi get_weather
  • "Tôi muốn liên hệ, email: test@example.com" - Gọi submit_contact_form

6 JavaScript API

Khởi tạo thủ công

// Khởi tạo với options
const chat = new ChatboxWidget({
  server: 'http://localhost:3000',
  title: 'My Chat',
  subtitle: 'Online',
  welcome: 'Xin chào!',
  primaryColor: '#10b981',
  persistHistory: true
});

Các phương thức

// Mở/Đóng chatbox
chat.open();
chat.close();
chat.toggle();

// Xóa lịch sử chat và bắt đầu cuộc trò chuyện mới
chat.clearHistory();

// Hủy widget hoàn toàn
chat.destroy();

Tích hợp với các sự kiện website

// Mở chat khi click vào button
document.getElementById('support-btn').addEventListener('click', () => {
  ChatboxWidget.open();
});

// Mở chat sau 30 giây người dùng ở trên trang
setTimeout(() => {
  ChatboxWidget.open();
}, 30000);

7 REST API Endpoints

Chat Endpoints

Method Endpoint Mô tả
POST /api/chat/stream Chat với streaming response (SSE)
POST /api/chat/message Chat không streaming
GET /api/chat/functions Danh sách functions khả dụng
GET /api/chat/health Kiểm tra trạng thái server & database
GET /api/chat/statistics Thống kê tổng quan (số phiên, tin nhắn...)
WebSocket /ws Kết nối WebSocket real-time

Session Management Endpoints

Method Endpoint Mô tả
GET /api/chat/sessions Lấy danh sách tất cả phiên chat
GET /api/chat/sessions/:conversationId Lấy chi tiết phiên chat (bao gồm tin nhắn)
GET /api/chat/sessions/:conversationId/functions Lấy lịch sử function executions của phiên
DELETE /api/chat/sessions/:conversationId Xóa phiên chat (soft/hard delete)
GET /api/chat/history/:conversationId Lấy lịch sử hội thoại (format đơn giản)
DELETE /api/chat/history/:conversationId Xóa phiên chat (backwards compatible)

Ví dụ Request/Response

POST /api/chat/stream

// Request Body
{
  "message": "Xin chào",
  "conversationId": "conv_abc123",  // Optional - tự động tạo nếu không có
  "userIdentifier": "user@email.com",  // Optional - định danh user
  "functions": ["get_current_time", "calculate"]  // Optional - giới hạn functions
}

GET /api/chat/sessions

// Query Parameters
?limit=50            // Số lượng tối đa (default: 50)
&offset=0           // Vị trí bắt đầu (default: 0)
&activeOnly=true    // Chỉ lấy phiên active (default: true)
&userIdentifier=xxx // Lọc theo user (optional)

// Response
{
  "success": true,
  "count": 10,
  "sessions": [
    {
      "id": "uuid-here",
      "conversationId": "conv_1234567890_abcd1234",
      "userIdentifier": "user@email.com",
      "startedAt": "2024-01-15T10:30:00Z",
      "lastMessageAt": "2024-01-15T10:35:00Z",
      "isActive": true,
      "totalMessages": 8
    }
  ]
}

GET /api/chat/sessions/:conversationId

// Query Parameters
?includeMessages=true  // Có lấy tin nhắn không (default: true)
&messageLimit=100     // Số tin nhắn tối đa (default: 100)

// Response
{
  "success": true,
  "session": {
    "id": "uuid-here",
    "conversationId": "conv_1234567890_abcd1234",
    "userIdentifier": "user@email.com",
    "userIp": "192.168.1.1",
    "userAgent": "Mozilla/5.0...",
    "startedAt": "2024-01-15T10:30:00Z",
    "lastMessageAt": "2024-01-15T10:35:00Z",
    "isActive": true
  },
  "messages": [
    {
      "id": "msg-uuid",
      "role": "user",
      "content": "Xin chào",
      "model": null,
      "tokensUsed": 0,
      "createdAt": "2024-01-15T10:30:00Z"
    },
    {
      "id": "msg-uuid-2",
      "role": "assistant",
      "content": "Xin chào! Tôi có thể giúp gì cho bạn?",
      "model": "gpt-4o-mini",
      "tokensUsed": 15,
      "createdAt": "2024-01-15T10:30:05Z"
    }
  ],
  "totalMessages": 2
}

DELETE /api/chat/sessions/:conversationId

// Query Parameters
?hard=false  // false = soft delete (default), true = xóa vĩnh viễn

// Response
{
  "success": true,
  "message": "Session deactivated",  // hoặc "Session permanently deleted"
  "conversationId": "conv_1234567890_abcd1234"
}

GET /api/chat/statistics

// Response
{
  "success": true,
  "statistics": {
    "activeSessions": 15,
    "totalSessions": 150,
    "totalMessages": 1250,
    "totalFunctionCalls": 89,
    "totalTokensUsed": 125000
  }
}

8 Cấu trúc dự án

chatboxlib/
├── src/
│ ├── server.js ── Entry point, khởi tạo Express & WebSocket
│ ├── routes/
│ │ └── chat.js ── API routes (SSE, REST, Session Management)
│ └── services/
│ ├── llm.js ── Kết nối LLM, System Message
│ ├── functions.js ── Registry cho Function Calling
│ ├── websocket.js ── WebSocket handler
│ └── database.js ── PostgreSQL connection & queries
├── database/
│ └── schema.sql ── SQL schema cho PostgreSQL
├── public/
│ ├── index.html ── Trang demo này
│ ├── css/
│ │ └── chatbox.css ── Styles cho widget
│ └── js/
│ └── widget.js ── Widget script để nhúng
├── .env.example ── Template cấu hình
├── .env ── Cấu hình thực tế (không commit)
├── package.json
└── README.md

9 Xử lý lỗi thường gặp

CORS Error: Nếu gặp lỗi CORS, thêm domain của bạn vào ALLOWED_ORIGINS trong file .env
WebSocket không kết nối: Kiểm tra firewall và đảm bảo port 3000 không bị chặn. Nếu dùng HTTPS, cần WSS thay vì WS.
API Key Error: Đảm bảo đã copy đúng API key vào file .env và restart server sau khi thay đổi.
Tip: Sử dụng npm run dev để server tự động reload khi bạn thay đổi code.