Widget chat AI có thể nhúng vào bất kỳ website nào
npm install
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..."
npm start # Production
npm run dev # Development (auto-reload)
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>
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 |
<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>
Hỗ trợ cả WebSocket và Server-Sent Events (SSE) để stream response từ LLM theo thời gian thực.
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.
Lịch sử chat được lưu vào localStorage, giữ nguyên khi refresh trang. Tự động xóa sau 24 giờ.
Chỉ cần 1 thẻ script để nhúng. Hoạt động với mọi website: WordPress, React, Vue, HTML thuần.
Hỗ trợ OpenAI, Anthropic Claude, hoặc bất kỳ API tương thích OpenAI (Ollama, LM Studio...)
Thiết kế responsive, hiển thị đẹp trên cả desktop và mobile. Fullscreen trên mobile.
# 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
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...`;
# 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
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
database/schema.sql để tạo các bảng cần thiết:
psql -U postgres -d chatbox -f database/schema.sql
LLM có thể tự động gọi các function khi cần. Các function có sẵn:
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
};
}
}
};
get_current_timecalculateget_weathersubmit_contact_form// 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
});
// 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();
// 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);
| 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 |
| 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) |
// 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
}
// 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
}
]
}
// 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
}
// 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"
}
// Response
{
"success": true,
"statistics": {
"activeSessions": 15,
"totalSessions": 150,
"totalMessages": 1250,
"totalFunctionCalls": 89,
"totalTokensUsed": 125000
}
}
ALLOWED_ORIGINS trong file .env
npm run dev để server tự động reload khi bạn thay đổi code.