Chức năng này tạo một chatbot nhỏ cho website bán quần áo PHP + MySQL.
Chatbot hiện tại không dùng AI thật như OpenAI/Gemini và không cần API key. Nó hoạt động theo kiểu demo RAG đơn giản:
- Người dùng nhập câu hỏi trên giao diện web.
- JavaScript gửi câu hỏi đó qua API PHP.
- PHP đọc dữ liệu trong MySQL.
- PHP tìm sản phẩm/chính sách phù hợp.
- PHP tự ghép câu trả lời và trả về cho giao diện chat.
Nói ngắn gọn: chatbot chỉ trả lời dựa trên dữ liệu đang có trong database của website.
RAG là viết tắt của Retrieval Augmented Generation.
Trong đồ án này có thể hiểu đơn giản như sau:
Retrieval: tìm dữ liệu liên quan trong database, ví dụ bảngsanpham.Generation: tạo câu trả lời dựa trên dữ liệu vừa tìm được.
Ví dụ người dùng hỏi:
Quần dưới 100k
Backend sẽ hiểu:
- Cần tìm loại sản phẩm:
Quần - Cần lọc giá: nhỏ hơn
100000 - Tìm trong bảng
sanpham - Trả về danh sách sản phẩm phù hợp
Chatbot này chưa dùng mô hình ngôn ngữ lớn, nên phần Generation chỉ là PHP ghép chuỗi trả lời. Sau này nếu muốn thông minh hơn, có thể lấy dữ liệu tìm được trong database rồi gửi qua OpenAI/Gemini để AI viết câu trả lời tự nhiên hơn.
File này chứa giao diện chatbot:
- Nút chat nổi ở góc phải màn hình.
- Khung chat khi bấm mở.
- Tin nhắn của người dùng.
- Tin nhắn của bot.
- Ô nhập câu hỏi.
- Nút gửi.
File này chỉ lo phần hiển thị, không xử lý database.
File này xử lý phần frontend của chatbot.
Nhiệm vụ chính:
- Mở/đóng khung chat.
- Lấy câu hỏi người dùng nhập.
- Hiển thị tin nhắn người dùng lên khung chat.
- Gửi câu hỏi tới API:
main/api/ai_chatbot.php
- Nhận câu trả lời từ PHP.
- Hiển thị câu trả lời của bot.
Đoạn quan trọng là:
fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({ question: cleanQuestion })
});Đoạn này có nghĩa là JavaScript gửi câu hỏi qua phương thức POST dưới dạng JSON.
Ví dụ dữ liệu gửi đi:
{
"question": "Quần dưới 100k"
}File này dùng để kết nối MySQL.
Cấu hình quan trọng:
$DB_HOST = "localhost";
$DB_USER = "root";
$DB_PASS = "vertrigo";
$DB_NAME = "qlquanao";
$DB_PORT = 3306;Nếu máy bạn dùng cấu hình khác thì sửa tại đây.
Ví dụ:
- Database không tên
qlquanaothì sửa$DB_NAME. - Password MySQL không phải
vertrigothì sửa$DB_PASS. - MySQL chạy port khác
3306thì sửa$DB_PORT.
File này còn thử thêm một số cấu hình local phổ biến như:
localhost127.0.0.1- mật khẩu
vertrigo - mật khẩu rỗng
Mục đích là giúp chạy dễ hơn trên Vertrigo/local server.
Đây là file backend chính của chatbot.
Nhiệm vụ:
- Nhận câu hỏi từ frontend.
- Chuẩn hóa câu hỏi.
- Tách từ khóa.
- Tìm chính sách trong bảng
store_policiesnếu có. - Tìm sản phẩm trong bảng
sanpham. - Ghép câu trả lời.
- Trả JSON về cho JavaScript.
API trả về dạng JSON:
{
"success": true,
"answer": "Tôi tìm thấy 2 sản phẩm phù hợp...",
"sources": {
"products": [],
"policies": []
}
}File SQL mẫu để tạo bảng chính sách/FAQ.
Nếu import file này vào phpMyAdmin, chatbot có thể trả lời thêm các câu như:
- Chính sách đổi trả
- Giao hàng
- Liên hệ cửa hàng
Bảng được tạo là:
store_policiesFile này không bắt buộc. Nếu chưa import, chatbot vẫn tìm sản phẩm bình thường.
File đã sửa:
main/user/user.html
Đã thêm CSS chatbot trong phần <head>:
<link rel="stylesheet" href="../assets/css/chatbot.css">Đã thêm giao diện chatbot gần cuối file:
<button type="button" class="chatbot-fab" id="chatbotFab">
<span class="material-symbols-outlined">smart_toy</span>
</button>
<section class="chatbot-widget hidden" id="chatbotWidget">
...
</section>Đã thêm JavaScript chatbot:
<script src="../assets/js/chatbot.js"></script>Trong user.html có nút:
<button class="chatbot-fab" id="chatbotFab">Khi bấm nút này, chatbot.js sẽ mở khung chat.
Ví dụ:
Có áo nam nào còn hàng không?
File chatbot.js gửi câu hỏi đến:
main/api/ai_chatbot.php
Dữ liệu gửi đi là JSON:
{
"question": "Có áo nam nào còn hàng không?"
}Trong ai_chatbot.php, hàm này đọc câu hỏi:
function getInputQuestion()Nó đọc dữ liệu từ:
php://inputvì JavaScript gửi JSON bằng fetch().
Ví dụ câu hỏi:
Có áo nam nào còn hàng không?
sẽ được chuẩn hóa gần giống:
co ao nam nao con hang khong
Mục đích:
- Dễ nhận biết từ khóa hơn.
- Người dùng gõ có dấu hoặc không dấu đều dễ xử lý hơn.
Với câu:
Có áo nam nào còn hàng không?
Backend hiểu:
- Có chữ
aonên lọcloai_splà áo. - Có chữ
namnên lọcgt_splà nam. - Có chữ
con hangnên lọcsoluong > 0.
SQL sẽ tìm trong bảng:
sanpham
Các cột quan trọng:
id
ten_sp
loai_sp
gt_sp
soluong
gia
mo_ta
hinh_anh
Nếu tìm thấy sản phẩm, PHP trả lời kiểu:
Tôi tìm thấy 2 sản phẩm phù hợp trong hệ thống:
- Áo thun đen lưu niệm của WinWinStore | Áo | Nam | 30.000đ | còn 14 sản phẩm
Nếu không tìm thấy dữ liệu, PHP trả:
Xin lỗi, hiện tại tôi chưa có thông tin về nội dung này.
chatbot.js nhận JSON từ PHP rồi đưa nội dung answer vào khung chat.
Ví dụ:
Áo nam
Quần nữ
Giày nam
Váy
Chatbot sẽ lọc theo cột:
loai_sp
Ví dụ:
Đồ nam
Đồ nữ
Unisex
Chatbot sẽ lọc theo cột:
gt_sp
Ví dụ:
Có áo nam nào còn hàng không?
Quần nào còn hàng?
Chatbot sẽ thêm điều kiện:
soluong > 0Ví dụ:
Quần dưới 100k
Áo dưới 50k
Giày trên 100k
Sản phẩm giá rẻ
Chatbot sẽ lọc theo cột:
gia
Ví dụ:
dưới 100k
tương đương SQL:
gia < 100000Ví dụ:
Mô tả áo thun
Thông tin chi tiết giày
Chất liệu áo
Nếu sản phẩm có dữ liệu ở cột mo_ta, chatbot sẽ đưa mô tả vào câu trả lời.
Ví dụ:
Có tất cả bao nhiêu sản phẩm?
Tổng sản phẩm là bao nhiêu?
Chatbot sẽ không tìm theo tên sản phẩm nữa, mà chạy câu SQL thống kê:
SELECT COUNT(*) AS total_products, COALESCE(SUM(soluong), 0) AS total_stock FROM sanphamKết quả trả về gồm:
- Số mẫu sản phẩm trong bảng
sanpham. - Tổng số lượng tồn kho cộng từ cột
soluong.
Vì bản hiện tại không gọi OpenAI, Gemini hay dịch vụ AI bên ngoài.
Chatbot chỉ dùng:
- HTML
- CSS
- JavaScript
- PHP
- MySQL
Do đó không cần:
- API key
- tài khoản OpenAI
- tài khoản Gemini
- train model
- server riêng
Lỗi 500 Internal Server Error trước đó xảy ra khi chatbot gửi câu hỏi bằng POST.
Nguyên nhân nằm trong file:
main/api/ai_chatbot.php
Hàm gây lỗi là:
function tableExists($conn, $tableName)Ban đầu hàm này dùng:
$stmt = $conn->prepare("SHOW TABLES LIKE ?");
$stmt->bind_param("s", $tableName);
$stmt->execute();
$stmt->store_result();
return $stmt->num_rows > 0;Trên môi trường PHP/MySQL local của Vertrigo, câu SHOW TABLES LIKE ? dùng với prepare() không ổn, làm PHP trả lỗi 500 và response rỗng.
Đã sửa thành:
function tableExists($conn, $tableName) {
$safeTableName = $conn->real_escape_string($tableName);
$result = $conn->query("SHOW TABLES LIKE '$safeTableName'");
return $result && $result->num_rows > 0;
}Nghĩa là:
- Không dùng
prepare()cho câuSHOW TABLES. - Dùng
real_escape_string()để làm sạch tên bảng. - Dùng
$conn->query()để chạy SQL trực tiếp.
Sau khi sửa, API trả 200 OK và chatbot hoạt động lại.
Ban đầu khi hỏi:
Có áo nam nào còn hàng không?
Chatbot trả cả quần và giày nam.
Lý do là backend ghép điều kiện bằng OR.
Nghĩa là chỉ cần sản phẩm là Nam thì cũng được trả về, dù không phải Áo.
Sau đó đã sửa logic thành:
- Nhóm loại sản phẩm phải đúng.
- Nhóm giới tính phải đúng.
- Nhóm tồn kho phải đúng nếu người dùng hỏi còn hàng.
- Nhóm giá phải đúng nếu người dùng hỏi giá.
Ví dụ:
Áo nam còn hàng
sẽ thành logic:
loai_sp là áo
AND gt_sp là nam
AND soluong > 0
Nhờ vậy kết quả không còn lẫn quần/giày nữa.
Ban đầu câu:
Quần dưới 100k
chỉ trả sản phẩm giá từ 50k đến 100k, nên bỏ mất sản phẩm giá 33k, 37k, 40k.
Nguyên nhân là rule cũ thấy chữ 100k rồi hiểu nhầm thành khoảng:
gia BETWEEN 50000 AND 100000Đã sửa thành:
if (preg_match("/duoi\s+([0-9]+)\s*k?/", $normalized, $priceMatch)) {
$maxPrice = ((int)$priceMatch[1]) * 1000;
$filters[] = "gia < " . $maxPrice;
}Nghĩa là:
dưới 100k
sẽ hiểu đúng là:
gia < 100000Mở:
http://127.0.0.1:8070/DoAnWeb/main/api/ai_chatbot.php
Nếu thấy:
{
"success": true,
"answer": "Bạn hãy nhập câu hỏi về sản phẩm, giá, tồn kho hoặc chính sách cửa hàng nhé.",
"sources": []
}thì API đang chạy bình thường. Đây không phải lỗi.
Lý do là trình duyệt đang mở bằng GET, chưa gửi câu hỏi.
Mở:
http://127.0.0.1:8070/DoAnWeb/main/user/user.html
Nhấn nút chat ở góc phải, hỏi thử:
Có áo nam nào còn hàng không?
hoặc:
Quần dưới 100k
Import file:
main/api/chatbot_policies.sql
vào database:
qlquanao
Sau đó chatbot có thể trả lời:
Chính sách đổi trả là gì?
Giao hàng thế nào?
Liên hệ cửa hàng ở đâu?
Sửa trong:
main/api/db_connect.php
Dòng:
$DB_NAME = "qlquanao";Nếu bảng sản phẩm không phải sanpham, sửa trong:
main/api/ai_chatbot.php
Tìm:
FROM sanphamvà đổi thành tên bảng mới.
Chatbot hiện dùng các cột:
ten_sp
loai_sp
gt_sp
soluong
gia
mo_ta
hinh_anh
Nếu database của bạn đặt tên khác, phải sửa lại trong câu SQL và phần tạo câu trả lời.
Hiện tại chatbot tự ghép câu trả lời bằng PHP.
Sau này có thể nâng cấp như sau:
- PHP vẫn tìm dữ liệu liên quan trong MySQL.
- Dữ liệu tìm được được gom thành
context. - Gửi
contextvà câu hỏi người dùng lên OpenAI/Gemini. - AI viết câu trả lời tự nhiên hơn.
- PHP trả câu trả lời đó về frontend.
Điểm quan trọng: dù dùng AI thật, vẫn nên bắt AI chỉ trả lời dựa trên dữ liệu lấy từ database. Như vậy chatbot không tự bịa sản phẩm hoặc chính sách không có trong hệ thống.
Chức năng chatbot gồm 4 phần:
user.html
Hiển thị nút chat và khung chat.
chatbot.css
Làm đẹp giao diện chatbot.
chatbot.js
Gửi câu hỏi của người dùng đến PHP và hiển thị câu trả lời.
ai_chatbot.php
Nhận câu hỏi, tìm trong MySQL, tạo câu trả lời.
db_connect.php
Kết nối database.
Luồng chạy:
Người dùng hỏi
-> chatbot.js gửi POST
-> ai_chatbot.php xử lý
-> db_connect.php kết nối MySQL
-> tìm bảng sanpham/store_policies
-> trả JSON
-> chatbot.js hiển thị câu trả lời