Chờ một xíu nhaaaa!
Trang chủ
  • leviathan706leviathan706
  • Date:  Tháng mười một 6, 2025
  • Linh tinh

Code chatbot AI for Web

Front-end




WIN WIN POWER

Trợ lý AI sẵn sàng tư vấn 24/7

Xin chào! Tôi là trợ lý AI của WIN WIN POWER. Tôi có thể tư vấn cho bạn về các giải pháp điện mặt trời và pin lưu trữ. Bạn cần hỗ trợ gì ạ?



Back-end

/*
Đây là code cho Backend (Supabase Edge Function) đã được cập nhật để sử dụng Google Gemini API.
Tệp này sẽ được đặt tại: /supabase/functions/chat-bot/index.ts
Nó sẽ xử lý logic nghiệp vụ, gọi Gemini API và TRÍCH XUẤT THÔNG TIN LEAD.
*/

import { serve } from ‘https://deno.land/std@0.177.0/http/server.ts’;

// Lấy API key của Gemini từ biến môi trường (an toàn)
const GEMINI_API_KEY = Deno.env.get(‘GEMINI_API_KEY’);
const GEMINI_API_URL = ‘https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent’;

// Hàm helper để chuyển đổi định dạng tin nhắn sang định dạng của Gemini API
function convertMessagesToGeminiFormat(messages: any[]) {
const systemInstruction = messages.find(m => m.role === ‘system’)?.content || ”;
const contents = messages
.filter(m => m.role !== ‘system’)
.map(m => {
const role = m.role === ‘assistant’ ? ‘model’ : m.role;
return {
role: role,
parts: [{ text: m.content }]
};
});

return { systemInstruction, contents };
}

/**
* Hàm trích xuất thông tin Tên, SĐT, Địa chỉ từ tin nhắn của khách hàng
* Dùng regex đơn giản để tìm kiếm các thông tin phổ biến.
*/
function extractLeadInfo(text: string): { customer_name: string | null, phone_number: string | null, address: string | null } {
// 1. Tìm Số điện thoại (chỉ tìm chuỗi số từ 8-12 chữ số)
const phoneMatch = text.match(/((0|\+84)\s?(\d{2,4})\s?\d{3,4}\s?\d{3,4})/);
let phoneNumber = phoneMatch ? phoneMatch[0].trim().replace(/\s/g, ”) : null;

// Loại bỏ SĐT ra khỏi văn bản để dễ tìm Tên và Địa chỉ hơn
let remainingText = text;
if (phoneNumber) {
remainingText = remainingText.replace(phoneMatch[0], ‘ ‘);
}

// 2. Tạm thời coi phần còn lại là Tên và Địa chỉ.
// Việc tách chính xác Tên và Địa chỉ bằng code rất phức tạp.
// Tốt nhất là lưu toàn bộ tin nhắn (messages_json) và sử dụng bot để trích xuất sau,
// nhưng ta vẫn cố gắng trích xuất cơ bản.

// Coi phần còn lại là Tên và Địa chỉ
const parts = remainingText.trim().split(/[,;]/).map(p => p.trim()).filter(p => p.length > 0);

let name = null;
let address = null;

if (parts.length >= 2) {
// Giả định phần đầu là tên, phần cuối là địa chỉ
name = parts[0];
address = parts.slice(1).join(‘, ‘).trim();
} else if (parts.length === 1) {
// Nếu chỉ còn một phần (ví dụ chỉ có tên)
name = parts[0];
}

return {
customer_name: name || null,
phone_number: phoneNumber,
address: address || null
};
}

serve(async (req) => {
// Xử lý CORS
if (req.method === ‘OPTIONS’) {
return new Response(‘ok’, {
headers: {
‘Access-Control-Allow-Origin’: ‘*’,
‘Access-Control-Allow-Methods’: ‘POST, OPTIONS’,
‘Access-Control-Allow-Headers’: ‘authorization, x-client-info, apikey, content-type’,
},
});
}

try {
if (!GEMINI_API_KEY) {
throw new Error(‘Missing GEMINI_API_KEY environment variable. Please set it via Supabase CLI.’);
}

// Lấy lịch sử tin nhắn từ client
const { messages } = await req.json();

if (!messages) {
throw new Error(‘Missing “messages” in request body’);
}

// Lấy tin nhắn cuối cùng của người dùng
const userMessage = messages[messages.length – 1].content;
const userMessageLower = userMessage.toLowerCase();

let responseContent = ”;
let skipAI = false;
let leadData = null; // Dữ liệu Lead sẽ được gửi về Frontend

// — LOGIC NGHIỆP VỤ (Thu thập thông tin khách hàng) —
const priceKeywords = [‘giá’, ‘báo giá’, ‘chi phí’, ‘giá cả’, ‘bao nhiêu tiền’];
const isAskingForPrice = priceKeywords.some(keyword => userMessageLower.includes(keyword));

// Kiểm tra xem tin nhắn trước đó của bot có phải là yêu cầu thông tin không
const lastBotMessage = messages[messages.length – 2]?.content || ”;
const wasAskingForInfo = lastBotMessage.includes(‘Tên, Số điện thoại và Địa chỉ’);

if (isAskingForPrice && !wasAskingForInfo) {
// 1. Khách hàng hỏi giá lần đầu
responseContent = ‘Dạ, để cung cấp báo giá chính xác, em cần thêm một số thông tin ạ. Anh/Chị vui lòng cho em xin Tên, Số điện thoại và Địa chỉ lắp đặt dự kiến nhé!’;
skipAI = true;
} else if (wasAskingForInfo && userMessage.trim().length > 5) { // Đã yêu cầu và người dùng đã nhập thông tin
// 2. Khách hàng vừa cung cấp thông tin

// TRÍCH XUẤT THÔNG TIN VÀ CHUẨN BỊ GỬI VỀ FRONTEND
leadData = extractLeadInfo(userMessage);

responseContent = ‘Cảm ơn Anh/Chị! Bộ phận kinh doanh của WIN WIN POWER sẽ liên hệ tư vấn và báo giá cho mình sớm nhất ạ. Anh/Chị còn cần em hỗ trợ thêm thông tin gì không ạ?’;
skipAI = true;
}
// — KẾT THÚC LOGIC NGHIỆP VỤ —

if (!skipAI) {
// 3. Các trường hợp còn lại, gọi Gemini API

const { systemInstruction, contents } = convertMessagesToGeminiFormat(messages);

const payload = {
contents: contents,
systemInstruction: {
parts: [{ text: systemInstruction }]
},
generationConfig: {
temperature: 0.5,
maxOutputTokens: 300,
}
};

const geminiResponse = await fetch(`${GEMINI_API_URL}?key=${GEMINI_API_KEY}`, {
method: ‘POST’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify(payload)
});

if (!geminiResponse.ok) {
const errorText = await geminiResponse.text();
throw new Error(`Gemini API call failed: ${geminiResponse.status} – ${errorText}`);
}

const result = await geminiResponse.json();

// Lấy nội dung từ phản hồi của Gemini
responseContent = result?.candidates?.[0]?.content?.parts?.[0]?.text || ‘Xin lỗi, tôi không thể tạo phản hồi vào lúc này.’;
}

// Trả phản hồi về cho client, bao gồm cả leadData (nếu có)
return new Response(JSON.stringify({ reply: responseContent, leadData: leadData }), {
headers: {
‘Access-Control-Allow-Origin’: ‘*’,
‘Content-Type’: ‘application/json’,
},
});
} catch (error) {
console.error(‘Error handling request:’, error.message);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: {
‘Access-Control-Allow-Origin’: ‘*’,
‘Content-Type’: ‘application/json’,
},
});
}
});

Hướng dẫn

Chào bạn, để chatbot hoạt động, bạn cần làm theo 3 phần chính sau. Hãy kiên nhẫn một chút ở phần 1 và 2, bạn chỉ làm một lần duy nhất.

PHẦN 1: CÀI ĐẶT CƠ SỞ DỮ LIỆU (SUPABASE)

Đây là nơi lưu trữ các cuộc hội thoại.

  1. Tạo tài khoản Supabase:
    • Truy cập supabase.com và đăng ký một tài khoản miễn phí.
  2. Tạo Project mới:
    • Sau khi đăng nhập, nhấn “New Project”.
    • Đặt tên cho project (ví dụ: “win-win-power-bot”), tạo mật khẩu Database.
    • Chọn “Region” là “Southeast Asia” (Singapore) cho tốc độ nhanh nhất.
    • Chờ vài phút để project được khởi tạo.
  3. Lấy API Keys:
    • Trong project dashboard, vào Settings (biểu tượng bánh răng) -> API.
    • Tìm mục “Project API Keys”.
    • Copy 2 giá trị:
      • Project URL (Đây là SUPABASE_URL)
      • anon public key (Đây là SUPABASE_ANON_KEY)
    • Lưu lại 2 giá trị này để dán vào file chatbot-wordpress.html.
  4. Tạo Bảng Lưu trữ:
    • Quay lại trang chủ project, chọn SQL Editor (biểu tượng </>).
    • Nhấn “New query”.
    • Dán đoạn mã SQL dưới đây vào và nhấn RUN:

    -- 1. Tạo bảng để lưu hội thoại và thông tin Lead CREATE TABLE public.conversations ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), conversation_id TEXT NOT NULL UNIQUE, messages_json JSONB, -- Lưu toàn bộ tin nhắn (user và bot) -- Cột mới để lưu thông tin khách hàng (Lead) được trích xuất customer_name TEXT NULL, phone_number TEXT NULL, address TEXT NULL ); -- 2. Kích hoạt Row Level Security (RLS) để bảo mật ALTER TABLE public.conversations ENABLE ROW LEVEL SECURITY; -- 3. Tạo Policy cho phép ai cũng có thể TẠO (INSERT) hội thoại -- Khách hàng của bạn sẽ dùng quyền này CREATE POLICY "Allow public insert" ON public.conversations FOR INSERT WITH CHECK (true); -- 4. Tạo Policy cho phép ai cũng có thể CẬP NHẬT (UPDATE) hội thoại -- Dùng để cập nhật tin nhắn mới và thông tin Lead (nếu có) CREATE POLICY "Allow public update" ON public.conversations FOR UPDATE USING (true);

PHẦN 2: CÀI ĐẶT BACKEND AN TOÀN (SUPABASE EDGE FUNCTION)

Đây là phần gọi Gemini API an toàn mà không lộ API Key.

  1. Cài đặt Supabase CLI (Làm trên máy tính của bạn):
    • Bạn cần cài đặt Supabase CLI để deploy function.
    • Nếu dùng macOS: brew install supabase/tap/supabase
    • Nếu dùng Windows: scoop bucket add supabase; scoop install supabase
    • (Xem thêm tại: docs.supabase.com/guides/cli)
  2. Liên kết Project:
    • Mở Terminal (Command Prompt) trên máy tính.
    • Tạo một thư mục mới: mkdir win-win-bot && cd win-win-bot
    • Đăng nhập: supabase login
    • Liên kết đến project của bạn: supabase link --project-ref YOUR_PROJECT_REF
      • (Bạn có thể tìm thấy YOUR_PROJECT_REF trong Settings -> General)
  3. Tạo Edge Function:
    • Chạy lệnh: supabase functions new chat-bot
    • Thao tác này sẽ tạo một thư mục: supabase/functions/chat-bot/index.ts.
  4. Dán Code Backend:
    • Mở tệp supabase/functions/chat-bot/index.ts vừa tạo.
    • Xóa toàn bộ nội dung cũ của nó.
    • Copy toàn bộ nội dung của tệp backend-function.ts (ở dưới) và dán vào.
  5. Cài đặt Gemini API Key (Bảo mật):
    • Lấy API key của bạn từ Google AI Studio hoặc Google Cloud Vertex AI.
    • Trong Terminal, chạy lệnh sau (thay AIzaSy...your-key-here bằng key của bạn): supabase secrets set GEMINI_API_KEY=AIzaSy...your-key-here
    • Lưu ý: Bạn cần có tài khoản API đã kích hoạt.
  6. Deploy Function:
    • Chạy lệnh: supabase functions deploy chat-bot
    • Sau khi deploy thành công, Supabase sẽ trả về cho bạn một URL. Đây chính là SUPABASE_EDGE_FUNCTION_URL.
    • Lưu lại URL này để dán vào file chatbot-wordpress.html.

PHẦN 3: THÊM CHATBOT VÀO WORDPRESS

Đây là bước cuối cùng!

  1. Mở tệp chatbot-wordpress.html:
    • Mở tệp chatbot-wordpress.html (ở dưới) bằng một trình soạn thảo văn bản (như Notepad, VSCode…).
  2. Cập nhật Cấu hình:
    • Tìm đến phần “CẤU HÌNH DÀNH CHO QUẢN TRỊ VIÊN”.
    • Dán 3 giá trị bạn đã lưu từ Phần 1 và Phần 2 vào:
      • SUPABASE_URL
      • SUPABASE_ANON_KEY
      • SUPABASE_EDGE_FUNCTION_URL
    • Bạn cũng có thể chỉnh sửa SYSTEM_PROMPT tại đây để thay đổi cách chatbot trả lời.
  3. Dán Code vào WordPress:
    • Copy toàn bộ nội dung của tệp chatbot-wordpress.html (sau khi đã cập nhật cấu hình).
    • Đăng nhập vào trang quản trị WordPress của bạn.
    • Cách dễ nhất (Khuyên dùng):
      1. Vào Plugins -> Add New.
      2. Tìm và cài đặt plugin tên là “Insert Headers and Footers” (của WPBeginner).
      3. Kích hoạt (Activate) plugin.
      4. Vào Settings -> Insert Headers and Footers.
      5. Dán toàn bộ code đã copy vào ô “Scripts in Footer”.
      6. Nhấn Save.
    • Cách khác (Nếu bạn biết về theme):
      1. Vào Appearance -> Theme File Editor.
      2. Ở bên phải, tìm và mở tệp Theme Footer (footer.php).
      3. Dán toàn bộ code ngay trước thẻ </body>.
      4. Nhấn Update File.
  4. Kiểm tra kết quả:
    • Mở trang web của bạn ở chế độ ẩn danh (incognito) để xem.
    • Bạn sẽ thấy biểu tượng chat ở góc dưới bên phải.
    • Thử chat và kiểm tra xem bot có trả lời và thu thập thông tin khi hỏi về giá không.
    • Bạn có thể vào Supabase -> Table Editor -> bảng conversations để xem các tin nhắn được lưu lại.

Chúc mừng! Bạn đã có một chatbot AI chuyên nghiệp cho WIN WIN POWER.

Posted in Linh tinh
Về trước
Tất cả bài viết
Tiếp theo

Viết bình luận

© Leviathan 2025. All rights reserved.

Thiết kế bởi #Leviathan706