diff --git a/.env.example b/.env.example new file mode 100644 index 000000000000..274feffd1075 --- /dev/null +++ b/.env.example @@ -0,0 +1,59 @@ +# LLM Integration Configuration +# Copy this file to .env and fill in your API keys + +# ============================================================================ +# LLM Provider Selection +# ============================================================================ +# Choose: 'openai' or 'claude' +LLM_PROVIDER=openai + +# ============================================================================ +# OpenAI Configuration +# ============================================================================ +# Get your API key from: https://platform.openai.com/api-keys +OPENAI_API_KEY=your-openai-api-key-here + +# Model options: +# - gpt-4 (most capable, expensive) +# - gpt-3.5-turbo (fast, cheap) +OPENAI_MODEL=gpt-4 + +# ============================================================================ +# Anthropic Claude Configuration +# ============================================================================ +# Get your API key from: https://console.anthropic.com/ +ANTHROPIC_API_KEY=your-anthropic-api-key-here + +# Model options: +# - claude-3-5-sonnet-20241022 (best performance) +# - claude-3-haiku-20240307 (fast, cheap) +CLAUDE_MODEL=claude-3-5-sonnet-20241022 + +# ============================================================================ +# Hybrid Configuration +# ============================================================================ +# Confidence threshold for LLM fallback (0.0 - 1.0) +# If Rasa confidence < this value, use LLM +CONFIDENCE_THRESHOLD=0.7 + +# Ambiguity threshold for intent clarification +# If top 2 intents differ by less than this, clarify with LLM +AMBIGUITY_THRESHOLD=0.2 + +# Number of previous messages to include as context +CONTEXT_LENGTH=5 + +# ============================================================================ +# Advanced Settings +# ============================================================================ +# LLM temperature (0.0 = deterministic, 1.0 = creative) +LLM_TEMPERATURE=0.7 + +# Max tokens for LLM response +LLM_MAX_TOKENS=500 + +# Enable response caching (reduce API costs) +ENABLE_LLM_CACHE=true + +# Log LLM requests for debugging +LOG_LLM_REQUESTS=true diff --git a/CLASSIFICATION_VS_GENERATIVE_INTEGRATION_VI.md b/CLASSIFICATION_VS_GENERATIVE_INTEGRATION_VI.md new file mode 100644 index 000000000000..364b446305c6 --- /dev/null +++ b/CLASSIFICATION_VS_GENERATIVE_INTEGRATION_VI.md @@ -0,0 +1,1311 @@ +# Classification Model vs Generative Model & Tích Hợp Rasa + LLM + +## Mục Lục +1. [Classification Model Là Gì?](#classification-model-là-gì) +2. [Generative Model Là Gì?](#generative-model-là-gì) +3. [So Sánh Chi Tiết](#so-sánh-chi-tiết) +4. [Ví Dụ Thực Tế](#ví-dụ-thực-tế) +5. [Tích Hợp Rasa + LLM](#tích-hợp-rasa--llm) +6. [Best Practices](#best-practices) + +--- + +## Classification Model Là Gì? + +### Định Nghĩa Đơn Giản + +**Classification Model** = Model **phân loại** - chọn 1 nhãn từ tập hợp có sẵn. + +**Giống như:** +- Giáo viên chấm bài trắc nghiệm (A, B, C, D) +- Nhân viên phân loại thư (Hà Nội, TP.HCM, Đà Nẵng...) +- Bác sĩ chẩn đoán bệnh (Cúm, Covid, Viêm họng...) + +**Đặc điểm chính:** +- ✅ Output là **nhãn có sẵn** (pre-defined labels) +- ✅ Không tạo ra nội dung mới +- ✅ Chỉ "chọn" từ danh sách + +--- + +### Cách Hoạt Động + +``` +┌─────────────────────────────────────────────┐ +│ INPUT (Text) │ +│ "Tôi muốn đặt vé máy bay" │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ CLASSIFICATION MODEL │ +│ (Rasa DIETClassifier) │ +│ │ +│ Training đã học: │ +│ - Intent: greet │ +│ - Intent: book_flight ← Chọn cái này │ +│ - Intent: ask_price │ +│ - Intent: cancel_booking │ +│ - Intent: goodbye │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ OUTPUT (Label) │ +│ Intent: book_flight (confidence: 0.95) │ +└─────────────────────────────────────────────┘ +``` + +### Ví Dụ Cụ Thể Với Rasa + +#### Input: +``` +"Tôi muốn đặt vé máy bay đi Hà Nội" +``` + +#### Process: +```python +# Model đã được train với các labels: +labels = [ + "greet", + "goodbye", + "book_flight", # ← Đây! + "ask_price", + "cancel_booking" +] + +# Model chỉ CHỌN 1 trong số labels này +# KHÔNG tạo ra label mới +``` + +#### Output: +```json +{ + "intent": "book_flight", + "confidence": 0.95, + "entities": [ + { + "entity": "destination", + "value": "Hà Nội" + } + ] +} +``` + +**Lưu ý quan trọng:** +- ❌ Model KHÔNG generate text +- ❌ Model KHÔNG tạo ra intent mới +- ✅ Model CHỈ chọn từ danh sách đã train + +--- + +### Ưu Điểm Classification Model + +| Ưu Điểm | Giải Thích | +|---------|------------| +| **Predictable** | Output luôn nằm trong tập xác định | +| **Fast** | Chỉ cần tính score cho mỗi label | +| **Accurate** | Với đủ training data, accuracy cao | +| **Controlled** | Không bao giờ output ngoài ý muốn | +| **Lightweight** | Model nhỏ (10-100MB) | +| **Debuggable** | Dễ debug (xem confusion matrix) | + +### Nhược Điểm Classification Model + +| Nhược Điểm | Giải Thích | +|------------|------------| +| **Rigid** | Chỉ nhận biết intents đã train | +| **Limited** | Không xử lý được intents mới | +| **Manual** | Cần định nghĩa trước tất cả labels | +| **No Generation** | Không thể tạo responses tự nhiên | + +--- + +### Ví Dụ Thất Bại + +**Khi user hỏi điều chưa train:** + +``` +User: "Cho tôi biết thời tiết ở Paris hôm nay" + +Classification Model: +- Labels có sẵn: [greet, book_flight, ask_price, goodbye] +- KHÔNG có label "ask_weather" +→ Output: nlu_fallback (confidence: 0.3) +→ Bot: "Xin lỗi, tôi không hiểu" ❌ +``` + +**Giải pháp:** +- Thêm intent "ask_weather" vào training data +- Hoặc dùng LLM làm fallback + +--- + +## Generative Model Là Gì? + +### Định Nghĩa Đơn Giản + +**Generative Model** = Model **sáng tạo** - tạo ra nội dung mới. + +**Giống như:** +- Nhà văn viết truyện (tạo câu chuyện mới) +- Họa sĩ vẽ tranh (tạo hình ảnh mới) +- Nhạc sĩ sáng tác (tạo giai điệu mới) + +**Đặc điểm chính:** +- ✅ Output là **text hoàn toàn mới** (not pre-defined) +- ✅ Tạo ra nội dung chưa từng thấy +- ✅ Linh hoạt, sáng tạo + +--- + +### Cách Hoạt Động + +``` +┌─────────────────────────────────────────────┐ +│ INPUT (Text + Context) │ +│ "Tôi muốn đặt vé máy bay" │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ GENERATIVE MODEL (LLM) │ +│ (GPT-4, Claude) │ +│ │ +│ Không có labels định sẵn! │ +│ Model GENERATE từng từ một: │ +│ "Tôi" → "sẽ" → "giúp" → "bạn" → ... │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ OUTPUT (Generated Text) │ +│ "Tôi sẽ giúp bạn đặt vé máy bay. Để tìm │ +│ chuyến bay phù hợp, bạn có thể cho tôi │ +│ biết điểm đi, điểm đến và ngày khởi hành │ +│ không ạ?" │ +└─────────────────────────────────────────────┘ +``` + +### Quá Trình Generate + +**Step-by-step generation:** + +``` +Input: "Tôi muốn đặt vé máy bay" + +LLM generate từng token: +1. "Tôi" (probability: 0.95) +2. "sẽ" (probability: 0.89) +3. "giúp" (probability: 0.92) +4. "bạn" (probability: 0.94) +5. "đặt" (probability: 0.87) +6. "vé" (probability: 0.91) +7. "máy" (probability: 0.88) +8. "bay" (probability: 0.93) +9. "." (probability: 0.85) +10. "\n" +11. "Để" +12. "tìm" +... + +Final output: Hoàn chỉnh, tự nhiên, unique +``` + +### Ưu Điểm Generative Model + +| Ưu Điểm | Giải Thích | +|---------|------------| +| **Flexible** | Xử lý được mọi input, kể cả chưa thấy | +| **Natural** | Responses tự nhiên như người | +| **Creative** | Tạo variations khác nhau | +| **No Training Data** | Zero-shot, few-shot learning | +| **Contextual** | Hiểu context sâu | +| **Multi-task** | 1 model làm nhiều tasks | + +### Nhược Điểm Generative Model + +| Nhược Điểm | Giải Thích | +|------------|------------| +| **Unpredictable** | Output có thể khác nhau mỗi lần | +| **Hallucination** | Có thể "bịa" thông tin sai | +| **Slow** | Generate từng từ mất thời gian | +| **Expensive** | API costs cao | +| **Large** | Model rất lớn (14-350GB) | +| **Hard to Control** | Khó control exact behavior | + +--- + +### Ví Dụ Thành Công + +**Khi user hỏi điều chưa train:** + +``` +User: "Cho tôi biết thời tiết ở Paris hôm nay" + +Generative Model (LLM): +→ Generate: "Xin lỗi, tôi là chatbot hỗ trợ đặt vé máy bay + và không có khả năng tra cứu thời tiết thời + gian thực. Tôi có thể giúp bạn đặt vé bay đến + Paris thay vì không ạ?" ✅ +``` + +**Lợi ích:** +- ✅ Không cần train intent "ask_weather" +- ✅ Response tự nhiên, friendly +- ✅ Redirect về chức năng chính + +--- + +## So Sánh Chi Tiết + +### Table Tổng Hợp + +| Aspect | Classification Model (Rasa) | Generative Model (LLM) | +|--------|----------------------------|------------------------| +| **Cơ chế** | Chọn label từ danh sách | Tạo text từng từ | +| **Output** | Fixed labels | Free-form text | +| **Training** | Supervised với labels | Pre-training + prompting | +| **Flexibility** | Thấp (chỉ nhận biết intents đã train) | Cao (zero-shot) | +| **Predictability** | Cao (luôn 1 trong N labels) | Thấp (vô số outputs) | +| **Speed** | Nhanh (< 100ms) | Chậm (1-5s) | +| **Size** | Nhỏ (10-100MB) | Rất lớn (14-350GB) | +| **Cost** | Free (self-host) | Expensive (API) | +| **Accuracy** | Cao với đủ data | Varies | +| **Control** | Cao | Thấp | +| **Use Case** | Task-specific | General-purpose | + +--- + +### Ví Dụ So Sánh Trực Quan + +#### Scenario: User đặt câu hỏi + +**Input:** "Tôi muốn hủy chuyến bay đã đặt" + +--- + +**CLASSIFICATION MODEL (Rasa):** + +``` +┌─────────────────────────────────────┐ +│ Step 1: Intent Classification │ +├─────────────────────────────────────┤ +│ Input: "Tôi muốn hủy chuyến bay" │ +│ │ +│ Scores: │ +│ - greet: 0.02 │ +│ - book_flight: 0.05 │ +│ - cancel_booking: 0.93 ← WINNER │ +│ - ask_price: 0.03 │ +│ │ +│ Output: cancel_booking │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Step 2: Action Prediction │ +├─────────────────────────────────────┤ +│ TEDPolicy nhìn story: │ +│ - intent: cancel_booking │ +│ - action: action_confirm_cancel │ +│ │ +│ Output: action_confirm_cancel │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Step 3: Response Template │ +├─────────────────────────────────────┤ +│ Template: "Bạn có chắc muốn hủy │ +│ booking không?" │ +│ │ +│ Output: Fixed text │ +└─────────────────────────────────────┘ +``` + +**Đặc điểm:** +- ⚡ Fast (< 100ms total) +- 🎯 Predictable +- 📦 Controlled +- ❌ Rigid templates + +--- + +**GENERATIVE MODEL (LLM):** + +``` +┌─────────────────────────────────────┐ +│ Step 1: Understanding + Generation │ +├─────────────────────────────────────┤ +│ Input: "Tôi muốn hủy chuyến bay" │ +│ │ +│ LLM thinks: │ +│ - User wants to cancel │ +│ - Need confirmation │ +│ - Be empathetic │ +│ - Offer help │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Step 2: Generate Response │ +├─────────────────────────────────────┤ +│ Generating token by token... │ +│ "Tôi" → "hiểu" → "rồi" → "." │ +│ "Bạn" → "muốn" → "hủy" → ... │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Final Output │ +├─────────────────────────────────────┤ +│ "Tôi hiểu rồi. Bạn muốn hủy │ +│ chuyến bay đã đặt. Để tôi giúp │ +│ bạn, bạn có thể cung cấp mã đặt │ +│ chỗ hoặc thông tin chuyến bay │ +│ không? Tôi sẽ kiểm tra chính │ +│ sách hủy và hoàn tiền cho bạn." │ +└─────────────────────────────────────┘ +``` + +**Đặc điểm:** +- 🐌 Slower (1-5s) +- 🎨 Natural, varied +- 💡 Contextual +- ⚠️ Unpredictable + +--- + +### Analogy Dễ Hiểu + +**Classification Model = Nhà hàng buffet:** +- ✅ Món ăn có sẵn (labels) +- ✅ Bạn chọn từ menu +- ✅ Fast, predictable +- ❌ Không có món ngoài menu + +**Generative Model = Bếp trưởng Michelin:** +- ✅ Tạo món mới theo yêu cầu +- ✅ Creative, flexible +- ✅ Đáp ứng mọi request +- ❌ Slow, expensive + +--- + +## Ví Dụ Thực Tế + +### Case Study 1: Booking Chatbot + +**User Journey:** + +``` +1. User: "Xin chào" +2. User: "Tôi muốn đặt vé" +3. User: "Từ Hà Nội đi Sài Gòn" +4. User: "Ngày 15 tháng 12" +5. User: "Giá bao nhiêu?" +6. User: "OK, đặt luôn" +``` + +--- + +**Approach A: Pure Classification (Rasa Only)** + +```yaml +# domain.yml +intents: + - greet + - book_flight + - provide_info + - ask_price + - confirm + +responses: + utter_greet: + - text: "Xin chào! Tôi có thể giúp gì bạn?" + utter_ask_route: + - text: "Bạn muốn bay từ đâu đến đâu?" + utter_ask_date: + - text: "Bạn muốn bay vào ngày nào?" + # ... more templates +``` + +**Conversation:** +``` +1. User: "Xin chào" + Bot: "Xin chào! Tôi có thể giúp gì bạn?" [TEMPLATE] + +2. User: "Tôi muốn đặt vé" + Bot: "Bạn muốn bay từ đâu đến đâu?" [TEMPLATE] + +3. User: "Từ Hà Nội đi Sài Gòn" + Bot: "Bạn muốn bay vào ngày nào?" [TEMPLATE] + +4. User: "Ngày 15 tháng 12" + Bot: [Search flights...] + Bot: "Chuyến bay VN123: 2.500.000đ + Chuyến bay VJ456: 1.800.000đ" [TEMPLATE] + +5. User: "Giá bao nhiêu?" + Bot: "Như đã hiển thị ở trên: + - VN123: 2.500.000đ + - VJ456: 1.800.000đ" [TEMPLATE] + +6. User: "OK, đặt luôn" + Bot: "Bạn muốn đặt chuyến nào?" [TEMPLATE] +``` + +**Đánh giá:** +- ✅ Fast, reliable +- ✅ Follows strict flow +- ❌ Repetitive, robotic +- ❌ Không flexible + +--- + +**Approach B: Pure Generative (LLM Only)** + +**Conversation:** +``` +1. User: "Xin chào" + Bot: "Xin chào bạn! Tôi là trợ lý đặt vé máy bay. + Hôm nay tôi có thể giúp gì cho bạn?" [GENERATED] + +2. User: "Tôi muốn đặt vé" + Bot: "Tuyệt vời! Để tìm chuyến bay phù hợp nhất, + bạn có thể cho tôi biết: + - Điểm đi và điểm đến + - Ngày khởi hành dự kiến + - Số lượng hành khách" [GENERATED] + +3. User: "Từ Hà Nội đi Sài Gòn" + Bot: "Dạ, chuyến bay Hà Nội - TP. Hồ Chí Minh. + Bạn dự định bay vào ngày nào ạ?" [GENERATED] + +4. User: "Ngày 15 tháng 12" + Bot: [Function call: search_flights()] + Bot: "Tôi tìm thấy 2 chuyến bay phù hợp ngày 15/12: + + 1. Vietnam Airlines VN123 + - Khởi hành: 08:00 + - Đến: 10:15 + - Giá: 2.500.000đ + + 2. VietJet VJ456 + - Khởi hành: 14:30 + - Đến: 16:45 + - Giá: 1.800.000đ + + Bạn có muốn đặt chuyến nào không ạ?" [GENERATED] + +5. User: "Giá bao nhiêu?" + Bot: "Dạ, như tôi vừa thông tin ở trên: + - Chuyến VN123 của Vietnam Airlines: 2.500.000đ + - Chuyến VJ456 của VietJet: 1.800.000đ + + Bạn cần thông tin gì thêm không ạ?" [GENERATED] + +6. User: "OK, đặt luôn" + Bot: "Dạ vâng. Bạn muốn đặt chuyến nào trong 2 chuyến + trên ạ? VN123 (2.5tr) hay VJ456 (1.8tr)?" [GENERATED] +``` + +**Đánh giá:** +- ✅ Natural, friendly +- ✅ Contextual +- ✅ Flexible +- ❌ Slow (5-10s total) +- ❌ Expensive ($0.05 per conversation) +- ❌ Có thể đi off-topic + +--- + +**Approach C: Hybrid (Rasa + LLM) ⭐ RECOMMENDED** + +**Conversation:** +``` +1. User: "Xin chào" + [Rasa: intent=greet, confidence=0.98] + Bot: "Xin chào! Tôi có thể giúp gì bạn?" [RASA] + +2. User: "Tôi muốn đặt vé" + [Rasa: intent=book_flight, confidence=0.95] + Bot: "Bạn muốn bay từ đâu đến đâu?" [RASA] + +3. User: "Từ Hà Nội đi Sài Gòn" + [Rasa: entities extracted] + Bot: "Bạn muốn bay vào ngày nào?" [RASA] + +4. User: "Ngày 15 tháng 12" + [Rasa: date extracted] + Bot: [Search + display results] [RASA] + +5. User: "Ủa sao đắt thế? So với xe lửa thì sao?" + [Rasa: confidence=0.25, FALLBACK TO LLM] + Bot: "Tôi hiểu bạn quan tâm đến giá cả. Máy bay + tuy đắt hơn tàu hỏa nhưng tiết kiệm thời gian + (2 giờ vs 30 giờ). Tuy nhiên, tôi chỉ hỗ trợ + đặt vé máy bay. Bạn có muốn tiếp tục đặt vé + bay không ạ?" [LLM] + +6. User: "OK, đặt VJ456" + [Rasa: intent=confirm, confidence=0.92] + Bot: [Book ticket] [RASA] + Bot: "Đã đặt vé thành công!" [RASA] +``` + +**Đánh giá:** +- ✅ Fast (80% cases use Rasa) +- ✅ Cheap (LLM chỉ 20% cases) +- ✅ Controlled (Rasa handles main flow) +- ✅ Flexible (LLM handles edge cases) +- ⭐ **Best of both worlds!** + +--- + +## Tích Hợp Rasa + LLM + +### Tại Sao Nên Tích Hợp? + +**Rasa alone:** +- ✅ Fast, cheap, controlled +- ❌ Không flexible với unexpected inputs + +**LLM alone:** +- ✅ Flexible, natural +- ❌ Slow, expensive, unpredictable + +**Rasa + LLM:** +- ✅ 80% traffic → Rasa (fast, cheap) +- ✅ 20% edge cases → LLM (smart) +- ✅ Best user experience + +--- + +### Phương Pháp 1: LLM Fallback ⭐ + +**Concept:** Khi Rasa không tự tin → Gọi LLM + +**Architecture:** +``` +User Input + ↓ +Rasa NLU (DIETClassifier) + ↓ +Intent Confidence? + ├─ High (>0.7) → Rasa Actions [Fast] + └─ Low (<0.7) → LLM Fallback [Smart] +``` + +**Cấu hình:** + +```yaml +# config.yml +policies: + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: "action_llm_fallback" +``` + +**Custom Action:** + +```python +# actions/actions.py +from rasa_sdk import Action +from openai import OpenAI + +class ActionLLMFallback(Action): + def name(self): + return "action_llm_fallback" + + def run(self, dispatcher, tracker, domain): + # Lấy message của user + user_message = tracker.latest_message.get('text') + + # Build context từ conversation history + context = self._build_context(tracker) + + # Gọi LLM + client = OpenAI(api_key="your-key") + response = client.chat.completions.create( + model="gpt-4", + messages=[ + { + "role": "system", + "content": """Bạn là trợ lý đặt vé máy bay. + + QUY TẮC QUAN TRỌNG: + 1. CHỈ giúp đặt vé máy bay + 2. Nếu user hỏi ngoài topic, lịch sự chuyển hướng + 3. Ngắn gọn (tối đa 3 câu) + 4. Luôn hỏi rõ thông tin + + Ví dụ: + User: "Thời tiết Paris thế nào?" + Bot: "Tôi không có thông tin thời tiết, nhưng + tôi có thể giúp bạn đặt vé bay đến Paris. + Bạn có muốn xem các chuyến bay không?" + """ + }, + { + "role": "user", + "content": f"Ngữ cảnh: {context}\n\nUser: {user_message}" + } + ], + max_tokens=150, + temperature=0.7 + ) + + llm_text = response.choices[0].message.content + dispatcher.utter_message(text=llm_text) + + return [] + + def _build_context(self, tracker): + """Lấy 5 messages gần nhất để làm context""" + events = tracker.events[-10:] + context = "" + + for event in events: + if event.get('event') == 'user': + context += f"User: {event.get('text')}\n" + elif event.get('event') == 'bot': + context += f"Bot: {event.get('text')}\n" + + return context +``` + +**Example Flow:** + +``` +User: "Đặt vé từ Hà Nội đi Sài Gòn" +→ Rasa confidence: 0.95 +→ Use Rasa ✅ (< 100ms) +Bot: "Bạn muốn bay vào ngày nào?" + +User: "Ủa mà sao thời tiết Paris hôm nay thế?" +→ Rasa confidence: 0.15 +→ Use LLM ✅ (2s) +Bot: [LLM] "Xin lỗi, tôi không có thông tin thời tiết. + Tôi chỉ hỗ trợ đặt vé máy bay. Bạn có muốn tiếp + tục đặt vé đến Sài Gòn không?" +``` + +**Metrics:** +- ⚡ Rasa handles: 80% requests (< 100ms each) +- 🤖 LLM handles: 20% requests (1-2s each) +- 💰 Cost: ~$0.01 per conversation (vs $0.05 LLM-only) +- 📊 User satisfaction: Higher (gets answers for both) + +--- + +### Phương Pháp 2: LLM Response Enhancement + +**Concept:** Rasa làm logic, LLM làm đẹp responses + +**Architecture:** +``` +User Input + ↓ +Rasa NLU → Intent + Entities + ↓ +Rasa Core → Action to execute + ↓ +Action executes (DB query, API call) + ↓ +LLM → Generate natural response từ data + ↓ +User receives beautiful response +``` + +**Implementation:** + +```python +# actions/actions.py +class ActionShowFlights(Action): + def name(self): + return "action_show_flights" + + def run(self, dispatcher, tracker, domain): + # Lấy thông tin từ slots (Rasa extract) + departure = tracker.get_slot('departure') + destination = tracker.get_slot('destination') + date = tracker.get_slot('date') + + # Query database (Rasa logic) + flights = search_flights_db(departure, destination, date) + + # Prepare data + flights_data = { + "departure": departure, + "destination": destination, + "date": date, + "results": flights + } + + # LLM generate beautiful response + response = self._generate_response(flights_data) + + dispatcher.utter_message(text=response) + return [] + + def _generate_response(self, data): + """Dùng LLM để generate natural response""" + client = OpenAI(api_key="your-key") + + prompt = f""" + Tạo response thân thiện, chuyên nghiệp cho kết quả tìm vé. + + Thông tin tìm kiếm: + - Từ: {data['departure']} + - Đến: {data['destination']} + - Ngày: {data['date']} + + Các chuyến bay tìm được: + {json.dumps(data['results'], indent=2, ensure_ascii=False)} + + YÊU CẦU: + - Thân thiện, chuyên nghiệp + - Trình bày rõ ràng từng option + - Highlight ưu điểm của mỗi chuyến + - Hỏi user muốn chọn chuyến nào + - Dùng emoji phù hợp (🛫, 💰, ⏰) + """ + + response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": prompt}], + max_tokens=300 + ) + + return response.choices[0].message.content +``` + +**So sánh kết quả:** + +**BEFORE (Template):** +``` +Bot: "Tìm thấy 2 chuyến bay: + 1. VN123 - 08:00 - 2.500.000đ + 2. VJ456 - 14:30 - 1.800.000đ + Bạn chọn chuyến nào?" +``` + +**AFTER (LLM-enhanced):** +``` +Bot: "Tuyệt! Tôi tìm thấy 2 chuyến bay phù hợp từ Hà Nội + đến TP. Hồ Chí Minh vào ngày 15/12: + + 🛫 Buổi sáng - Vietnam Airlines VN123 + ⏰ Khởi hành: 08:00 → Đến: 10:15 + 💰 Giá vé: 2.500.000đ + ✨ Ưu điểm: Bay sớm, tiện đi làm, hãng uy tín + + 🛫 Buổi chiều - VietJet VJ456 + ⏰ Khởi hành: 14:30 → Đến: 16:45 + 💰 Giá vé: 1.800.000đ (rẻ hơn 700k!) + ✨ Ưu điểm: Giá tốt, thời gian linh hoạt + + Bạn thích chuyến nào hơn ạ? 😊" +``` + +**Lợi ích:** +- ✅ Response tự nhiên, friendly +- ✅ Dễ đọc, có cấu trúc +- ✅ Highlight thông tin quan trọng +- ✅ Vẫn có data accuracy (từ Rasa) + +--- + +### Phương Pháp 3: LLM Intent Clarification + +**Concept:** LLM giúp clarify khi Rasa không chắc + +**Use Case:** Multiple intents có confidence gần nhau + +**Implementation:** + +```python +class ActionClarifyIntent(Action): + def name(self): + return "action_clarify_intent" + + def run(self, dispatcher, tracker, domain): + user_message = tracker.latest_message.get('text') + + # Lấy top 3 intents từ Rasa + top_intents = tracker.latest_message['intent_ranking'][:3] + + # Nếu confidence gần nhau → Unclear + if top_intents[0]['confidence'] < 0.8 and \ + top_intents[1]['confidence'] > 0.4: + + # Ask LLM to clarify + client = OpenAI(api_key="your-key") + + prompt = f""" + User nói: "{user_message}" + + Possible intents (Rasa detected): + 1. {top_intents[0]['name']} (confidence: {top_intents[0]['confidence']:.2f}) + 2. {top_intents[1]['name']} (confidence: {top_intents[1]['confidence']:.2f}) + 3. {top_intents[2]['name']} (confidence: {top_intents[2]['confidence']:.2f}) + + Mô tả intents: + - book_flight: User muốn đặt vé máy bay + - cancel_booking: User muốn hủy booking + - reschedule_flight: User muốn đổi lịch bay + - ask_price: User hỏi giá vé + + Intent nào phù hợp NHẤT với câu nói của user? + + Trả lời CHỈ TÊN INTENT, không giải thích. + """ + + response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": prompt}], + max_tokens=10, + temperature=0.1 # Low temp for consistency + ) + + clarified_intent = response.choices[0].message.content.strip() + + # Use clarified intent + return [ + SlotSet("clarified_intent", clarified_intent), + FollowupAction(f"utter_{clarified_intent}") + ] + + else: + # Confidence high enough, use Rasa + return [] +``` + +**Example:** + +``` +User: "Tôi không muốn đi nữa" + +Rasa NLU: +- cancel_booking: 0.48 +- deny: 0.42 +- goodbye: 0.10 +→ Unclear! (top 2 gần nhau) + +LLM Clarification: +Prompt: "User said: 'Tôi không muốn đi nữa' + Intents: cancel_booking(0.48), deny(0.42), goodbye(0.10) + Which one?" + +Response: "cancel_booking" + +Action: +→ Trigger cancellation flow ✅ +``` + +--- + +### Phương Pháp 4: Hybrid Router + +**Concept:** Smart router quyết định Rasa hay LLM cho TOÀN BỘ request + +**Architecture:** +``` +┌─────────────────────────────────────┐ +│ User Input │ +└─────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────┐ +│ Smart Router (LLM-powered) │ +│ Quick classification: │ +│ - In-domain? → Rasa │ +│ - Out-of-domain? → LLM │ +│ - Chitchat? → LLM │ +└─────────────────────────────────────┘ + ↓ ↓ +┌─────────┐ ┌─────────┐ +│ Rasa │ │ LLM │ +│ Pipeline│ │ Direct │ +└─────────┘ └─────────┘ +``` + +**Implementation:** + +```python +class SmartRouter: + """Router thông minh chọn Rasa hoặc LLM""" + + def __init__(self): + self.rasa_agent = Agent.load("models/") + self.openai_client = OpenAI(api_key="your-key") + self.cache = {} # Cache domain checks + + async def route_message(self, user_message, sender_id): + """Main routing logic""" + + # Check domain (cached) + domain = self._check_domain(user_message) + + if domain == "in_domain": + # Use Rasa (fast, controlled) + return await self._rasa_response(user_message, sender_id) + else: + # Use LLM (flexible) + return await self._llm_response(user_message, sender_id) + + def _check_domain(self, message): + """Quick domain check với GPT-3.5 (cheap)""" + + # Check cache first + if message in self.cache: + return self.cache[message] + + # Quick LLM call + response = self.openai_client.chat.completions.create( + model="gpt-3.5-turbo", # Cheaper model for routing + messages=[{ + "role": "user", + "content": f""" + Chatbot này CHỈ hỗ trợ đặt vé máy bay. + + User message: "{message}" + + Câu này có liên quan đến đặt vé máy bay không? + - Đặt vé, hủy vé, đổi vé, hỏi giá → YES + - Thời tiết, tin tức, chitchat → NO + + Trả lời: YES hoặc NO + """ + }], + max_tokens=5, + temperature=0.1 + ) + + answer = response.choices[0].message.content.lower() + domain = "in_domain" if "yes" in answer else "out_domain" + + # Cache result + self.cache[message] = domain + + return domain + + async def _rasa_response(self, message, sender_id): + """Use Rasa pipeline""" + responses = await self.rasa_agent.handle_text(message, sender_id) + return responses[0]['text'] if responses else "Xin lỗi, tôi không hiểu." + + async def _llm_response(self, message, sender_id): + """Use LLM directly""" + response = self.openai_client.chat.completions.create( + model="gpt-4", + messages=[{ + "role": "system", + "content": """Bạn là trợ lý đặt vé máy bay. + Nếu user hỏi ngoài topic, lịch sự chuyển hướng.""" + }, { + "role": "user", + "content": message + }], + max_tokens=200 + ) + + return response.choices[0].message.content +``` + +**Example Flow:** + +``` +User: "Đặt vé đi Đà Nẵng" +→ Router check domain: "YES (in-domain)" +→ Route to: Rasa ⚡ +→ Response time: 80ms +→ Cost: $0 + +User: "Nói cho tôi nghe về lịch sử Paris" +→ Router check domain: "NO (out-domain)" +→ Route to: LLM 🤖 +→ Response time: 1.5s +→ Cost: $0.02 +``` + +**Metrics tracking:** + +```python +# Track usage +metrics = { + "total_requests": 0, + "rasa_count": 0, + "llm_count": 0, + "rasa_avg_latency": [], + "llm_avg_latency": [], +} + +# After routing +if used_rasa: + metrics["rasa_count"] += 1 +else: + metrics["llm_count"] += 1 + +# Alert if LLM > 30% +llm_percentage = metrics["llm_count"] / metrics["total_requests"] +if llm_percentage > 0.3: + alert("⚠️ High LLM usage! Check Rasa training data.") +``` + +--- + +## Best Practices + +### 1. Cost Optimization + +**A. Caching Responses** + +```python +# Simple cache +response_cache = {} + +def get_llm_response(prompt): + # Check cache + cache_key = hashlib.md5(prompt.encode()).hexdigest() + + if cache_key in response_cache: + return response_cache[cache_key] # Instant, free! + + # Call LLM + response = call_llm_api(prompt) + + # Cache it + response_cache[cache_key] = response + + return response +``` + +**Lợi ích:** +- 💰 Giảm 40-60% API costs +- ⚡ Response nhanh hơn (0ms vs 2s) + +**B. Model Selection** + +```python +# Routing decision +if need_reasoning: + model = "gpt-4" # $0.03/1K tokens +elif simple_task: + model = "gpt-3.5-turbo" # $0.001/1K tokens (30x cheaper!) +``` + +### 2. Confidence-Based Fallback + +**Tiered approach:** + +```python +def handle_message(message, rasa_result): + confidence = rasa_result['intent']['confidence'] + + if confidence > 0.85: + # Very confident → Use Rasa + return rasa_response(rasa_result) + + elif confidence > 0.6: + # Somewhat confident → Rasa with confirmation + return rasa_with_confirmation(rasa_result) + + elif confidence > 0.3: + # Low confidence → LLM clarify + return llm_clarify(message, rasa_result) + + else: + # Very low → Full LLM + return llm_fallback(message) +``` + +### 3. Monitoring & Alerting + +**Track key metrics:** + +```python +class MetricsTracker: + def __init__(self): + self.metrics = { + "requests_total": 0, + "rasa_handled": 0, + "llm_fallback": 0, + "rasa_confidence_avg": [], + "llm_cost_total": 0.0, + "response_time_avg": [], + } + + def log_request(self, used_rasa, confidence, latency, cost=0): + self.metrics["requests_total"] += 1 + + if used_rasa: + self.metrics["rasa_handled"] += 1 + self.metrics["rasa_confidence_avg"].append(confidence) + else: + self.metrics["llm_fallback"] += 1 + self.metrics["llm_cost_total"] += cost + + self.metrics["response_time_avg"].append(latency) + + # Check thresholds + self._check_alerts() + + def _check_alerts(self): + total = self.metrics["requests_total"] + llm_pct = self.metrics["llm_fallback"] / total + + # Alert if LLM usage too high + if llm_pct > 0.3: + send_alert(f"⚠️ LLM usage: {llm_pct*100:.1f}% (target: <30%)") + + # Alert if costs too high + if self.metrics["llm_cost_total"] > 10.0: # $10/day + send_alert(f"💰 LLM costs: ${self.metrics['llm_cost_total']:.2f}") +``` + +### 4. Prompt Engineering + +**Effective system prompts:** + +```python +SYSTEM_PROMPT = """ +Bạn là trợ lý đặt vé máy bay thông minh. + +QUY TẮC BẮT BUỘC: +1. CHỈ giúp về đặt vé máy bay (booking, hủy, đổi, giá) +2. Nếu user hỏi ngoài topic → Lịch sự từ chối + Redirect +3. Responses NGẮN GỌN (tối đa 3 câu) +4. Luôn hỏi thông tin CẦN THIẾT +5. KHÔNG BAO GIỜ bịa thông tin chuyến bay + +PHONG CÁCH: +- Thân thiện, chuyên nghiệp +- Dùng emoji phù hợp (🛫, ✈️, 💰) +- Gọi user bằng "bạn" + +VÍ DỤ TỐT: +User: "Thời tiết Paris thế nào?" +Bot: "Tôi không có thông tin thời tiết, nhưng tôi có thể + giúp bạn đặt vé bay đến Paris! Bạn muốn xem các + chuyến bay không? ✈️" + +VÍ DỤ XẤU: +Bot: "Xin lỗi tôi không biết về thời tiết." ← Không redirect! +""" +``` + +### 5. A/B Testing + +**Test different strategies:** + +```python +class ABTest: + def __init__(self): + self.strategies = { + "pure_rasa": {"count": 0, "satisfaction": []}, + "hybrid": {"count": 0, "satisfaction": []}, + } + + def route_user(self, user_id): + # 50/50 split + strategy = "hybrid" if hash(user_id) % 2 == 0 else "pure_rasa" + self.strategies[strategy]["count"] += 1 + return strategy + + def log_satisfaction(self, strategy, rating): + self.strategies[strategy]["satisfaction"].append(rating) + + def get_results(self): + for name, data in self.strategies.items(): + avg_satisfaction = sum(data["satisfaction"]) / len(data["satisfaction"]) + print(f"{name}: {avg_satisfaction:.2f}/5.0") +``` + +### 6. Error Handling + +**Graceful degradation:** + +```python +async def safe_llm_call(message): + try: + response = await call_llm_api(message, timeout=5) + return response + + except TimeoutError: + # LLM timeout → Fallback to default + return "Xin lỗi, tôi đang xử lý hơi chậm. Bạn có thể thử lại không?" + + except APIError as e: + # API error → Log and fallback + log_error(f"LLM API error: {e}") + return "Xin lỗi, hệ thống đang gặp sự cố. Vui lòng thử lại sau." + + except Exception as e: + # Unknown error + log_error(f"Unexpected error: {e}") + return "Xin lỗi, có lỗi xảy ra. Tôi sẽ chuyển bạn đến hỗ trợ." +``` + +--- + +## Tóm Tắt + +### Classification vs Generative - Tóm Gọn + +| | Classification (Rasa) | Generative (LLM) | +|---|----------------------|------------------| +| **Làm gì** | Chọn label | Tạo text | +| **Output** | Fixed | Free-form | +| **Speed** | Fast (< 100ms) | Slow (1-5s) | +| **Cost** | Free | Expensive | +| **Control** | High | Low | +| **Use case** | Task-specific | General | + +### Tích Hợp Rasa + LLM - 4 Phương Pháp + +1. **LLM Fallback** ⭐ RECOMMENDED + - Rasa 80%, LLM 20% + - Best balance + +2. **LLM Response Enhancement** + - Rasa logic + LLM beauty + - Natural responses + +3. **LLM Intent Clarification** + - LLM giúp khi unclear + - Better accuracy + +4. **Hybrid Router** + - Smart routing + - Optimal resource usage + +### Decision Framework + +``` +Bạn cần build chatbot? + ↓ +┌─────────────────────────┐ +│ Domain rõ ràng? │ +│ (booking, FAQ) │ +└─────────────────────────┘ + ├─ YES → Rasa + LLM Fallback ⭐ + │ (80% Rasa, 20% LLM) + │ + └─ NO → LLM-first + (Flexible, expensive) +``` + +### Key Takeaways + +✅ **Classification**: Fast, predictable, cheap - Dùng cho main flow +✅ **Generative**: Flexible, natural, expensive - Dùng cho edge cases +✅ **Hybrid**: Best of both worlds - RECOMMENDED +✅ **Monitor**: Track metrics để optimize + +--- + +**File đã tạo:** `CLASSIFICATION_VS_GENERATIVE_INTEGRATION_VI.md` + +**Nội dung:** +- ✅ Giải thích chi tiết Classification vs Generative +- ✅ Ví dụ thực tế từng approach +- ✅ 4 phương pháp tích hợp Rasa + LLM +- ✅ Code examples (không đi sâu implementation) +- ✅ Best practices & monitoring +- ✅ Decision framework + +Bạn có muốn tôi giải thích thêm phần nào không? 🤖 diff --git a/DOCKER_DEPLOYMENT_GUIDE_VI.md b/DOCKER_DEPLOYMENT_GUIDE_VI.md new file mode 100644 index 000000000000..f0120a817d06 --- /dev/null +++ b/DOCKER_DEPLOYMENT_GUIDE_VI.md @@ -0,0 +1,616 @@ +# Hướng Dẫn Triển Khai Rasa Chatbot Trên Docker + +## Mục Lục +1. [Giới Thiệu](#giới-thiệu) +2. [Yêu Cầu Hệ Thống](#yêu-cầu-hệ-thống) +3. [Cách 1: Sử Dụng Docker Image Có Sẵn](#cách-1-sử-dụng-docker-image-có-sẵn) +4. [Cách 2: Build Docker Image Từ Source](#cách-2-build-docker-image-từ-source) +5. [Cách 3: Triển Khai Với Docker Compose](#cách-3-triển-khai-với-docker-compose) +6. [Cấu Hình & Tùy Chỉnh](#cấu-hình--tùy-chỉnh) +7. [Các Lệnh Thường Dùng](#các-lệnh-thường-dùng) +8. [Troubleshooting](#troubleshooting) + +--- + +## Giới Thiệu + +Dự án này là **Rasa Open Source v3.6.21** - một framework mã nguồn mở để xây dựng chatbot thông minh với AI/ML. + +Rasa cho phép bạn tạo các trợ lý ảo có thể: +- Hiểu ngôn ngữ tự nhiên (NLU) +- Quản lý hội thoại đa lớp +- Tích hợp với nhiều nền tảng: Facebook Messenger, Slack, Telegram, v.v. + +--- + +## Yêu Cầu Hệ Thống + +### Phần Cứng Tối Thiểu +- **RAM**: 4GB (khuyến nghị 8GB+) +- **CPU**: 2 cores (khuyến nghị 4+ cores) +- **Disk**: 10GB trống + +### Phần Mềm +- **Docker**: phiên bản 20.10+ +- **Docker Compose**: phiên bản 1.29+ (tùy chọn) +- **Git**: để clone repository + +### Cài Đặt Docker + +**Ubuntu/Debian:** +```bash +# Cập nhật packages +sudo apt-get update + +# Cài đặt Docker +sudo apt-get install -y docker.io docker-compose + +# Thêm user vào group docker (để không cần sudo) +sudo usermod -aG docker $USER + +# Khởi động Docker +sudo systemctl start docker +sudo systemctl enable docker +``` + +**macOS:** +```bash +# Cài Docker Desktop từ: https://www.docker.com/products/docker-desktop +# Hoặc dùng Homebrew: +brew install --cask docker +``` + +**Windows:** +- Tải Docker Desktop: https://www.docker.com/products/docker-desktop + +--- + +## Cách 1: Sử Dụng Docker Image Có Sẵn + +Đây là cách nhanh nhất để chạy Rasa chatbot. + +### Bước 1: Chuẩn Bị Dự Án Chatbot + +```bash +# Tạo thư mục cho chatbot +mkdir my-chatbot +cd my-chatbot + +# Khởi tạo dự án Rasa mới (sử dụng Docker) +docker run -v $(pwd):/app rasa/rasa:3.6.21-full init --no-prompt +``` + +### Bước 2: Train Model + +```bash +# Train model với dữ liệu mẫu +docker run -v $(pwd):/app rasa/rasa:3.6.21-full train +``` + +### Bước 3: Chạy Chatbot + +```bash +# Chạy Rasa server +docker run -v $(pwd):/app -p 5005:5005 rasa/rasa:3.6.21-full run --enable-api + +# Hoặc chạy ở chế độ shell (tương tác) +docker run -it -v $(pwd):/app rasa/rasa:3.6.21-full shell +``` + +### Bước 4: Test Chatbot + +Mở terminal khác và test API: +```bash +curl -X POST http://localhost:5005/webhooks/rest/webhook \ + -H "Content-Type: application/json" \ + -d '{"message": "Hello", "sender": "test_user"}' +``` + +--- + +## Cách 2: Build Docker Image Từ Source + +Nếu bạn muốn tùy chỉnh hoặc phát triển Rasa từ source code. + +### Bước 1: Clone Repository + +```bash +git clone https://github.com/RasaHQ/rasa.git +cd rasa +``` + +### Bước 2: Build Docker Image + +```bash +# Build image với make (khuyến nghị) +make build-docker + +# Image sẽ có tag: rasa:localdev +``` + +**Hoặc build thủ công:** +```bash +docker build -t my-rasa:latest \ + --build-arg IMAGE_BASE_NAME=rasa \ + --build-arg BASE_IMAGE_HASH=latest \ + --build-arg BASE_BUILDER_IMAGE_HASH=latest \ + -f Dockerfile . +``` + +### Bước 3: Chạy Image Đã Build + +```bash +# Chạy với image vừa build +docker run -it -v $(pwd)/examples/moodbot:/app \ + -p 5005:5005 rasa:localdev shell + +# Hoặc chạy server +docker run -v $(pwd)/examples/moodbot:/app \ + -p 5005:5005 rasa:localdev run --enable-api +``` + +--- + +## Cách 3: Triển Khai Với Docker Compose + +Docker Compose giúp quản lý nhiều container (Rasa server, Action server, Database, v.v.) + +### Bước 1: Tạo File docker-compose.yml + +Tạo file `docker-compose.yml` trong thư mục dự án: + +```yaml +version: '3.8' + +services: + # Rasa Server + rasa: + image: rasa/rasa:3.6.21-full + container_name: rasa-server + ports: + - "5005:5005" + volumes: + - ./:/app + command: + - run + - --enable-api + - --cors + - "*" + - --debug + networks: + - rasa-network + + # Rasa Action Server (cho custom actions) + action-server: + image: rasa/rasa-sdk:3.6.2 + container_name: rasa-action-server + ports: + - "5055:5055" + volumes: + - ./actions:/app/actions + networks: + - rasa-network + + # Duckling (cho entity extraction - dates, numbers, etc.) + duckling: + image: rasa/duckling:latest + container_name: rasa-duckling + ports: + - "8000:8000" + networks: + - rasa-network + +networks: + rasa-network: + driver: bridge +``` + +### Bước 2: Chuẩn Bị Cấu Trúc Thư Mục + +```bash +# Cấu trúc thư mục chatbot +my-chatbot/ +├── docker-compose.yml +├── domain.yml +├── config.yml +├── credentials.yml +├── endpoints.yml +├── data/ +│ ├── nlu.yml +│ └── stories.yml +├── actions/ +│ ├── __init__.py +│ └── actions.py +└── models/ +``` + +### Bước 3: Cấu Hình endpoints.yml + +Tạo file `endpoints.yml` để kết nối với Action Server: + +```yaml +action_endpoint: + url: "http://action-server:5055/webhook" +``` + +### Bước 4: Train Model + +```bash +# Train model trước khi start services +docker-compose run rasa train +``` + +### Bước 5: Khởi Động Services + +```bash +# Start tất cả services +docker-compose up -d + +# Xem logs +docker-compose logs -f rasa + +# Kiểm tra status +docker-compose ps +``` + +### Bước 6: Test Chatbot + +```bash +# Test qua REST API +curl -X POST http://localhost:5005/webhooks/rest/webhook \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Xin chào", + "sender": "user123" + }' + +# Test interactive shell +docker-compose exec rasa rasa shell +``` + +--- + +## Cấu Hình & Tùy Chỉnh + +### 1. Cấu Hình Pipeline NLU (config.yml) + +```yaml +language: vi # Ngôn ngữ tiếng Việt + +pipeline: + - name: WhitespaceTokenizer + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + - name: CountVectorsFeaturizer + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 1 + max_ngram: 4 + - name: DIETClassifier + epochs: 100 + - name: EntitySynonymMapper + - name: ResponseSelector + epochs: 100 + +policies: + - name: MemoizationPolicy + - name: TEDPolicy + max_history: 5 + epochs: 100 + - name: RulePolicy +``` + +### 2. Environment Variables + +Thêm vào `docker-compose.yml`: + +```yaml +services: + rasa: + environment: + - RASA_TELEMETRY_ENABLED=false + - RASA_LOG_LEVEL=DEBUG + - RASA_MODEL=/app/models +``` + +### 3. Persistent Storage cho Models + +```yaml +services: + rasa: + volumes: + - ./:/app + - ./models:/app/models + - rasa-data:/tmp/rasa + +volumes: + rasa-data: +``` + +### 4. Sử Dụng Database (PostgreSQL) + +Thêm PostgreSQL vào `docker-compose.yml`: + +```yaml +services: + postgres: + image: postgres:13-alpine + container_name: rasa-postgres + environment: + POSTGRES_DB: rasa + POSTGRES_USER: rasa + POSTGRES_PASSWORD: rasa123 + volumes: + - postgres-data:/var/lib/postgresql/data + networks: + - rasa-network + + rasa: + depends_on: + - postgres + environment: + - DB_HOST=postgres + - DB_PORT=5432 + - DB_USER=rasa + - DB_PASSWORD=rasa123 + - DB_DATABASE=rasa + +volumes: + postgres-data: +``` + +Cập nhật `endpoints.yml`: +```yaml +tracker_store: + type: SQL + dialect: postgresql + url: postgres + port: 5432 + db: rasa + username: rasa + password: rasa123 +``` + +--- + +## Các Lệnh Thường Dùng + +### Quản Lý Container + +```bash +# Xem danh sách containers đang chạy +docker-compose ps + +# Start services +docker-compose up -d + +# Stop services +docker-compose down + +# Restart services +docker-compose restart + +# Xem logs +docker-compose logs -f rasa +docker-compose logs -f action-server + +# Stop và xóa tất cả (bao gồm volumes) +docker-compose down -v +``` + +### Rasa Commands + +```bash +# Train model +docker-compose run rasa train + +# Train NLU only +docker-compose run rasa train nlu + +# Test model +docker-compose run rasa test + +# Interactive learning +docker-compose run rasa interactive + +# Shell mode +docker-compose exec rasa rasa shell + +# Validate domain và data +docker-compose run rasa data validate + +# Visualize stories +docker-compose run rasa visualize +``` + +### Debug & Development + +```bash +# Vào container shell +docker-compose exec rasa bash + +# Xem Rasa version +docker-compose run rasa --version + +# Test NLU model +docker-compose run rasa shell nlu + +# Run với debug mode +docker-compose run rasa run --enable-api --debug --cors "*" +``` + +--- + +## Troubleshooting + +### Lỗi: Port 5005 đã được sử dụng + +```bash +# Tìm process đang dùng port +sudo lsof -i :5005 + +# Hoặc kill process +sudo kill -9 $(sudo lsof -t -i:5005) + +# Hoặc đổi port trong docker-compose.yml +ports: + - "5006:5005" # Host:Container +``` + +### Lỗi: Model không load được + +```bash +# Kiểm tra xem model có tồn tại không +docker-compose exec rasa ls -la /app/models/ + +# Train lại model +docker-compose run rasa train --force + +# Xóa old models và train lại +rm -rf models/* +docker-compose run rasa train +``` + +### Lỗi: Action server không kết nối được + +```bash +# Kiểm tra action server đang chạy +docker-compose ps action-server + +# Check logs +docker-compose logs action-server + +# Test connection từ rasa container +docker-compose exec rasa curl http://action-server:5055/health +``` + +### Lỗi: Out of Memory + +Tăng memory limit trong `docker-compose.yml`: + +```yaml +services: + rasa: + deploy: + resources: + limits: + memory: 2G + reservations: + memory: 1G +``` + +### Lỗi: Permission denied với volumes + +```bash +# Fix permissions +sudo chown -R $USER:$USER ./ +chmod -R 755 ./ + +# Hoặc thêm user vào docker-compose.yml +services: + rasa: + user: "${UID}:${GID}" +``` + +### Debugging Tips + +1. **Xem logs chi tiết:** +```bash +docker-compose logs -f --tail=100 rasa +``` + +2. **Test API endpoint:** +```bash +# Health check +curl http://localhost:5005/ + +# Model info +curl http://localhost:5005/status +``` + +3. **Rebuild khi có thay đổi code:** +```bash +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` + +--- + +## Ví Dụ Chatbot Hoàn Chỉnh + +### 1. Sử dụng Moodbot Example + +```bash +# Copy moodbot example +cp -r examples/moodbot ./my-moodbot +cd my-moodbot + +# Train +docker run -v $(pwd):/app rasa/rasa:3.6.21-full train + +# Run +docker run -it -v $(pwd):/app -p 5005:5005 \ + rasa/rasa:3.6.21-full shell +``` + +### 2. Deploy Production với Nginx Reverse Proxy + +Tạo `docker-compose.prod.yml`: + +```yaml +version: '3.8' + +services: + nginx: + image: nginx:alpine + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - rasa + networks: + - rasa-network + + rasa: + image: rasa/rasa:3.6.21-full + command: + - run + - --enable-api + - --cors + - "*" + networks: + - rasa-network + +networks: + rasa-network: +``` + +--- + +## Tài Liệu Tham Khảo + +- **Rasa Documentation**: https://rasa.com/docs/rasa/ +- **Docker Documentation**: https://docs.docker.com/ +- **Rasa Docker Images**: https://hub.docker.com/r/rasa/rasa +- **Rasa Community Forum**: https://forum.rasa.com/ + +--- + +## Kết Luận + +Bạn đã hoàn thành hướng dẫn triển khai Rasa Chatbot trên Docker! + +**Các bước tiếp theo:** +1. Tùy chỉnh `domain.yml` và `data/` cho use case của bạn +2. Phát triển custom actions trong `actions/actions.py` +3. Train và test model thường xuyên +4. Deploy lên production server + +**Cần trợ giúp?** +- GitHub Issues: https://github.com/RasaHQ/rasa/issues +- Rasa Community: https://forum.rasa.com/ + +Chúc bạn xây dựng chatbot thành công! 🚀 diff --git a/IT_STORE_DEMO_GUIDE_VI.md b/IT_STORE_DEMO_GUIDE_VI.md new file mode 100644 index 000000000000..4c8c099836d6 --- /dev/null +++ b/IT_STORE_DEMO_GUIDE_VI.md @@ -0,0 +1,499 @@ +# Hướng Dẫn Demo Web Frontend - TechStore AI Chatbot + +## 📋 Tổng Quan + +Web frontend chuyên nghiệp để demo chatbot AI tư vấn sản phẩm IT cho khách hàng. Hệ thống bán các sản phẩm công nghệ thông tin như: + +- 💻 **Máy tính & Laptop** (Gaming, Văn phòng, Workstation) +- 🖥️ **Máy chủ** (Dell, HP, Lenovo) +- 🔌 **Switch mạng** (Cisco, HPE) +- 📹 **Camera an ninh** (Hikvision, Dahua) +- 💿 **Phần mềm thương mại** (Windows, Office, Antivirus, CAD) + +## 🎯 Tính Năng Chatbot AI + +### 1. **Tìm Kiếm Thông Minh** +- Tìm sản phẩm theo loại, thương hiệu, giá cả +- Tìm theo thông số kỹ thuật (CPU, RAM, số port, độ phân giải...) +- Tìm theo nhu cầu sử dụng (gaming, văn phòng, doanh nghiệp...) + +**Ví dụ:** +``` +- "Tìm laptop gaming dưới 30 triệu" +- "Máy chủ Dell cho doanh nghiệp" +- "Camera 4MP có AI" +- "Switch 48 port managed" +``` + +### 2. **So Sánh Sản Phẩm** +- So sánh chi tiết 2-3 sản phẩm +- Hiển thị khác biệt về cấu hình, giá cả +- Phân tích ưu nhược điểm + +**Ví dụ:** +``` +- "So sánh Dell PowerEdge R740 và HP ProLiant DL380" +- "ASUS ROG khác MSI Katana gì?" +- "So sánh giá laptop gaming" +``` + +### 3. **Tư Vấn Chuyên Nghiệp** +- Gợi ý sản phẩm phù hợp với mục đích sử dụng +- Tư vấn dựa trên ngân sách +- Gợi ý giải pháp trọn gói + +**Ví dụ:** +``` +- "Tư vấn laptop cho sinh viên IT" +- "Giải pháp camera cho văn phòng 500m2" +- "Máy chủ phù hợp cho startup 20 người" +``` + +### 4. **Thông Số Kỹ Thuật** +- Giải thích chi tiết cấu hình +- Tư vấn về khả năng tương thích +- Hướng dẫn chọn sản phẩm + +**Ví dụ:** +``` +- "Dell R740 có cấu hình gì?" +- "Switch managed khác unmanaged như thế nào?" +- "Camera AcuSense là gì?" +``` + +### 5. **Báo Giá & Khuyến Mãi** +- Kiểm tra giá sản phẩm +- Thông tin khuyến mãi hiện hành +- Báo giá số lượng lớn + +**Ví dụ:** +``` +- "Giá máy chủ HP ProLiant" +- "Có khuyến mãi laptop không?" +- "Mua 10 camera giảm bao nhiêu?" +``` + +### 6. **Hỗ Trợ Kỹ Thuật** +- Hướng dẫn cài đặt +- Khắc phục sự cố +- Chính sách bảo hành + +**Ví dụ:** +``` +- "Hướng dẫn cài Windows Server" +- "Cấu hình switch Cisco" +- "Bảo hành máy chủ như thế nào?" +``` + +## 🚀 Cách Chạy Demo + +### Phương Án 1: Demo Không Cần Rasa Server (Standalone) + +Frontend có sẵn chế độ demo với câu trả lời mẫu, không cần chạy Rasa server. + +```bash +# Mở file frontend/index.html bằng trình duyệt +cd frontend +# Trên macOS +open index.html + +# Trên Linux +xdg-open index.html + +# Hoặc Windows +start index.html +``` + +**Lưu ý:** Ở chế độ này, chatbot sẽ trả lời bằng logic JavaScript có sẵn (không kết nối Rasa). + +### Phương Án 2: Demo Đầy Đủ với Rasa Server + +Để chatbot hoạt động với AI thật sự: + +#### Bước 1: Training Chatbot + +```bash +# Di chuyển vào thư mục IT store bot +cd examples/it_store_bot + +# Training model +rasa train + +# Kết quả: Model được lưu trong thư mục models/ +``` + +#### Bước 2: Chạy Rasa Action Server + +```bash +# Terminal 1: Chạy action server +cd examples/it_store_bot +rasa run actions --port 5055 +``` + +#### Bước 3: Chạy Rasa Server + +```bash +# Terminal 2: Chạy Rasa server +cd examples/it_store_bot +rasa run --enable-api --cors "*" --port 5005 +``` + +#### Bước 4: Mở Web Frontend + +```bash +# Mở frontend/index.html bằng trình duyệt +# Hoặc sử dụng Python HTTP server +cd frontend +python3 -m http.server 8000 + +# Truy cập: http://localhost:8000 +``` + +## 📱 Hướng Dẫn Demo Cho Khách Hàng + +### Kịch Bản Demo 1: Tìm Laptop Gaming + +1. **Mở chat widget** (click nút chat góc dưới phải) +2. **Nhập:** "Tôi cần laptop gaming dưới 30 triệu" +3. **Chatbot hiển thị:** + - 2-3 sản phẩm phù hợp + - Giá cả, cấu hình + - Tình trạng còn hàng + - Khuyến mãi (nếu có) +4. **Hỏi thêm:** "So sánh ASUS ROG và MSI Katana" +5. **Chatbot so sánh** chi tiết 2 sản phẩm + +### Kịch Bản Demo 2: Tư Vấn Máy Chủ Doanh Nghiệp + +1. **Nhập:** "Tư vấn máy chủ cho doanh nghiệp 50 nhân viên" +2. **Chatbot hỏi thêm về:** + - Ngân sách + - Mục đích sử dụng (file server, web server, database...) + - Yêu cầu đặc biệt +3. **Chatbot đề xuất:** + - 2-3 máy chủ phù hợp + - Giải thích lý do chọn + - Dịch vụ đi kèm + +### Kịch Bản Demo 3: Giải Pháp Camera An Ninh + +1. **Nhập:** "Tư vấn giải pháp camera cho văn phòng 500m2" +2. **Chatbot phân tích:** + - Diện tích cần giám sát + - Số lượng camera đề xuất + - Thiết bị cần thiết (NVR, HDD, cáp...) +3. **Chatbot báo giá:** + - Gói trọn bộ + - Giá từng sản phẩm + - Khuyến mãi bundle + - Chi phí lắp đặt + +### Kịch Bản Demo 4: So Sánh Switch Mạng + +1. **Nhập:** "So sánh Cisco Catalyst và HPE OfficeConnect" +2. **Chatbot hiển thị:** + - Bảng so sánh chi tiết + - Số port, tốc độ, tính năng + - Chênh lệch giá + - Ưu nhược điểm +3. **Gợi ý:** Nên chọn sản phẩm nào dựa vào nhu cầu + +### Kịch Bản Demo 5: Hỗ Trợ Kỹ Thuật + +1. **Nhập:** "Hướng dẫn cài đặt Windows Server" +2. **Chatbot cung cấp:** + - Link tài liệu hướng dẫn + - Video tutorial + - Dịch vụ hỗ trợ từ xa + - Hotline kỹ thuật + +## 🎨 Giao Diện Web + +### Trang Chủ (Hero Section) +- **Tiêu đề nổi bật:** TechStore AI +- **Slogan:** "Trợ Lý AI Tư Vấn Sản Phẩm IT" +- **CTA Button:** "Bắt Đầu Tư Vấn Ngay" +- **Floating cards:** Hiển thị 4 danh mục chính + +### Danh Mục Sản Phẩm +- **6 category cards:** + 1. Máy Tính & Laptop + 2. Máy Chủ (Server) + 3. Switch Mạng + 4. Camera An Ninh + 5. Phần Mềm + 6. Linh Kiện +- **Click vào card** → Tự động mở chat và hỏi về danh mục đó + +### Tính Năng Chatbot (Features Section) +- **6 feature cards** với ví dụ thực tế: + 1. Tìm Kiếm Thông Minh + 2. So Sánh Sản Phẩm + 3. Tư Vấn Chuyên Nghiệp + 4. Thông Số Kỹ Thuật + 5. Báo Giá & Khuyến Mãi + 6. Hỗ Trợ Kỹ Thuật +- **"Xem ví dụ" button** → Demo câu hỏi mẫu + +### Thống Kê (Stats Section) +- **5000+ Sản Phẩm** +- **95% Độ Chính Xác** +- **24/7 Hoạt Động** +- **<3s Thời Gian Phản Hồi** + +### Chat Widget +- **Vị trí:** Góc dưới bên phải +- **Tính năng:** + - Avatar bot với icon robot + - Status: "Đang hoạt động" + - Typing indicator + - Quick replies (gợi ý nhanh) + - Message formatting (bold, bullets) + - Product cards + +## 📊 Database Sản Phẩm Demo + +### Laptop (4 sản phẩm) +1. **ASUS ROG Strix G15** - Gaming - 28,990,000đ +2. **MSI Katana GF66** - Gaming - 24,990,000đ +3. **Dell Latitude 5420** - Văn phòng - 15,990,000đ +4. **HP ProBook 450 G9** - Văn phòng - 21,490,000đ + +### Máy Chủ (3 sản phẩm) +1. **Dell PowerEdge R740** - 145,000,000đ +2. **HP ProLiant DL380 Gen10** - 98,000,000đ +3. **Lenovo ThinkSystem SR650** - 112,000,000đ + +### Switch (2 sản phẩm) +1. **Cisco Catalyst 2960-X 48 Port** - 42,500,000đ +2. **HPE OfficeConnect 1920S 48G** - 18,900,000đ + +### Camera (2 sản phẩm) +1. **Hikvision DS-2CD2143G2-I** - 2,890,000đ +2. **Dahua IPC-HDW3441TM-AS** - 1,990,000đ + +### Phần Mềm (3 sản phẩm) +1. **Windows 11 Pro** - 5,490,000đ +2. **Windows Server 2022 Standard** - 24,900,000đ +3. **Office 2021 Professional Plus** - 8,900,000đ + +## 🔧 Tùy Chỉnh + +### Thêm Sản Phẩm Mới + +Chỉnh sửa file: `examples/it_store_bot/actions/actions_it_store.py` + +```python +PRODUCT_DATABASE = { + "laptop": [ + { + "id": "LP005", + "name": "Lenovo ThinkPad X1 Carbon", + "brand": "Lenovo", + "category": "laptop", + "type": "office", + "price": 35990000, + "specs": { + "cpu": "Intel i7-1260P", + "ram": "16GB LPDDR5", + "storage": "512GB NVMe SSD", + "display": "14\" 2.8K OLED" + }, + "stock": True, + "warranty": "36 tháng", + "promotion": None + }, + # Thêm sản phẩm khác... + ] +} +``` + +### Thay Đổi Màu Sắc & Branding + +Chỉnh sửa file: `frontend/style.css` + +```css +:root { + --primary-color: #2563eb; /* Màu chủ đạo */ + --secondary-color: #10b981; /* Màu phụ */ + --accent-color: #f59e0b; /* Màu nhấn */ +} +``` + +### Thay Đổi Logo & Tên Công Ty + +Chỉnh sửa file: `frontend/index.html` + +```html + +``` + +## 🌐 Triển Khai Production + +### Bước 1: Deploy Rasa Server + +```bash +# Sử dụng Docker +docker run -p 5005:5005 \ + -v $(pwd)/examples/it_store_bot:/app \ + rasa/rasa:3.6.21-full \ + run --enable-api --cors "*" +``` + +### Bước 2: Deploy Action Server + +```bash +docker run -p 5055:5055 \ + -v $(pwd)/examples/it_store_bot/actions:/app/actions \ + rasa/rasa-sdk:3.6.0 +``` + +### Bước 3: Deploy Frontend + +Upload thư mục `frontend/` lên web hosting hoặc: + +```bash +# Sử dụng Nginx +docker run -p 80:80 \ + -v $(pwd)/frontend:/usr/share/nginx/html \ + nginx:alpine +``` + +### Bước 4: Cập Nhật URL Server + +Chỉnh sửa `frontend/script.js`: + +```javascript +const RASA_SERVER_URL = 'https://your-rasa-server.com'; +``` + +## 📝 Training Thêm Dữ Liệu + +### Thêm Intent Mới + +File: `examples/it_store_bot/data/nlu.yml` + +```yaml +- intent: ask_delivery + examples: | + - giao hàng mất bao lâu + - ship hàng thế nào + - phí vận chuyển + - có giao hàng miễn phí không +``` + +### Thêm Response + +File: `examples/it_store_bot/domain.yml` + +```yaml +responses: + utter_delivery_info: + - text: | + 🚚 Chính sách giao hàng: + • Miễn phí trong nội thành (<50km) + • 1-2 ngày cho sản phẩm thường + • 3-5 ngày cho máy chủ (cần kiểm tra kỹ) +``` + +### Training Lại + +```bash +cd examples/it_store_bot +rasa train +# Restart Rasa server để load model mới +``` + +## 🎯 Tips Demo Hiệu Quả + +### 1. **Chuẩn Bị Trước** +- ✅ Kiểm tra Rasa server đang chạy +- ✅ Test 3-4 câu hỏi mẫu +- ✅ Chuẩn bị backup plan (demo standalone) + +### 2. **Trong Lúc Demo** +- 🎤 Giải thích từng tính năng khi demo +- 💡 Nhấn mạnh lợi ích cho khách hàng: + - Tiết kiệm thời gian tư vấn + - Tăng tỷ lệ chuyển đổi + - Hỗ trợ 24/7 + - Giảm chi phí nhân sự + +### 3. **Xử Lý Lỗi** +- Nếu Rasa server down → Chuyển sang demo standalone +- Nếu chatbot không hiểu → Giải thích "đang training thêm data" +- Nếu trả lời sai → Ghi nhận feedback để cải thiện + +### 4. **Kết Thúc Demo** +- 📊 Trình bày số liệu: accuracy, response time +- 💰 Báo giá triển khai +- 📅 Đề xuất lộ trình: POC → Pilot → Production + +## 🔗 Tích Hợp Thêm + +### Tích Hợp LLM (OpenAI/Claude) + +Sử dụng module LLM đã tạo trước đó: + +```bash +# Copy LLM module vào IT store bot +cp -r actions/llm examples/it_store_bot/actions/ + +# Cấu hình trong domain.yml +actions: + - action_llm_fallback + - action_search_product # existing +``` + +### Tích Hợp Database Thật + +Thay thế `PRODUCT_DATABASE` bằng: + +```python +import pymongo +# hoặc +import mysql.connector + +def search_products(product_type, ...): + # Query database thật + cursor = db.products.find({ + "category": product_type, + "price": {"$lte": price_max} + }) + return list(cursor) +``` + +### Tích Hợp CRM/ERP + +```python +def notify_sales_team(customer_query, products_viewed): + """Thông báo cho sales team khi có khách hỏi""" + # Gửi webhook đến CRM + requests.post("https://your-crm.com/webhook", json={ + "query": customer_query, + "products": products_viewed, + "timestamp": datetime.now() + }) +``` + +## 📞 Hỗ Trợ + +Nếu cần hỗ trợ kỹ thuật: +- 📧 Email: support@techstore.vn +- 💬 Slack/Teams channel +- 📚 Docs: Xem các file guide khác trong repo + +## 🎉 Kết Luận + +Web frontend này cung cấp: +- ✅ Giao diện chuyên nghiệp, hiện đại +- ✅ 6 tính năng chatbot AI đầy đủ +- ✅ Database sản phẩm IT demo +- ✅ Standalone mode (không cần Rasa) +- ✅ Dễ dàng tùy chỉnh & mở rộng +- ✅ Kịch bản demo rõ ràng + +**Sẵn sàng để demo cho khách hàng ngay!** 🚀 diff --git a/LLM_INTEGRATION_GUIDE_VI.md b/LLM_INTEGRATION_GUIDE_VI.md new file mode 100644 index 000000000000..e129c8a3bd91 --- /dev/null +++ b/LLM_INTEGRATION_GUIDE_VI.md @@ -0,0 +1,528 @@ +# Hướng Dẫn Tích Hợp LLM (OpenAI/Claude) Với Rasa + +## Tổng Quan + +Module này cung cấp tích hợp hoàn chỉnh giữa Rasa và các LLMs (OpenAI GPT-4, Claude AI) theo phương án **Hybrid** - kết hợp điểm mạnh của cả hai. + +### Kiến Trúc + +``` +User Input + ↓ +┌─────────────────────────────────┐ +│ Rasa NLU (DIETClassifier) │ +│ - Intent classification │ +│ - Entity extraction │ +└─────────────────────────────────┘ + ↓ +Confidence Check + ├─ High (>0.7) → Rasa Actions ⚡ + │ (Fast, controlled) + │ + └─ Low (<0.7) → LLM Fallback 🤖 + (Smart, flexible) +``` + +--- + +## Cài Đặt + +### Bước 1: Cài Dependencies + +```bash +# Cài đặt dependencies cho LLM +pip install -r config/llm_requirements.txt + +# Hoặc cài thủ công +pip install openai anthropic python-dotenv rasa-sdk +``` + +### Bước 2: Cấu Hình API Keys + +```bash +# Copy file example +cp .env.example .env + +# Edit .env và thêm API keys +nano .env +``` + +**File `.env`:** +```bash +# Chọn provider +LLM_PROVIDER=openai # or 'claude' + +# OpenAI API Key +OPENAI_API_KEY=sk-your-api-key-here + +# Or Claude API Key +ANTHROPIC_API_KEY=your-claude-key-here + +# Thresholds +CONFIDENCE_THRESHOLD=0.7 +AMBIGUITY_THRESHOLD=0.2 +``` + +**Lấy API Keys:** +- OpenAI: https://platform.openai.com/api-keys +- Claude: https://console.anthropic.com/ + +### Bước 3: Cấu Trúc Thư Mục + +``` +rasa_chatbot/ +├── actions/ +│ ├── llm/ # LLM integration module +│ │ ├── __init__.py +│ │ ├── providers.py # OpenAI + Claude providers +│ │ ├── fallback.py # LLM fallback handler +│ │ ├── response_enhancer.py +│ │ └── intent_clarifier.py +│ └── actions_llm.py # Custom Rasa actions +│ +├── examples/hybrid_bot/ # Example hybrid bot +│ ├── config.yml +│ ├── domain.yml +│ ├── endpoints.yml +│ └── data/ +│ +├── config/ +│ └── llm_requirements.txt +│ +└── .env # API keys (create from .env.example) +``` + +--- + +## Sử Dụng + +### Quick Start + +```bash +# 1. Train Rasa model +cd examples/hybrid_bot +rasa train + +# 2. Start action server (in terminal 1) +rasa run actions + +# 3. Start Rasa (in terminal 2) +rasa shell + +# Test conversation +You: Xin chào +Bot: Xin chào! Tôi là trợ lý đặt vé máy bay... + +You: Thời tiết Paris thế nào? +Bot: [LLM Fallback] Tôi không có thông tin thời tiết, + nhưng tôi có thể giúp bạn đặt vé bay đến Paris! ✈️ +``` + +--- + +## Các Tính Năng + +### 1. LLM Fallback ⭐ + +**Khi dùng:** +- Rasa confidence < 0.7 +- User hỏi câu chưa train +- Cần xử lý linh hoạt + +**Cách hoạt động:** + +```yaml +# config.yml +policies: + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: "action_llm_fallback" +``` + +**Ví dụ:** +``` +User: "Ủa sao đắt thế? So với tàu hỏa thì sao?" + +Rasa: + Intent: nlu_fallback (confidence: 0.25) + → Trigger action_llm_fallback + +LLM Response: + "Tôi hiểu bạn quan tâm đến giá cả. Máy bay tuy đắt hơn + tàu hỏa nhưng tiết kiệm thời gian (2h vs 30h). Tôi chỉ + hỗ trợ đặt vé máy bay. Bạn có muốn tiếp tục không?" +``` + +**Code:** +```python +# actions/actions_llm.py +class ActionLLMFallback(Action): + def name(self): + return "action_llm_fallback" + + def run(self, dispatcher, tracker, domain): + # Get user message + user_message = tracker.latest_message.get("text") + + # Build context + context = FALLBACK_HANDLER.build_context(tracker.events) + + # Generate LLM response + llm_response = FALLBACK_HANDLER.generate_response( + user_message=user_message, + context=context + ) + + dispatcher.utter_message(text=llm_response) + return [] +``` + +--- + +### 2. Response Enhancement + +**Khi dùng:** +- Rasa xử lý logic (DB query) +- LLM làm đẹp response + +**Ví dụ:** + +**BEFORE (Template):** +``` +Bot: "Tìm thấy 2 chuyến bay: + 1. VN123 - 08:00 - 2.500.000đ + 2. VJ456 - 14:30 - 1.800.000đ" +``` + +**AFTER (LLM Enhanced):** +``` +Bot: "Tuyệt! Tôi tìm thấy 2 chuyến bay phù hợp 🛫 + + ✈️ Vietnam Airlines VN123 + ⏰ 08:00 → 10:15 + 💰 2.500.000đ + ✨ Bay sớm, tiện đi làm + + ✈️ VietJet VJ456 + ⏰ 14:30 → 16:45 + 💰 1.800.000đ (rẻ hơn 700k!) + ✨ Giá tốt, linh hoạt + + Bạn thích chuyến nào hơn?" +``` + +**Code:** +```python +class ActionShowFlights(Action): + def run(self, dispatcher, tracker, domain): + # Query database + flights_data = search_flights(...) + + # Enhance with LLM + enhanced_response = RESPONSE_ENHANCER.enhance_flight_results( + flights_data=flights_data + ) + + dispatcher.utter_message(text=enhanced_response) + return [] +``` + +--- + +### 3. Intent Clarification + +**Khi dùng:** +- Top 2 intents có confidence gần nhau +- Cần xác định intent chính xác + +**Ví dụ:** + +``` +User: "Tôi không muốn đi nữa" + +Rasa NLU: + - cancel_booking: 0.48 + - deny: 0.42 + - goodbye: 0.10 + → Ambiguous! + +LLM Clarification: + Analyze: "User muốn hủy booking" + → Return: "cancel_booking" ✅ +``` + +**Code:** +```python +class ActionClarifyIntent(Action): + def run(self, dispatcher, tracker, domain): + intent_ranking = tracker.latest_message["intent_ranking"] + + if INTENT_CLARIFIER.is_ambiguous(intent_ranking): + clarified = INTENT_CLARIFIER.clarify_intent( + user_message=tracker.latest_message["text"], + intent_ranking=intent_ranking + ) + + return [SlotSet("clarified_intent", clarified)] + + return [] +``` + +--- + +## Cấu Hình Chi Tiết + +### Chuyển Đổi Provider + +**Dùng OpenAI:** +```python +# actions/actions_llm.py +LLM_PROVIDER = "openai" +OPENAI_MODEL = "gpt-4" # or "gpt-3.5-turbo" +``` + +**Dùng Claude:** +```python +# actions/actions_llm.py +LLM_PROVIDER = "claude" +CLAUDE_MODEL = "claude-3-5-sonnet-20241022" +``` + +### Tuning Thresholds + +```python +# Fallback threshold +CONFIDENCE_THRESHOLD = 0.7 # Lower = More LLM usage + +# Ambiguity threshold +AMBIGUITY_THRESHOLD = 0.2 # Lower = More clarification +``` + +### Custom System Prompt + +```python +# actions/llm/fallback.py +FALLBACK_HANDLER.set_system_prompt(""" +Bạn là trợ lý của công ty XYZ. + +Quy tắc: +1. Luôn nhắc tên công ty +2. Formal tone +3. ... +""") +``` + +--- + +## Docker Deployment + +### Dockerfile + +```dockerfile +FROM rasa/rasa:3.6.21-full + +# Install LLM dependencies +RUN pip install openai anthropic python-dotenv + +# Copy actions +COPY actions /app/actions/ +COPY .env /app/.env + +USER 1001 +``` + +### docker-compose.yml + +```yaml +version: '3.8' + +services: + rasa: + image: rasa/rasa:3.6.21-full + ports: + - "5005:5005" + volumes: + - ./:/app + command: + - run + - --enable-api + - --cors + - "*" + + action-server: + build: . + ports: + - "5055:5055" + volumes: + - ./actions:/app/actions + - ./.env:/app/.env + environment: + - OPENAI_API_KEY=${OPENAI_API_KEY} + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + command: + - start + - --actions + - actions +``` + +**Run:** +```bash +docker-compose up -d +``` + +--- + +## Monitoring & Costs + +### Track Metrics + +```python +# In actions_llm.py +logger.info( + f"🤖 LLM used | " + f"Provider: {LLM_PROVIDER} | " + f"Model: {model} | " + f"Tokens: {tokens}" +) +``` + +### Cost Estimation + +**OpenAI GPT-4:** +- Input: $0.03 / 1K tokens +- Output: $0.06 / 1K tokens +- Average conversation: ~500 tokens = $0.03 + +**Claude Sonnet:** +- Input: $0.003 / 1K tokens +- Output: $0.015 / 1K tokens +- Average conversation: ~500 tokens = $0.009 + +**With 80/20 hybrid:** +- 80% requests → Rasa (free) +- 20% requests → LLM +- 1000 conversations/day = ~$6-18/month + +--- + +## Troubleshooting + +### Lỗi: API Key Invalid + +```bash +# Check .env file +cat .env | grep API_KEY + +# Test directly +python -c "from openai import OpenAI; print(OpenAI().models.list())" +``` + +### Lỗi: LLM Not Available + +```python +# Check provider initialization +if FALLBACK_HANDLER.provider.is_available(): + print("✅ LLM ready") +else: + print("❌ LLM not available") +``` + +### Lỗi: Slow Response + +```python +# Use faster model +LLM_PROVIDER = "openai" +OPENAI_MODEL = "gpt-3.5-turbo" # 10x faster + +# Or reduce max_tokens +LLM_MAX_TOKENS = 200 # Instead of 500 +``` + +--- + +## Best Practices + +### 1. Cost Optimization + +```python +# Cache common queries +from functools import lru_cache + +@lru_cache(maxsize=100) +def get_llm_response(prompt): + return provider.generate(...) +``` + +### 2. Error Handling + +```python +try: + llm_response = provider.generate(messages) +except Exception as e: + logger.error(f"LLM failed: {e}") + # Fallback to template + llm_response = "Xin lỗi, tôi không hiểu..." +``` + +### 3. Testing + +```python +# Test without LLM +LLM_PROVIDER = None # Disable LLM + +# Or use mock +from unittest.mock import Mock +FALLBACK_HANDLER.provider = Mock() +``` + +--- + +## Examples + +Xem folder `examples/hybrid_bot/` để có: +- ✅ Full configuration +- ✅ Sample conversations +- ✅ Training data +- ✅ Custom actions + +--- + +## Tóm Tắt + +### Khi Nào Dùng LLM? + +| Scenario | Use Rasa | Use LLM | +|----------|----------|---------| +| **Booking flow** | ✅ | ❌ | +| **FAQ đơn giản** | ✅ | ❌ | +| **Unexpected questions** | ❌ | ✅ | +| **Chitchat** | ❌ | ✅ | +| **Complex reasoning** | ❌ | ✅ | +| **Response enhancement** | Combo | ✅ | + +### Architecture Tốt Nhất + +``` +┌────────────────────────────────┐ +│ 80% traffic → Rasa │ +│ (Fast, Free, Controlled) │ +└────────────────────────────────┘ + +┌────────────────────────────────┐ +│ 20% edge cases → LLM │ +│ (Smart, Flexible) │ +└────────────────────────────────┘ + += Best user experience + Low cost +``` + +--- + +## Support + +- 📧 Issues: [GitHub Issues](https://github.com/RasaHQ/rasa/issues) +- 💬 Community: [Rasa Forum](https://forum.rasa.com) +- 📖 Docs: [Rasa Docs](https://rasa.com/docs/) + +**Module version:** 1.0.0 +**Last updated:** 2024-11-18 diff --git a/RASA_MODELS_VS_LLM_GUIDE_VI.md b/RASA_MODELS_VS_LLM_GUIDE_VI.md new file mode 100644 index 000000000000..5b05e1ef11fa --- /dev/null +++ b/RASA_MODELS_VS_LLM_GUIDE_VI.md @@ -0,0 +1,707 @@ +# Rasa Có Dùng Mô Hình LLM Không? + +## Câu Trả Lời Ngắn Gọn + +**KHÔNG, Rasa KHÔNG sử dụng LLMs (Large Language Models) như GPT-4, Claude, hoặc Gemini.** + +Tuy nhiên, Rasa **CÓ HỖ TRỢ** các **Pre-trained Language Models** (PLMs) như BERT, RoBERTa, GPT-2 - nhưng chúng là các models **nhỏ hơn NHIỀU** và hoạt động **KHÁC BIỆT** so với LLMs hiện đại. + +--- + +## Mục Lục +1. [Rasa Dùng Mô Hình Gì?](#rasa-dùng-mô-hình-gì) +2. [Pre-trained Language Models vs LLMs](#pre-trained-language-models-vs-llms) +3. [Kiến Trúc Mô Hình Của Rasa](#kiến-trúc-mô-hình-của-rasa) +4. [So Sánh: Rasa vs LLM Chatbots](#so-sánh-rasa-vs-llm-chatbots) +5. [Khi Nào Dùng Rasa, Khi Nào Dùng LLM](#khi-nào-dùng-rasa-khi-nào-dùng-llm) +6. [Tích Hợp Rasa Với LLM](#tích-hợp-rasa-với-llm) + +--- + +## Rasa Dùng Mô Hình Gì? + +### 1. Custom Neural Networks (Chính) + +Rasa chủ yếu dùng **custom neural networks tự build** với TensorFlow: + +#### DIETClassifier (Dual Intent Entity Transformer) +- **Chức năng:** Phân loại intent + trích xuất entity +- **Kiến trúc:** Transformer-based +- **Kích thước:** ~10-50MB +- **Parameters:** ~5-20 million +- **Training:** Supervised learning trên YOUR data + +```yaml +# config.yml +pipeline: + - name: DIETClassifier + epochs: 200 + transformer_size: 256 + number_of_transformer_layers: 2 +``` + +**Đặc điểm:** +- ✅ Lightweight (chạy trên CPU) +- ✅ Fast inference (< 100ms) +- ✅ Task-specific (chỉ làm intent + entity) +- ❌ Không có khả năng reasoning phức tạp +- ❌ Không generate text tự do + +#### TEDPolicy (Transformer Embedding Dialogue) +- **Chức năng:** Dự đoán action tiếp theo trong hội thoại +- **Kiến trúc:** Transformer + attention mechanism +- **Kích thước:** ~20-100MB +- **Training:** Học từ stories + +```yaml +# config.yml +policies: + - name: TEDPolicy + epochs: 200 + transformer_size: 256 +``` + +**Đặc điểm:** +- ✅ Hiểu context hội thoại +- ✅ Dự đoán action phù hợp +- ❌ Không generate responses +- ❌ Cần định nghĩa trước tất cả actions + +### 2. Pre-trained Language Models (Tùy Chọn) + +Rasa **HỖ TRỢ** (không bắt buộc) các pre-trained models từ HuggingFace: + +#### LanguageModelFeaturizer + +**Models hỗ trợ:** +- **BERT** (Bidirectional Encoder Representations from Transformers) +- **GPT-2** (Generative Pre-trained Transformer 2) +- **RoBERTa** (Robustly Optimized BERT) +- **DistilBERT** (Distilled BERT) +- **XLNet** +- **CamemBERT** (French) +- **LaBSE** (Language-agnostic BERT Sentence Embedding) + +```yaml +# config.yml - Dùng BERT cho featurization +pipeline: + - name: LanguageModelFeaturizer + model_name: "bert" + model_weights: "bert-base-multilingual-cased" +``` + +**Chức năng:** +- Chuyển text thành vector embeddings +- Cung cấp semantic understanding tốt hơn +- **KHÔNG** generate text +- **KHÔNG** làm reasoning + +**Kích thước:** +| Model | Parameters | Size | +|-------|-----------|------| +| DistilBERT | 66M | ~250MB | +| BERT-base | 110M | ~440MB | +| RoBERTa-base | 125M | ~500MB | +| GPT-2 | 124M-1.5B | ~500MB-6GB | + +**So với LLMs:** +| | Pre-trained LMs | LLMs | +|---|----------------|------| +| **Parameters** | 66M - 1.5B | 7B - 175B+ | +| **Size** | 250MB - 6GB | 14GB - 350GB+ | +| **Use case** | Feature extraction | Text generation + reasoning | + +--- + +## Pre-trained Language Models vs LLMs + +### Điểm Giống Nhau + +✅ Đều dựa trên Transformer architecture +✅ Đều được pre-train trên large text corpora +✅ Đều hiểu ngữ cảnh và ngữ nghĩa + +### Điểm Khác Biệt Quan Trọng + +| Aspect | Pre-trained LMs (BERT, GPT-2) | LLMs (GPT-4, Claude, Gemini) | +|--------|------------------------------|------------------------------| +| **Kích thước** | 100M - 1.5B parameters | 7B - 175B+ parameters | +| **Capabilities** | Feature extraction, classification | Generation, reasoning, multi-step tasks | +| **Input** | Fixed length (512-1024 tokens) | Long context (8K-200K tokens) | +| **Output** | Embeddings, labels | Free-form text | +| **Training** | Pre-training + fine-tuning | Pre-training + RLHF + prompting | +| **Inference** | Fast (~50ms) | Slower (~1-5s) | +| **Cost** | Chạy local, free | API calls, expensive | +| **Use in Rasa** | Featurization only | Not used natively | + +### Ví Dụ Minh Họa + +**BERT (Pre-trained LM):** +```python +Input: "Đặt vé máy bay đi Hà Nội" +Output: [0.23, -0.45, 0.89, ...] # 768-dimensional vector +→ Vector này được dùng cho classification +``` + +**GPT-4 (LLM):** +```python +Input: "Đặt vé máy bay đi Hà Nội" +Output: "Tôi sẽ giúp bạn đặt vé máy bay đi Hà Nội. + Bạn muốn khởi hành từ đâu và vào ngày nào?" +→ Generate text response trực tiếp +``` + +**Rasa với BERT:** +``` +User: "Đặt vé máy bay đi Hà Nội" +1. BERT → vector [0.23, -0.45, ...] +2. DIETClassifier → intent: book_flight, entity: Hà Nội +3. TEDPolicy → action: utter_ask_departure +4. Response template → "Bạn muốn bay từ đâu?" +``` + +--- + +## Kiến Trúc Mô Hình Của Rasa + +### Pipeline Hoàn Chỉnh + +``` +User Input: "Đặt vé từ Hà Nội đi Sài Gòn" + ↓ +┌─────────────────────────────────────────────┐ +│ 1. TOKENIZATION │ +│ WhitespaceTokenizer │ +│ → ["Đặt", "vé", "từ", "Hà", "Nội", ...] │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ 2. FEATURIZATION (Optional: BERT/GPT-2) │ +│ LanguageModelFeaturizer (BERT) │ +│ → Dense vectors [768-dim per token] │ +│ │ +│ CountVectorsFeaturizer │ +│ → Sparse vectors [bag-of-words] │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ 3. INTENT CLASSIFICATION │ +│ DIETClassifier (Custom Transformer) │ +│ → Intent: book_flight (confidence: 0.95) │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ 4. ENTITY EXTRACTION │ +│ DIETClassifier (same model) │ +│ → departure: "Hà Nội" │ +│ → destination: "Sài Gòn" │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ 5. DIALOGUE MANAGEMENT │ +│ TEDPolicy (Custom Transformer) │ +│ → Next action: utter_ask_date │ +└─────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────┐ +│ 6. RESPONSE GENERATION │ +│ Response Selector / Templates │ +│ → "Bạn muốn bay vào ngày nào?" │ +└─────────────────────────────────────────────┘ +``` + +### Các Models Trong Rasa + +**1. DIETClassifier** +- Type: Custom Transformer +- Size: 10-50MB +- Purpose: Intent + Entity +- Training: Supervised on labeled data + +**2. TEDPolicy** +- Type: Custom Transformer +- Size: 20-100MB +- Purpose: Dialogue prediction +- Training: Supervised on stories + +**3. ResponseSelector** +- Type: Custom Transformer +- Size: 10-30MB +- Purpose: Select FAQ responses +- Training: Supervised on Q&A pairs + +**4. LanguageModelFeaturizer** (Optional) +- Type: Pre-trained BERT/GPT-2/RoBERTa +- Size: 250MB-6GB +- Purpose: Feature extraction only +- Training: Pre-trained, frozen weights + +### Training Process + +``` +Training Data +├─ 500 NLU examples +├─ 20 stories +└─ 5 rules + + ↓ + +Rasa Train +├─ Train DIETClassifier (30 min) +├─ Train TEDPolicy (20 min) +└─ Optional: Load BERT weights (5 min) + + ↓ + +Trained Model (50-200MB) +└─ Ready for inference +``` + +**Không giống LLM:** +- ❌ Không có billions of parameters +- ❌ Không train trên internet-scale data +- ❌ Không có general knowledge +- ✅ Task-specific, lightweight, fast + +--- + +## So Sánh: Rasa vs LLM Chatbots + +### Architecture Comparison + +**Rasa (Task-Specific Approach):** +``` +┌─────────────────────────────────────────┐ +│ User Input │ +└─────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────┐ +│ NLU Model (DIETClassifier) │ +│ - Intent classification │ +│ - Entity extraction │ +└─────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────┐ +│ Dialogue Manager (TEDPolicy) │ +│ - Action prediction │ +│ - Context tracking │ +└─────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────┐ +│ Response Templates / Actions │ +│ - Pre-defined responses │ +│ - Custom actions (API calls, DB) │ +└─────────────────────────────────────────┘ + ↓ +Bot Response +``` + +**LLM Chatbot (Generation Approach):** +``` +┌─────────────────────────────────────────┐ +│ User Input + Conversation History │ +└─────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────┐ +│ LLM (GPT-4 / Claude) │ +│ - Understand intent │ +│ - Generate response │ +│ - Reasoning & planning │ +│ - All-in-one model │ +└─────────────────────────────────────────┘ + ↓ +Bot Response (generated) +``` + +### Feature Comparison + +| Feature | Rasa | LLM Chatbot | +|---------|------|-------------| +| **Intent Recognition** | ✅ Excellent (trained) | ✅ Good (zero-shot) | +| **Entity Extraction** | ✅ Excellent (trained) | ⚠️ Moderate (prompting) | +| **Dialogue Control** | ✅ Excellent (stories) | ⚠️ Moderate (prompt eng.) | +| **Response Generation** | ⚠️ Templates only | ✅ Natural, varied | +| **Reasoning** | ❌ Limited | ✅ Strong | +| **Domain Knowledge** | ⚠️ Only trained data | ✅ Broad knowledge | +| **Consistency** | ✅ Very high | ⚠️ Can vary | +| **Latency** | ✅ Fast (<100ms) | ⚠️ Slower (1-5s) | +| **Cost** | ✅ Free (self-host) | ❌ Expensive (API) | +| **Privacy** | ✅ Fully controlled | ⚠️ Data sent to API | +| **Customization** | ✅ Full control | ⚠️ Limited to prompts | +| **Offline** | ✅ Yes | ❌ No | + +### Example Conversations + +**Scenario: Flight Booking** + +**Rasa:** +``` +User: Tôi muốn đặt vé máy bay +Bot: Bạn muốn bay từ đâu đến đâu? [Template response] + +User: Từ Hà Nội đi Sài Gòn +Bot: Bạn muốn bay vào ngày nào? [Template response] + +User: Ngày 15/12 +Bot: [API call to search flights] +Bot: Đây là các chuyến bay khả dụng: [List from DB] + +User: Tôi chọn chuyến 1 +Bot: [Action: book_ticket] +Bot: Đã đặt vé thành công! [Template response] +``` + +**Pros:** +✅ Predictable, controlled +✅ Always follows flow +✅ Reliable database integration +✅ Fast responses + +**Cons:** +❌ Rigid templates +❌ Cannot handle unexpected questions +❌ Limited natural language variation + +--- + +**LLM Chatbot:** +``` +User: Tôi muốn đặt vé máy bay +Bot: Tôi sẽ giúp bạn đặt vé máy bay. Để tìm chuyến bay + phù hợp nhất, bạn có thể cho tôi biết: + - Bạn muốn bay từ đâu đến đâu? + - Ngày khởi hành? + - Số lượng hành khách? + +User: Từ Hà Nội đi Sài Gòn, ngày 15/12, 2 người +Bot: Tuyệt vời! Tôi sẽ tìm các chuyến bay từ Hà Nội đến + TP. Hồ Chí Minh cho 2 hành khách vào ngày 15/12. + + Bạn có muốn chuyến bay buổi sáng hay buổi chiều? + Và bạn có ưu tiên hãng hàng không nào không? + +User: Chuyến sáng, VietJet hoặc Bamboo đều được +Bot: Dạ, tôi hiểu rồi. Để tôi kiểm tra... + [Function call: search_flights(...)] + + Tôi tìm thấy 3 chuyến bay phù hợp... +``` + +**Pros:** +✅ Natural, conversational +✅ Flexible, adaptive +✅ Can handle unexpected inputs +✅ Friendly, contextual + +**Cons:** +❌ Unpredictable outputs +❌ Can go off-track +❌ API costs +❌ Slower responses + +--- + +## Khi Nào Dùng Rasa, Khi Nào Dùng LLM + +### Use Case Matrix + +| Scenario | Recommend | Why? | +|----------|-----------|------| +| **Customer Support (Fixed FAQs)** | ✅ Rasa | Predictable, fast, cheap | +| **Booking/Reservation** | ✅ Rasa | Need strict flow control | +| **Banking/Finance** | ✅ Rasa | Security, compliance | +| **General Chatting** | ✅ LLM | Need conversational ability | +| **Complex Reasoning** | ✅ LLM | Rasa can't reason | +| **Content Creation** | ✅ LLM | Need generation | +| **Multi-language** | ⚠️ Both | Rasa with BERT / LLM with prompts | +| **Low Latency Required** | ✅ Rasa | <100ms vs 1-5s | +| **Privacy Critical** | ✅ Rasa | Self-hosted | +| **Budget Constrained** | ✅ Rasa | Free vs API costs | + +### Decision Tree + +``` +┌─────────────────────────────────────────┐ +│ Bạn cần chatbot làm gì? │ +└─────────────────────────────────────────┘ + ↓ + ┌─────────┴─────────┐ + │ │ +Task-specific Open-ended +(booking, FAQ) (chat, advice) + │ │ + ↓ ↓ +┌─────────┐ ┌─────────┐ +│ RASA │ │ LLM │ +└─────────┘ └─────────┘ +``` + +### Detailed Scenarios + +#### ✅ Nên Dùng Rasa Khi: + +1. **Domain hẹp, rõ ràng** + - Đặt vé + - FAQ + - Form filling + - Appointment booking + +2. **Cần control chặt chẽ** + - Banking transactions + - Healthcare advice + - Legal information + +3. **Ưu tiên tốc độ** + - Real-time support + - High traffic + +4. **Ngân sách hạn chế** + - Startup + - Non-profit + +5. **Privacy quan trọng** + - Sensitive data + - Compliance requirements + +#### ✅ Nên Dùng LLM Khi: + +1. **Cần conversational ability** + - Casual chatting + - Personal assistant + +2. **Domain rộng, diverse** + - General knowledge Q&A + - Educational tutor + +3. **Cần reasoning** + - Problem solving + - Decision support + +4. **Cần generation** + - Content creation + - Email drafting + - Summarization + +5. **Có budget** + - Enterprise + - High-value use cases + +#### ⚠️ Hybrid Approach (Best of Both) + +**Kết hợp Rasa + LLM:** +``` +┌─────────────────────────────────────────┐ +│ User Input │ +└─────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────┐ +│ Rasa NLU │ +│ - Intent classification │ +│ - Entity extraction │ +└─────────────────────────────────────────┘ + ↓ + ┌─────────┴─────────┐ + │ │ +Simple intents Complex/Unknown + │ │ + ↓ ↓ +┌─────────┐ ┌─────────┐ +│ Rasa │ │ LLM │ +│ Actions │ │ Call │ +└─────────┘ └─────────┘ + │ │ + └─────────┬─────────┘ + ↓ + Bot Response +``` + +**Ưu điểm:** +- ✅ Rasa xử lý 80% cases (fast, cheap) +- ✅ LLM xử lý 20% edge cases (flexible) +- ✅ Best of both worlds + +--- + +## Tích Hợp Rasa Với LLM + +### Phương Pháp 1: LLM Làm Fallback + +**Khi nào:** Rasa không tự tin → Gọi LLM + +```yaml +# domain.yml +actions: + - action_llm_fallback + +# actions/actions.py +class ActionLLMFallback(Action): + def name(self) -> str: + return "action_llm_fallback" + + async def run(self, dispatcher, tracker, domain): + user_message = tracker.latest_message.get('text') + + # Call GPT-4 / Claude API + llm_response = call_llm_api(user_message, context=tracker.events) + + dispatcher.utter_message(text=llm_response) + return [] +``` + +**Config:** +```yaml +# config.yml +policies: + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: action_llm_fallback +``` + +### Phương Pháp 2: LLM Generate Responses + +**Khi nào:** Muốn responses tự nhiên hơn templates + +```python +# actions/actions.py +class ActionGenerateResponse(Action): + def name(self) -> str: + return "action_generate_response" + + async def run(self, dispatcher, tracker, domain): + intent = tracker.latest_message['intent']['name'] + entities = tracker.latest_message['entities'] + + # Build prompt + prompt = f""" + User intent: {intent} + Entities: {entities} + + Generate a helpful response for the user. + """ + + # Call LLM + response = call_llm_api(prompt) + + dispatcher.utter_message(text=response) + return [] +``` + +### Phương Pháp 3: LLM Cho Chitchat + +**Khi nào:** Out-of-scope conversations + +```yaml +# config.yml +pipeline: + - name: DIETClassifier + - name: FallbackClassifier + threshold: 0.7 + +# domain.yml +intents: + - chitchat + +# rules.yml +rules: +- rule: Handle chitchat with LLM + steps: + - intent: chitchat + - action: action_llm_chitchat +``` + +### Phương Pháp 4: LLM Data Augmentation + +**Khi nào:** Tự động tạo training data + +```python +# scripts/augment_data.py +from openai import OpenAI + +def generate_nlu_examples(intent, num_examples=50): + prompt = f""" + Generate {num_examples} diverse examples for intent '{intent}'. + Include variations in: + - Phrasing + - Formality + - Typos + - Vietnamese and English + + Intent: {intent} + Examples: + """ + + response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": prompt}] + ) + + return response.choices[0].message.content + +# Generate data +book_flight_examples = generate_nlu_examples("book_flight") + +# Add to data/nlu.yml +# Train Rasa model +``` + +--- + +## Tóm Tắt + +### Câu Trả Lời Chi Tiết + +**Rasa có dùng LLM không?** + +**KHÔNG** - Rasa không dùng LLMs như GPT-4, Claude, Gemini. + +**Rasa dùng gì?** + +1. **Custom Transformers** (DIETClassifier, TEDPolicy) + - Kích thước: 10-100MB + - Parameters: 5-50M + - Mục đích: Task-specific (intent, entity, dialogue) + +2. **Pre-trained Language Models** (Optional) + - BERT, GPT-2, RoBERTa + - Kích thước: 250MB-6GB + - Parameters: 66M-1.5B + - Mục đích: Feature extraction only + +**Khác biệt chính:** + +| | Rasa Models | LLMs | +|---|-------------|------| +| **Size** | 10-100MB | 14-350GB | +| **Parameters** | 5-50M | 7-175B | +| **Capability** | Classification | Generation + Reasoning | +| **Speed** | <100ms | 1-5s | +| **Cost** | Free | Expensive | +| **Control** | High | Low | + +**Kết luận:** + +✅ **Dùng Rasa:** Task-specific chatbots (booking, FAQ, support) +✅ **Dùng LLM:** Open-ended conversations (general chat, advice) +✅ **Hybrid:** Rasa (main) + LLM (fallback) = Best approach + +--- + +## File Đã Tạo + +Tôi đã phân tích source code và tạo **hướng dẫn chi tiết** về models trong Rasa: + +📄 **File mới:** `RASA_MODELS_VS_LLM_GUIDE_VI.md` + +**Nội dung:** +- ✅ Rasa dùng models gì +- ✅ So sánh Pre-trained LMs vs LLMs +- ✅ Kiến trúc chi tiết +- ✅ Use case recommendations +- ✅ Cách tích hợp Rasa + LLM + +**Kết quả chính:** +- Rasa = Task-specific models (lightweight, fast, controlled) +- LLMs = General-purpose models (heavy, flexible, expensive) +- Hybrid approach = Best of both worlds + +Bạn có câu hỏi nào thêm về models hay architecture không? 🤖 diff --git a/TRAINING_DATA_GUIDE_VI.md b/TRAINING_DATA_GUIDE_VI.md new file mode 100644 index 000000000000..0750c242c2d7 --- /dev/null +++ b/TRAINING_DATA_GUIDE_VI.md @@ -0,0 +1,1017 @@ +# Hướng Dẫn Chi Tiết: Tạo Training Data Cho Rasa Chatbot + +## 📚 Mục Lục + +1. [Tổng Quan Training Data](#tổng-quan) +2. [NLU Training Data](#nlu-training-data) +3. [Stories Training Data](#stories-training-data) +4. [Rules Training Data](#rules-training-data) +5. [Best Practices](#best-practices) +6. [Tools & Tips](#tools--tips) +7. [Ví Dụ Thực Tế](#ví-dụ-thực-tế) +8. [Kiểm Tra & Testing](#kiểm-tra--testing) + +--- + +## 📖 Tổng Quan + +### Training Data Trong Rasa Gồm 3 Loại: + +``` +data/ +├── nlu.yml # Dạy bot hiểu ngôn ngữ (Intent & Entity) +├── stories.yml # Dạy bot hội thoại (Conversation flows) +└── rules.yml # Dạy bot quy tắc cứng (Fixed behaviors) +``` + +### Khi Nào Dùng Loại Nào? + +| Loại | Khi Nào Dùng | Ví Dụ | +|------|--------------|-------| +| **NLU** | Dạy bot hiểu câu nói | "tìm laptop" → intent: search_product | +| **Stories** | Hội thoại nhiều bước, có ngữ cảnh | Đặt vé máy bay (hỏi điểm đi, điểm đến, ngày...) | +| **Rules** | Hành vi cố định, không phụ thuộc ngữ cảnh | "chào" → luôn chào lại | + +--- + +## 🎯 NLU Training Data + +### Cấu Trúc File NLU + +```yaml +version: "3.1" + +nlu: + - intent: tên_intent + examples: | + - câu ví dụ 1 + - câu ví dụ 2 + - câu ví dụ 3 với [entity](entity_name) +``` + +### 1. Viết Intent Cơ Bản + +**Ví dụ: Intent chào hỏi** + +```yaml +nlu: + - intent: greet + examples: | + - xin chào + - chào bạn + - hello + - hi + - chào buổi sáng + - chào buổi chiều + - hey + - hế lô +``` + +**📌 Quy tắc vàng:** +- ✅ Mỗi intent cần **tối thiểu 10-15 examples** +- ✅ Examples phải **đa dạng** (ngắn, dài, có typo, slang...) +- ✅ Viết theo cách người dùng thật nói +- ❌ KHÔNG copy-paste giống nhau + +### 2. Viết Intent Với Entities + +**Ví dụ: Tìm sản phẩm** + +```yaml +nlu: + - intent: search_product + examples: | + - tìm [laptop](product_type) + - tôi muốn mua [máy tính](product_type) + - cho tôi xem [laptop](product_type) [gaming](category) + - tìm [laptop](product_type) [ASUS](brand) + - [laptop](product_type) giá [20 triệu](price_range) + - tìm [laptop](product_type) cho [sinh viên](use_case) + - cần [máy chủ](product_type) [Dell](brand) dưới [100 triệu](price_range) + - [camera](product_type) [4MP](specification) + - tìm [switch](product_type) [48 port](specification) + - [phần mềm](product_type) [Windows](product_name) +``` + +**Cú pháp Entity Annotation:** +``` +[giá trị entity](tên_entity) +``` + +**📌 Các loại Entity phổ biến:** +- `product_type`: laptop, máy chủ, camera... +- `brand`: Dell, HP, ASUS... +- `price_range`: dưới 20 triệu, từ 10-15 triệu... +- `specification`: 16GB RAM, 48 port, 4MP... +- `use_case`: gaming, văn phòng, doanh nghiệp... + +### 3. Viết Intent Phức Tạp + +**Ví dụ: So sánh sản phẩm** + +```yaml +nlu: + - intent: compare_products + examples: | + - so sánh [Dell R740](product_name) và [HP DL380](product_name) + - so sánh [laptop](product_type) [Dell](brand) với [HP](brand) + - khác nhau gì giữa [ASUS ROG](product_name) và [MSI Katana](product_name) + - [Dell](brand) tốt hơn [HP](brand) không + - sự khác biệt của [switch Cisco](product_type) và [HPE](brand) + - so sánh giá [máy chủ](product_type) + - [camera Hikvision](product_name) so với [Dahua](brand) + - nên chọn [laptop](product_type) nào + - sản phẩm nào tốt hơn + - compare [server](product_type) [Dell](brand) vs [Lenovo](brand) +``` + +### 4. Synonyms (Từ Đồng Nghĩa) + +Dùng khi nhiều cách nói khác nhau nhưng cùng ý nghĩa: + +```yaml +nlu: + - synonym: laptop + examples: | + - máy tính xách tay + - laptop + - máy tính + - pc xách tay + - notebook + + - synonym: máy chủ + examples: | + - server + - máy chủ + - may chu + - máy chủ server + + - synonym: gaming + examples: | + - chơi game + - gaming + - game + - chơi games +``` + +### 5. Regex Features + +Dùng cho patterns cố định (số điện thoại, email, mã sản phẩm...): + +```yaml +nlu: + - regex: phone_number + examples: | + - \d{10} + - \d{3}[-.\s]\d{3}[-.\s]\d{4} + + - regex: product_code + examples: | + - [A-Z]{2}\d{3,5} + - LP\d{3} + - SV\d{3} + + - regex: price_pattern + examples: | + - \d+\s?(triệu|tr|trieu) + - \d+\s?(ngàn|k|ngan) +``` + +### 6. Lookup Tables + +Dùng cho danh sách giá trị cố định (thành phố, sản phẩm...): + +```yaml +nlu: + - lookup: brands + examples: | + - Dell + - HP + - Lenovo + - ASUS + - MSI + - Cisco + - HPE + - Hikvision + - Dahua + + - lookup: product_types + examples: | + - laptop + - máy chủ + - server + - switch + - camera + - phần mềm +``` + +--- + +## 📖 Stories Training Data + +Stories dạy bot cách hội thoại nhiều bước. + +### Cấu Trúc Story + +```yaml +version: "3.1" + +stories: + - story: tên story (mô tả ngắn gọn) + steps: + - intent: ý định của user + - action: hành động của bot + - intent: user nói tiếp + - action: bot phản hồi +``` + +### 1. Story Cơ Bản + +**Ví dụ: Chào hỏi đơn giản** + +```yaml +stories: + - story: greet and goodbye + steps: + - intent: greet + - action: utter_greet + - intent: goodbye + - action: utter_goodbye +``` + +**Diễn giải:** +1. User: "xin chào" (intent: greet) +2. Bot: "Xin chào! Tôi có thể giúp gì..." (action: utter_greet) +3. User: "tạm biệt" (intent: goodbye) +4. Bot: "Hẹn gặp lại!" (action: utter_goodbye) + +### 2. Story Với Entities & Slots + +**Ví dụ: Tìm sản phẩm** + +```yaml +stories: + - story: search laptop by price + steps: + - intent: search_product + entities: + - product_type: "laptop" + - price_range: "25 triệu" + - slot_was_set: + - product_type: "laptop" + - price_range: "25 triệu" + - action: action_search_product + - intent: affirm + - action: action_show_details +``` + +**Diễn giải:** +1. User: "tìm laptop dưới 25 triệu" +2. Bot lưu: product_type="laptop", price_range="25 triệu" +3. Bot chạy: action_search_product (tìm kiếm) +4. User: "đúng rồi" (xác nhận) +5. Bot chạy: action_show_details (hiển thị chi tiết) + +### 3. Story Với Nhiều Nhánh + +**Ví dụ: Tư vấn sản phẩm** + +```yaml +stories: + - story: recommend laptop - gaming + steps: + - intent: recommend_product + entities: + - product_type: "laptop" + - use_case: "gaming" + - action: action_recommend_product + - intent: ask_price + - action: action_show_price + - intent: affirm + - action: action_add_to_cart + + - story: recommend laptop - office + steps: + - intent: recommend_product + entities: + - product_type: "laptop" + - use_case: "văn phòng" + - action: action_recommend_product + - intent: ask_specifications + - action: action_show_specifications + - intent: compare_products + - action: action_compare_products +``` + +### 4. Story Với Form (Thu Thập Thông Tin) + +**Ví dụ: Đặt hàng** + +```yaml +stories: + - story: complete order form + steps: + - intent: place_order + - action: order_form + - active_loop: order_form + - slot_was_set: + - requested_slot: product_name + - slot_was_set: + - requested_slot: quantity + - slot_was_set: + - requested_slot: phone_number + - slot_was_set: + - requested_slot: null + - active_loop: null + - action: action_submit_order +``` + +### 5. Checkpoints (Tái Sử Dụng Story) + +```yaml +stories: + - story: greet user + steps: + - intent: greet + - action: utter_greet + - checkpoint: after_greet + + - story: greet then search + steps: + - checkpoint: after_greet + - intent: search_product + - action: action_search_product + + - story: greet then ask price + steps: + - checkpoint: after_greet + - intent: ask_price + - action: action_show_price +``` + +--- + +## ⚖️ Rules Training Data + +Rules là quy tắc cứng, luôn thực thi giống nhau. + +### Cấu Trúc Rule + +```yaml +version: "3.1" + +rules: + - rule: tên rule + steps: + - intent: intent_name + - action: action_name +``` + +### 1. Rule Cơ Bản + +**Ví dụ: Chào hỏi** + +```yaml +rules: + - rule: Say goodbye anytime user says goodbye + steps: + - intent: goodbye + - action: utter_goodbye + + - rule: Say thanks + steps: + - intent: thank + - action: utter_thank +``` + +**📌 Đặc điểm:** +- Luôn chạy khi gặp intent +- Không phụ thuộc ngữ cảnh + +### 2. Rule Với Conditions + +**Ví dụ: Chỉ chào khi chưa chào** + +```yaml +rules: + - rule: Greet user only once + condition: + - slot_was_set: + - user_greeted: false + steps: + - intent: greet + - action: utter_greet + - action: action_set_greeted_flag +``` + +### 3. Rule Kích Hoạt Form + +```yaml +rules: + - rule: Activate order form + steps: + - intent: place_order + - action: order_form + - active_loop: order_form + + - rule: Submit order form + condition: + - active_loop: order_form + steps: + - action: order_form + - active_loop: null + - slot_was_set: + - requested_slot: null + - action: action_submit_order +``` + +### 4. Rule Cho Fallback + +```yaml +rules: + - rule: Ask user to rephrase when confidence is low + steps: + - intent: nlu_fallback + - action: utter_ask_rephrase + + - rule: Handle out of scope + steps: + - intent: out_of_scope + - action: utter_out_of_scope +``` + +--- + +## ✅ Best Practices + +### 1. Quy Tắc Viết NLU Data + +#### ✅ ĐÚNG: +```yaml +nlu: + - intent: search_product + examples: | + - tìm laptop + - laptop gaming + - cho tôi xem máy tính + - tôi cần mua laptop ASUS + - có laptop nào dưới 20 triệu + - tìm máy tính cho sinh viên + - laptop văn phòng giá rẻ + - cho xem laptop chơi game + - cần laptop thiết kế đồ họa + - tìm laptop Dell có sẵn +``` + +**📌 Lý do tốt:** +- Đa dạng cách diễn đạt +- Có ngắn, có dài +- Có entity, không entity +- Tự nhiên như người nói + +#### ❌ SAI: +```yaml +nlu: + - intent: search_product + examples: | + - tìm laptop + - tìm laptop gaming + - tìm laptop ASUS + - tìm laptop Dell + - tìm laptop HP +``` + +**📌 Lý do sai:** +- Quá giống nhau (chỉ thay brand) +- Không đa dạng cấu trúc +- Bot sẽ overfit (chỉ học pattern "tìm laptop X") + +### 2. Số Lượng Examples Cần Thiết + +| Intent Type | Số Examples Tối Thiểu | Khuyến Nghị | +|-------------|------------------------|-------------| +| Intent đơn giản (greet, goodbye) | 10-15 | 20-30 | +| Intent trung bình (search, ask) | 20-30 | 50-100 | +| Intent phức tạp (với entities) | 30-50 | 100-200 | +| Intent quan trọng (core business) | 50-100 | 200-500 | + +### 3. Viết Examples Đa Dạng + +**Chiến lược "DIVERSE" (Đa Dạng Hóa):** + +```yaml +nlu: + - intent: ask_price + examples: | + # Ngắn + - giá + - bao nhiêu + - giá bao nhiêu + + # Trung bình + - laptop này giá bao nhiêu + - giá Dell R740 là bao nhiêu + - hỏi giá máy chủ + + # Dài + - cho tôi hỏi laptop ASUS ROG này giá bao nhiêu + - tôi muốn biết giá của máy chủ Dell PowerEdge R740 + + # Slang/typo + - giá bn + - bao nhiu + - gia bao nhieu + + # Formal/informal + - Xin cho biết giá cả + - Giá thành sản phẩm này là bao nhiêu ạ + - giá mấy + - giá bao nhiêu tiền + + # Với context + - máy này giá bao nhiêu + - cái đó giá bao nhiêu + - sản phẩm vừa rồi giá thế nào +``` + +### 4. Xử Lý Intents Tương Tự + +**Vấn đề:** 2 intents quá giống nhau → Bot nhầm lẫn + +```yaml +# ❌ SAI: Quá tương tự +- intent: search_laptop + examples: | + - tìm laptop + - laptop nào tốt + +- intent: recommend_laptop + examples: | + - gợi ý laptop + - laptop nào tốt +``` + +**✅ ĐÚNG: Tách biệt rõ ràng** + +```yaml +- intent: search_product + examples: | + - tìm laptop gaming + - có laptop Dell không + - cho xem laptop ASUS ROG + # Focus: Tìm sản phẩm CỤ THỂ + +- intent: recommend_product + examples: | + - tư vấn laptop cho sinh viên + - laptop nào phù hợp với tôi + - gợi ý laptop trong tầm giá 20 triệu + # Focus: Xin GỢI Ý dựa trên nhu cầu +``` + +### 5. Entities Best Practices + +#### Cách Đặt Tên Entity + +✅ **ĐÚNG:** +``` +product_type, product_name, price_range, use_case +``` + +❌ **SAI:** +``` +type, name, price, case # Quá chung chung +ProductType, productName # Không theo convention +``` + +#### Annotation Đầy Đủ + +```yaml +nlu: + - intent: search_product + examples: | + # ✅ Annotate TẤT CẢ entities quan trọng + - tìm [laptop](product_type) [ASUS](brand) dưới [20 triệu](price_range) + - [máy chủ](product_type) [Dell R740](product_name) cho [doanh nghiệp](use_case) + + # ❌ KHÔNG bỏ sót + - tìm laptop ASUS dưới 20 triệu # Thiếu annotation +``` + +### 6. Stories Best Practices + +#### Viết Story Ngắn & Tập Trung + +✅ **ĐÚNG:** +```yaml +stories: + - story: search and show details + steps: + - intent: search_product + - action: action_search_product + - intent: ask_specifications + - action: action_show_specifications +``` + +❌ **SAI:** Story quá dài (>10 steps) +```yaml +stories: + - story: complete user journey # Quá dài! + steps: + - intent: greet + - action: utter_greet + - intent: search_product + - action: action_search_product + - intent: ask_price + - action: action_show_price + - intent: compare_products + - action: action_compare_products + - intent: ask_specifications + # ... 20 steps nữa +``` + +#### Sử Dụng OR Statement + +```yaml +stories: + - story: user can affirm or deny + steps: + - action: action_ask_confirmation + - or: + - intent: affirm + - intent: deny + - action: action_handle_response +``` + +### 7. Rules vs Stories + +| Tình Huống | Dùng | Ví Dụ | +|------------|------|-------| +| Hành vi cố định, không đổi | **Rule** | Chào → Chào lại | +| Single-turn Q&A | **Rule** | Hỏi giờ → Trả lời giờ | +| Multi-turn conversation | **Story** | Đặt vé máy bay | +| Kích hoạt Form | **Rule** | Start form | +| Xử lý trong Form | **Story** | Form flow | + +--- + +## 🛠️ Tools & Tips + +### 1. Rasa Data Validator + +Kiểm tra lỗi trong training data: + +```bash +# Validate tất cả data +rasa data validate + +# Validate stories +rasa data validate stories + +# Check for conflicts +rasa data validate --max-history 5 +``` + +**Common Errors:** +- Intent không có examples +- Story reference intent không tồn tại +- Entity không được define trong domain +- Conflicting stories + +### 2. Rasa Interactive Learning + +Tạo training data qua chat: + +```bash +rasa interactive +``` + +**Workflow:** +1. Chat với bot +2. Sửa predictions nếu sai +3. Rasa tự động thêm vào stories +4. Export thành training data + +### 3. Data Augmentation Tools + +**a) Paraphrasing Tool (online):** +- QuillBot: https://quillbot.com +- Paraphrase Online + +**b) Python Script:** +```python +# augment_data.py +import random + +templates = [ + "tìm {product}", + "cho tôi xem {product}", + "có {product} nào không", + "{product} giá bao nhiêu", + "tôi cần {product}" +] + +products = ["laptop", "máy chủ", "camera", "switch"] + +for template in templates: + for product in products: + print(f" - {template.format(product=product)}") +``` + +### 4. Markdown to YAML Converter + +```python +# Convert từ format cũ sang mới +rasa data convert nlu --data data/ --out converted/ --format yaml +``` + +### 5. Annotate Tool - Rasa NLU Trainer + +Web UI để annotate entities: + +```bash +pip install rasa-nlu-trainer +rasa-nlu-trainer +``` + +### 6. Bulk Testing Intent + +Tạo file test: + +```yaml +# tests/test_nlu.yml +nlu: + - intent: search_product + examples: | + - tìm laptop Dell + - máy chủ HP +``` + +Run test: +```bash +rasa test nlu --nlu tests/test_nlu.yml +``` + +--- + +## 💡 Ví Dụ Thực Tế + +### Use Case 1: Chatbot Đặt Đồ Ăn + +**File: data/nlu.yml** + +```yaml +version: "3.1" + +nlu: + # Intents + - intent: order_food + examples: | + - tôi muốn đặt món + - đặt đồ ăn + - order + - gọi món + - cho tôi đặt [pizza](dish) + - tôi muốn [phở](dish) + - đặt [2](quantity) [bánh mì](dish) + - [3](quantity) [cơm gà](dish) nhé + + - intent: ask_menu + examples: | + - menu có gì + - danh sách món ăn + - có món gì + - xem thực đơn + - món nào ngon + + - intent: ask_price + examples: | + - [pizza](dish) giá bao nhiêu + - giá [phở](dish) + - bao nhiêu tiền + - [cơm gà](dish) bao nhiêu + + # Entities + - synonym: pizza + examples: | + - pizza + - piza + - bánh pizza + + - lookup: dishes + examples: | + - pizza + - phở + - bánh mì + - cơm gà + - bún bò +``` + +**File: data/stories.yml** + +```yaml +version: "3.1" + +stories: + - story: order food flow + steps: + - intent: order_food + entities: + - dish: "pizza" + - quantity: "2" + - action: action_add_to_cart + - action: utter_ask_anything_else + - intent: deny + - action: utter_ask_delivery_info + - action: delivery_form + - active_loop: delivery_form + - active_loop: null + - action: action_confirm_order + + - story: check menu then order + steps: + - intent: ask_menu + - action: action_show_menu + - intent: order_food + - action: action_add_to_cart +``` + +### Use Case 2: Chatbot Hỗ Trợ Kỹ Thuật + +**File: data/nlu.yml** + +```yaml +version: "3.1" + +nlu: + - intent: report_issue + examples: | + - [laptop](device) tôi bị lỗi + - [máy tính](device) không khởi động được + - [máy in](device) bị [kẹt giấy](issue) + - [wifi](device) [không kết nối được](issue) + - [màn hình](device) bị [nhấp nháy](issue) + - [chuột](device) không hoạt động + - [bàn phím](device) bị [liệt phím](issue) + + - intent: ask_solution + examples: | + - làm thế nào để sửa + - cách khắc phục + - hướng dẫn tôi + - phải làm gì + - giải quyết như thế nào + + - regex: ticket_number + examples: | + - TICKET-\d{6} + - TK\d{4,6} +``` + +**File: data/rules.yml** + +```yaml +version: "3.1" + +rules: + - rule: Create ticket for new issue + steps: + - intent: report_issue + - action: action_create_ticket + - action: utter_ticket_created + + - rule: Provide solution if known issue + condition: + - slot_was_set: + - known_issue: true + steps: + - intent: ask_solution + - action: action_provide_solution +``` + +--- + +## 🧪 Kiểm Tra & Testing + +### 1. Test NLU Model + +```bash +# Test với file test riêng +rasa test nlu --nlu tests/test_nlu.yml + +# Cross-validation +rasa test nlu --nlu data/nlu.yml --cross-validation + +# Test và xem confusion matrix +rasa test nlu --nlu data/nlu.yml --out results/ +``` + +### 2. Test Stories + +```bash +# Test stories +rasa test core --stories tests/test_stories.yml + +# Test end-to-end +rasa test --stories tests/test_stories.yml +``` + +### 3. Interactive Testing + +```bash +# Chat và kiểm tra predictions +rasa shell + +# Debug mode +rasa shell --debug + +# NLU only +rasa shell nlu +``` + +### 4. Metrics Quan Trọng + +**NLU Metrics:** +- **Intent Accuracy**: >85% (tốt), >90% (xuất sắc) +- **Entity F1 Score**: >80% (tốt), >90% (xuất sắc) +- **Confidence**: >0.7 (chấp nhận được) + +**Core Metrics:** +- **Action Accuracy**: >90% +- **Story Accuracy**: >85% + +### 5. Phân Tích Lỗi + +```bash +# Xem errors +rasa test nlu --nlu data/nlu.yml --out results/ + +# Mở file results/intent_errors.json +# Check intent nào bị nhầm nhiều nhất +``` + +**Common Issues:** +1. **Intent Confusion**: 2 intents quá giống → Gộp hoặc tách rõ hơn +2. **Low Confidence**: Thiếu training data → Thêm examples +3. **Entity Miss**: Không recognize → Thêm examples có entity + +--- + +## 📋 Checklist Trước Khi Deploy + +### Training Data Quality Check + +- [ ] Mỗi intent có ít nhất 20 examples +- [ ] Examples đa dạng (ngắn, dài, formal, slang) +- [ ] Tất cả entities đều được annotate +- [ ] Không có intent trùng lặp/tương tự +- [ ] Synonyms và lookup tables đầy đủ +- [ ] Stories cover các flow chính +- [ ] Rules được dùng đúng chỗ + +### Testing Check + +- [ ] `rasa data validate` pass +- [ ] Intent accuracy >85% +- [ ] Entity F1 >80% +- [ ] Test thủ công 20+ câu +- [ ] Cross-validation results tốt + +### Documentation + +- [ ] Comment trong code +- [ ] Ghi chú các entities quan trọng +- [ ] Document conversation flows +- [ ] Training data versioning (git) + +--- + +## 🎯 Tổng Kết + +### Công Thức Thành Công + +``` +Quality Training Data = + Diverse Examples (40%) + + Sufficient Quantity (30%) + + Proper Annotation (20%) + + Good Testing (10%) +``` + +### Next Steps + +1. **Bắt đầu nhỏ**: 5-10 intents, 20 examples mỗi intent +2. **Test sớm, test thường xuyên**: Mỗi lần thêm data → test ngay +3. **Lặp lại**: Deploy → Thu thập real user data → Cải thiện +4. **Tự động hóa**: Script để generate examples, validate data + +### Resources + +- 📚 Rasa Docs: https://rasa.com/docs/rasa/training-data-format +- 🎓 Rasa Masterclass: https://learning.rasa.com +- 💬 Rasa Forum: https://forum.rasa.com +- 🛠️ Rasa X: Tool để improve training data + +--- + +**Chúc bạn tạo training data hiệu quả!** 🚀 diff --git a/TRAINING_MODULE_GUIDE_VI.md b/TRAINING_MODULE_GUIDE_VI.md new file mode 100644 index 000000000000..d997e1cb34ec --- /dev/null +++ b/TRAINING_MODULE_GUIDE_VI.md @@ -0,0 +1,1222 @@ +# Hướng Dẫn Chi Tiết Module Training Trong Rasa + +## Mục Lục +1. [Tổng Quan](#tổng-quan) +2. [Module Training Là Gì?](#module-training-là-gì) +3. [Các Loại Training](#các-loại-training) +4. [Quy Trình Training](#quy-trình-training) +5. [Các Tính Năng Chính](#các-tính-năng-chính) +6. [Ví Dụ Thực Tế](#ví-dụ-thực-tế) +7. [Best Practices](#best-practices) +8. [Troubleshooting](#troubleshooting) + +--- + +## Tổng Quan + +**Module Training** là **trái tim** của Rasa - nơi chatbot **học** từ dữ liệu của bạn để có thể: +- Hiểu câu hỏi của người dùng (NLU) +- Quyết định hành động tiếp theo (Dialogue Management) +- Cải thiện dần theo thời gian (Incremental Training) + +**Không có training = chatbot không thể hoạt động!** + +--- + +## Module Training Là Gì? + +### Định Nghĩa Đơn Giản + +Training trong Rasa giống như **dạy học cho một đứa trẻ**: + +``` +Dữ liệu Đầu Vào → Module Training → Model Thông Minh → Chatbot Hoạt Động +``` + +**Tương tự:** +- **Đứa trẻ**: Rasa model (ban đầu chưa biết gì) +- **Sách giáo khoa**: Training data (NLU data, stories, rules) +- **Quá trình học**: Training process (algorithms, neural networks) +- **Kiểm tra**: Testing & validation +- **Tốt nghiệp**: Trained model (.tar.gz file) + +### Các Thành Phần Chính + +``` +┌─────────────────────────────────────────────┐ +│ MODULE TRAINING TRONG RASA │ +├─────────────────────────────────────────────┤ +│ │ +│ 1. TRAINING DATA (Input) │ +│ ├─ NLU data (nlu.yml) │ +│ ├─ Stories (stories.yml) │ +│ ├─ Rules (rules.yml) │ +│ └─ Domain (domain.yml) │ +│ │ +│ 2. CONFIGURATION (Config) │ +│ ├─ Pipeline (NLU components) │ +│ └─ Policies (Core components) │ +│ │ +│ 3. TRAINING ENGINE │ +│ ├─ Graph Trainer │ +│ ├─ NLU Trainer │ +│ ├─ Core Trainer │ +│ └─ Fingerprinting & Caching │ +│ │ +│ 4. OUTPUT │ +│ └─ Trained Model (.tar.gz) │ +│ │ +└─────────────────────────────────────────────┘ +``` + +--- + +## Các Loại Training + +Rasa có **4 loại training** chính: + +### 1. Full Training (Train Toàn Bộ) + +**Mục đích:** Train cả NLU và Dialogue Management từ đầu + +**Khi nào dùng:** +- ✅ Lần đầu tiên train model +- ✅ Thay đổi lớn trong cấu hình +- ✅ Thêm/xóa intents, entities, actions + +**Lệnh:** +```bash +rasa train +``` + +**Quy trình:** +``` +Input: + - data/nlu.yml (câu hỏi mẫu) + - data/stories.yml (kịch bản hội thoại) + - data/rules.yml (quy tắc cố định) + - domain.yml (các intents, actions, responses) + - config.yml (cấu hình pipeline & policies) + +Process: + 1. Load tất cả training data + 2. Validate data (kiểm tra lỗi) + 3. Train NLU model (hiểu ngôn ngữ) + 4. Train Core model (quản lý hội thoại) + 5. Package thành file .tar.gz + +Output: + - models/20231114-123456.tar.gz +``` + +**Thời gian:** +- Nhỏ (< 500 câu): 2-10 phút +- Trung bình (500-2000 câu): 10-30 phút +- Lớn (> 2000 câu): 30-120 phút + +--- + +### 2. NLU-Only Training (Train Chỉ NLU) + +**Mục đích:** Chỉ train phần hiểu ngôn ngữ tự nhiên + +**Khi nào dùng:** +- ✅ Chỉ thay đổi dữ liệu NLU +- ✅ Thêm intent hoặc entity mới +- ✅ Không động đến stories/rules + +**Lệnh:** +```bash +rasa train nlu +``` + +**Quy trình:** +``` +Input: + - data/nlu.yml + - config.yml (chỉ phần pipeline) + +Process: + 1. Load NLU training data + 2. Train các component trong pipeline: + - Tokenizer (tách từ) + - Featurizer (vector hóa) + - Intent Classifier (phân loại ý định) + - Entity Extractor (trích xuất entities) + +Output: + - models/nlu-20231114-123456.tar.gz +``` + +**Ví dụ thực tế:** +```yaml +# data/nlu.yml - Thêm intent mới +- intent: book_flight + examples: | + - đặt vé máy bay + - tôi muốn bay đi Hà Nội + - book flight to Saigon + +# Chỉ cần: rasa train nlu +# Không cần train lại stories +``` + +**Ưu điểm:** +- ⚡ Nhanh hơn full training (30-50%) +- 💰 Tiết kiệm tài nguyên +- 🔄 Không ảnh hưởng Core model + +--- + +### 3. Core-Only Training (Train Chỉ Core) + +**Mục đích:** Chỉ train phần quản lý hội thoại + +**Khi nào dùng:** +- ✅ Chỉ thay đổi stories/rules +- ✅ Thêm actions mới +- ✅ Không thay đổi NLU data + +**Lệnh:** +```bash +rasa train core +``` + +**Quy trình:** +``` +Input: + - data/stories.yml + - data/rules.yml + - domain.yml + - config.yml (chỉ phần policies) + +Process: + 1. Load Core training data + 2. Train các policies: + - MemoizationPolicy (ghi nhớ patterns) + - TEDPolicy (machine learning) + - RulePolicy (quy tắc cố định) + +Output: + - models/core-20231114-123456.tar.gz +``` + +**Ví dụ thực tế:** +```yaml +# data/stories.yml - Thêm story mới +- story: flight booking flow + steps: + - intent: book_flight + - action: action_ask_destination + - intent: inform + - action: action_confirm_booking + +# Chỉ cần: rasa train core +# Không cần train lại NLU +``` + +--- + +### 4. Incremental Training (Fine-tuning) + +**Mục đích:** Cải thiện model có sẵn với dữ liệu mới + +**Khi nào dùng:** +- ✅ Đã có model hoạt động tốt +- ✅ Chỉ muốn thêm ví dụ mới +- ✅ Không thay đổi labels (intents/entities/actions) + +**Lệnh:** +```bash +# Finetune từ model mới nhất +rasa train --finetune + +# Hoặc chỉ định model cụ thể +rasa train --finetune models/20231114-123456.tar.gz + +# Dùng 50% epochs (nhanh hơn) +rasa train --finetune --epoch-fraction 0.5 +``` + +**Quy trình:** +``` +Input: + - Existing trained model + - New training examples (không có label mới) + +Process: + 1. Load pretrained model weights + 2. Continue training với fewer epochs + 3. Update model với new data + +Output: + - models/finetuned-20231114-123456.tar.gz +``` + +**Ví dụ:** +```yaml +# TRƯỚC: Đã có 50 ví dụ cho intent "greet" +# SAU: Thêm 10 ví dụ mới + +# data/nlu.yml (thêm) +- intent: greet + examples: | + - chào bác + - hi anh + - hello chị + +# Fine-tune (nhanh hơn 50-70% so với train từ đầu) +rasa train --finetune --epoch-fraction 0.3 +``` + +**Điều kiện:** +- ⚠️ Config phải giống y hệt (trừ epochs) +- ⚠️ Không thêm/xóa labels +- ⚠️ Model tương thích version + +**Ưu điểm:** +- ⚡ Cực nhanh (dùng 30-50% epochs) +- 📈 Kết quả tốt hơn train from scratch với ít data +- 💾 Giữ lại knowledge từ model cũ + +--- + +## Quy Trình Training + +### Bước 1: Chuẩn Bị Dữ Liệu + +#### NLU Data (data/nlu.yml) + +**Mục đích:** Dạy chatbot hiểu người dùng nói gì + +```yaml +version: "3.1" + +nlu: +- intent: greet + examples: | + - xin chào + - hello + - hi + +- intent: book_flight + examples: | + - đặt vé bay từ [Hà Nội](departure) đến [Sài Gòn](destination) + - tôi muốn bay đi [Đà Nẵng](destination) vào [ngày mai](time) + - book flight to [Tokyo](destination) +``` + +**Gồm:** +- **Intents:** Ý định của người dùng (greet, book_flight, ask_price...) +- **Examples:** Các câu mẫu +- **Entities:** Thông tin quan trọng (địa điểm, thời gian, số lượng...) + +#### Stories (data/stories.yml) + +**Mục đích:** Dạy chatbot cách dẫn dắt hội thoại + +```yaml +version: "3.1" + +stories: +- story: flight booking happy path + steps: + - intent: greet + - action: utter_greet + - intent: book_flight + entities: + - departure: "Hà Nội" + - destination: "Sài Gòn" + - action: action_search_flights + - action: utter_show_results + - intent: confirm + - action: action_book_flight + - action: utter_confirm_booking +``` + +**Giống như:** Kịch bản phim - user nói gì, bot trả lời gì + +#### Rules (data/rules.yml) + +**Mục đích:** Các quy tắc cố định, luôn đúng + +```yaml +version: "3.1" + +rules: +- rule: Say goodbye anytime + steps: + - intent: goodbye + - action: utter_goodbye + +- rule: Fallback when low confidence + steps: + - intent: nlu_fallback + - action: utter_please_rephrase +``` + +**Khác với stories:** Rules luôn được thực thi, không phụ thuộc context + +#### Domain (domain.yml) + +**Mục đích:** Định nghĩa toàn bộ "vũ trụ" của chatbot + +```yaml +version: "3.1" + +intents: + - greet + - book_flight + - goodbye + +entities: + - departure + - destination + - time + +slots: + departure: + type: text + mappings: + - type: from_entity + entity: departure + +actions: + - utter_greet + - action_search_flights + - action_book_flight + +responses: + utter_greet: + - text: "Xin chào! Tôi có thể giúp gì bạn?" +``` + +### Bước 2: Cấu Hình (config.yml) + +```yaml +recipe: default.v1 +language: vi +assistant_id: flight_booking_bot + +# Pipeline: Xử lý NLU +pipeline: + - name: WhitespaceTokenizer + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + - name: CountVectorsFeaturizer + - name: DIETClassifier + epochs: 200 + +# Policies: Quản lý dialogue +policies: + - name: MemoizationPolicy + - name: TEDPolicy + epochs: 200 + - name: RulePolicy +``` + +### Bước 3: Validate Data (Kiểm Tra) + +**Trước khi train, Rasa sẽ validate:** + +```bash +rasa data validate +``` + +**Kiểm tra:** +- ✅ Syntax errors trong YAML +- ✅ Intents trong stories có trong domain không +- ✅ Actions được định nghĩa chưa +- ✅ Story conflicts (2 stories giống nhau nhưng khác outcome) +- ✅ Missing responses + +**Ví dụ lỗi:** +``` +ERROR: Action 'action_search_flights' in story 'booking' not found in domain +FIX: Thêm 'action_search_flights' vào domain.yml +``` + +### Bước 4: Training Process + +**Chạy lệnh:** +```bash +rasa train +``` + +**Quá trình bên trong:** + +#### Phase 1: Data Loading (5-10% thời gian) +``` +[Loading] Reading training data files... + ✓ data/nlu.yml (150 examples) + ✓ data/stories.yml (20 stories) + ✓ data/rules.yml (5 rules) + ✓ domain.yml +``` + +#### Phase 2: Validation (5-10% thời gian) +``` +[Validating] Checking for inconsistencies... + ✓ All intents are valid + ✓ All actions are defined + ✓ No story conflicts detected +``` + +#### Phase 3: NLU Training (40-50% thời gian) +``` +[Training NLU] Pipeline components: + → WhitespaceTokenizer... Done + → RegexFeaturizer... Done + → CountVectorsFeaturizer... Processing (epoch 1/200) + → DIETClassifier... Processing (epoch 50/200) +``` + +**Bên trong DIETClassifier:** +- Chuyển text → vectors +- Train neural network +- Học phân biệt intents +- Học extract entities + +#### Phase 4: Core Training (30-40% thời gian) +``` +[Training Core] Policies: + → MemoizationPolicy... Done + → TEDPolicy... Processing (epoch 100/200) + → RulePolicy... Done +``` + +**Bên trong TEDPolicy:** +- Học patterns từ stories +- Dự đoán action tiếp theo +- Tối ưu với neural networks + +#### Phase 5: Model Packaging (5% thời gian) +``` +[Packaging] Creating model archive... + ✓ Saved model to: models/20231114-123456.tar.gz +``` + +**Model file chứa:** +- Trained NLU model +- Trained Core model +- Configuration +- Fingerprints (để skip unchanged parts) + +--- + +## Các Tính Năng Chính + +### 1. Fingerprinting & Caching + +**Mục đích:** Không train lại phần không thay đổi + +**Cách hoạt động:** +``` +Lần train đầu: + - NLU data: hash = abc123 + - Stories: hash = def456 + → Train cả hai + → Lưu fingerprints + +Lần train thứ 2 (chỉ sửa NLU): + - NLU data: hash = xyz789 (THAY ĐỔI) + - Stories: hash = def456 (KHÔNG ĐỔI) + → Chỉ train NLU + → Reuse Core model từ cache + → Tiết kiệm 40-60% thời gian! +``` + +**Xem logs:** +``` +Training NLU model... +Core model has not changed. Using cached model. +``` + +**Force retrain (bỏ qua cache):** +```bash +rasa train --force +``` + +### 2. Data Augmentation + +**Mục đích:** Tạo thêm training examples từ stories + +**Ví dụ:** +```yaml +# Original story +- intent: greet +- action: utter_greet +- intent: book_flight +- action: utter_ask_destination + +# Augmented variations (tự động tạo): +- intent: greet +- action: utter_greet +- intent: inform # Khác story gốc +- action: utter_ask_destination + +- intent: book_flight +- action: utter_ask_destination # Bỏ qua utter_greet +``` + +**Cấu hình:** +```yaml +policies: + - name: TEDPolicy + epochs: 200 + # Augmentation multiplier + # 50 stories → 50 * 20 = 1000 augmented stories + augmentation_factor: 20 +``` + +**Lợi ích:** +- ✅ Model robust hơn +- ✅ Xử lý tốt unexpected user behavior +- ✅ Không cần viết nhiều stories + +### 3. Story Conflict Detection + +**Mục đích:** Phát hiện stories mâu thuẫn + +**Ví dụ conflict:** +```yaml +# Story 1 +- story: booking path 1 + steps: + - intent: book_flight + - action: utter_greet # Action A + +# Story 2 +- story: booking path 2 + steps: + - intent: book_flight + - action: action_search # Action B (KHÁC!) +``` + +**Vấn đề:** Cùng input (intent) nhưng 2 output khác nhau → Model confused! + +**Phát hiện:** +```bash +rasa data validate stories +``` + +``` +Story Conflict found! + Story 1: booking path 1 + Story 2: booking path 2 + Conflicting action: utter_greet vs action_search +``` + +**Giải pháp:** +- Thêm context (slots) để phân biệt +- Hoặc merge thành 1 story duy nhất + +### 4. Interactive Learning + +**Mục đích:** Train bằng cách chat thực tế với bot + +**Lệnh:** +```bash +rasa interactive +``` + +**Quy trình:** +``` +1. User: "xin chào" +2. Bot predict: utter_greet +3. You confirm: ✓ Correct +4. User: "đặt vé máy bay" +5. Bot predict: action_search_flights +6. You correct: ✗ Wrong, should be "utter_ask_destination" +7. Rasa learn từ correction +8. Export thành story mới +``` + +**Tính năng:** +- ✅ Realtime feedback +- ✅ Tự động tạo stories +- ✅ Visualize conversation flow +- ✅ Fix mistakes ngay lập tức + +### 5. Comparison Training + +**Mục đích:** So sánh nhiều configs để chọn tốt nhất + +**Lệnh:** +```bash +rasa train core --compare \ + --config config1.yml config2.yml config3.yml \ + --runs 3 \ + --percentages 0 25 50 +``` + +**Giải thích:** +- Train 3 configs khác nhau +- Mỗi config train 3 lần (để average) +- Test với 0%, 25%, 50% data removed + +**Output:** +``` +Config 1 (TEDPolicy only): + - Accuracy: 85% + - Training time: 10 min + +Config 2 (MemoizationPolicy + TEDPolicy): + - Accuracy: 92% + - Training time: 15 min + +Config 3 (All policies): + - Accuracy: 94% + - Training time: 25 min + +→ Recommended: Config 2 (best accuracy/time trade-off) +``` + +### 6. Model Persistence & Versioning + +**Tự động versioning:** +```bash +rasa train +# Output: models/20231114-123456.tar.gz + +rasa train --fixed-model-name "production-v1" +# Output: models/production-v1.tar.gz +``` + +**Load specific model:** +```bash +rasa shell --model models/20231114-123456.tar.gz +``` + +**Model structure:** +``` +20231114-123456.tar.gz +├── nlu/ +│ ├── DIETClassifier.pkl +│ └── ... +├── core/ +│ ├── TEDPolicy.pkl +│ └── ... +├── fingerprint.json +└── metadata.json +``` + +### 7. Dry Run (Test Training) + +**Mục đích:** Kiểm tra training process mà không save model + +```bash +rasa train --dry-run +``` + +**Dùng khi:** +- ✅ Test config mới +- ✅ Estimate training time +- ✅ Debug training errors +- ✅ CI/CD validation + +--- + +## Ví Dụ Thực Tế + +### Kịch Bản 1: Chatbot Đặt Vé Máy Bay + +#### Bước 1: Setup Data + +**NLU Data:** +```yaml +# data/nlu.yml +nlu: +- intent: greet + examples: | + - xin chào + - hi + - hello + +- intent: book_flight + examples: | + - đặt vé từ [Hà Nội](departure) đến [Sài Gòn](destination) + - bay đi [Đà Nẵng](destination) + - book flight to [Tokyo](destination) from [Hanoi](departure) + +- intent: provide_date + examples: | + - [ngày mai](date) + - [15/12/2023](date) + - [next monday](date) + +- intent: confirm + examples: | + - yes + - đồng ý + - ok +``` + +**Stories:** +```yaml +# data/stories.yml +stories: +- story: successful booking + steps: + - intent: greet + - action: utter_greet + - intent: book_flight + entities: + - departure: "Hà Nội" + - destination: "Sài Gòn" + - action: utter_ask_date + - intent: provide_date + entities: + - date: "15/12" + - action: action_search_flights + - action: utter_show_results + - intent: confirm + - action: action_book_ticket + - action: utter_success +``` + +**Domain:** +```yaml +# domain.yml +intents: + - greet + - book_flight + - provide_date + - confirm + +entities: + - departure + - destination + - date + +slots: + departure: + type: text + mappings: + - type: from_entity + entity: departure + destination: + type: text + mappings: + - type: from_entity + entity: destination + +actions: + - action_search_flights + - action_book_ticket + +responses: + utter_greet: + - text: "Xin chào! Tôi có thể giúp bạn đặt vé máy bay." + utter_ask_date: + - text: "Bạn muốn bay vào ngày nào?" +``` + +#### Bước 2: Train + +```bash +# Lần đầu - Full training +rasa train + +# Output: +# Training NLU model... +# Epochs: 100/200 +# Training Core model... +# Model saved: models/20231114-120000.tar.gz +``` + +#### Bước 3: Test + +```bash +rasa shell +``` + +``` +User: xin chào +Bot: Xin chào! Tôi có thể giúp bạn đặt vé máy bay. + +User: đặt vé từ Hà Nội đi Sài Gòn +Bot: Bạn muốn bay vào ngày nào? + +User: ngày mai +Bot: [Searching flights...] +Bot: Đây là các chuyến bay khả dụng: ... +``` + +#### Bước 4: Thêm Data Mới + +```yaml +# Thêm 10 ví dụ mới vào data/nlu.yml +- intent: book_flight + examples: | + - book vé bay + - tôi cần đặt chuyến bay + - muốn bay đi công tác +``` + +```bash +# Fine-tune model (nhanh hơn) +rasa train --finetune --epoch-fraction 0.3 + +# Chỉ mất 3-5 phút thay vì 10-15 phút! +``` + +--- + +### Kịch Bản 2: Cập Nhật Model Trong Production + +**Tình huống:** Chatbot đang chạy production, cần thêm tính năng mới + +#### Week 1: Production Model +```bash +# Train và deploy +rasa train --fixed-model-name production-v1.0 +# Deploy: models/production-v1.0.tar.gz +``` + +#### Week 2: Add New Intent +```yaml +# Thêm intent mới +- intent: cancel_booking + examples: | + - hủy vé + - cancel my flight +``` + +```bash +# Train NLU only (nhanh) +rasa train nlu --fixed-model-name production-v1.1-nlu + +# Test riêng NLU +rasa shell nlu --model models/production-v1.1-nlu.tar.gz +``` + +#### Week 3: Add Stories +```yaml +# Thêm story mới +- story: cancellation flow + steps: + - intent: cancel_booking + - action: action_cancel_booking + - action: utter_cancellation_success +``` + +```bash +# Train Core only +rasa train core --fixed-model-name production-v1.1-core + +# Test +rasa interactive +``` + +#### Week 4: Full Integration +```bash +# Train full model +rasa train --fixed-model-name production-v1.1 + +# A/B testing +# 50% traffic → production-v1.0 +# 50% traffic → production-v1.1 + +# Monitor metrics, sau đó rollout 100% +``` + +--- + +## Best Practices + +### 1. Training Data Quality + +**Nguyên tắc vàng:** + +**✅ DO:** +- Ít nhất 10-15 examples/intent +- Đa dạng cách diễn đạt +- Bao gồm typos phổ biến +- Real user messages (từ logs) + +```yaml +# GOOD +- intent: greet + examples: | + - xin chào + - chào bạn + - hello + - hi + - chào buổi sáng + - chao ban # typo + - alo +``` + +**❌ DON'T:** +```yaml +# BAD - Quá ít examples +- intent: greet + examples: | + - xin chào + - hello + +# BAD - Quá giống nhau +- intent: book_flight + examples: | + - đặt vé máy bay + - đặt vé máy bay đi Hà Nội + - đặt vé máy bay đi Sài Gòn +``` + +### 2. Training Frequency + +**Khuyến nghị:** + +| Giai Đoạn | Frequency | Lý Do | +|-----------|-----------|-------| +| **Development** | Mỗi khi code thay đổi | Test nhanh | +| **Staging** | 2-3 lần/tuần | Collect feedback | +| **Production** | 1-2 lần/tháng | Stability | + +**Continuous Training Pipeline:** +```bash +# Nightly training job +0 2 * * * cd /app && rasa train --out models/nightly/ +``` + +### 3. Version Control + +**Luôn version control:** +``` +git/ +├── data/ +│ ├── nlu.yml +│ ├── stories.yml +│ └── rules.yml +├── config.yml +├── domain.yml +└── models/ # Git ignore + └── .gitignore +``` + +**Tag releases:** +```bash +git tag -a v1.0 -m "Production release 1.0" +git push origin v1.0 +``` + +### 4. Monitor Training Metrics + +**Track:** +- Training time (phát hiện regression) +- Model size (optimize deployment) +- Validation warnings (fix errors) + +```bash +# Log training metrics +rasa train 2>&1 | tee logs/training-$(date +%Y%m%d).log +``` + +### 5. Incremental Training Strategy + +**Khi nào dùng incremental:** +- ✅ Thêm < 20% examples mới +- ✅ Không thay đổi architecture +- ✅ Model hiện tại đã tốt (> 80% accuracy) + +**Khi nào train from scratch:** +- ⚠️ Thêm > 50% data mới +- ⚠️ Thay đổi pipeline/policies +- ⚠️ Major refactor + +--- + +## Troubleshooting + +### Lỗi 1: Training Quá Lâu + +**Triệu chứng:** +``` +Training Core model... +Epochs: 50/200 (30 minutes passed...) +``` + +**Nguyên nhân:** +- Quá nhiều epochs +- Model quá phức tạp +- Dataset quá lớn + +**Giải pháp:** +```yaml +# Giảm epochs +policies: + - name: TEDPolicy + epochs: 100 # Thay vì 200 + +# Hoặc dùng smaller model + - name: TEDPolicy + epochs: 200 + transformer_size: 128 # Thay vì 256 + number_of_transformer_layers: 1 # Thay vì 2 +``` + +### Lỗi 2: Out of Memory + +**Triệu chứng:** +``` +Killed +(Process terminated) +``` + +**Giải pháp:** +```yaml +# Giảm batch size +policies: + - name: TEDPolicy + batch_size: [32, 64] # Thay vì [64, 256] + +pipeline: + - name: DIETClassifier + batch_size: [32, 64] +``` + +**Hoặc:** +```bash +# Train trên máy mạnh hơn +# Sử dụng cloud GPU +``` + +### Lỗi 3: Model Không Cải Thiện + +**Triệu chứng:** +``` +Epoch 100: loss=0.5, accuracy=75% +Epoch 150: loss=0.49, accuracy=76% +Epoch 200: loss=0.48, accuracy=76% +# Stuck! +``` + +**Nguyên nhân:** +- Training data kém chất lượng +- Config không phù hợp +- Overfitting + +**Giải pháp:** + +1. **Thêm data chất lượng:** +```yaml +# Phân tích confusion matrix +rasa test nlu --report confusion/ + +# Thêm examples cho intents bị confuse +``` + +2. **Tuning hyperparameters:** +```yaml +pipeline: + - name: DIETClassifier + epochs: 300 # Tăng + learning_rate: 0.001 # Điều chỉnh +``` + +3. **Regularization:** +```yaml +pipeline: + - name: DIETClassifier + drop_rate: 0.2 # Thêm dropout +``` + +### Lỗi 4: Story Conflicts + +**Triệu chứng:** +``` +UserWarning: Story structure conflict found in stories: + 'story_1' and 'story_2' +``` + +**Giải pháp:** + +```yaml +# BEFORE - Conflict +- story: ask price path 1 + steps: + - intent: ask_price + - action: utter_price_range # Action A + +- story: ask price path 2 + steps: + - intent: ask_price + - action: action_calculate_price # Action B (conflict!) + +# AFTER - Add context với slots +- story: ask price with destination + steps: + - intent: ask_price + - slot_was_set: + - destination: "Hanoi" + - action: action_calculate_price # Khi có destination + +- story: ask price without destination + steps: + - intent: ask_price + - action: utter_price_range # Khi chưa có destination +``` + +--- + +## Tóm Tắt + +### Module Training Trong 1 Phút + +**Training là gì?** +- Quá trình dạy chatbot hiểu và phản hồi người dùng + +**Input:** +- NLU data (câu mẫu) +- Stories (kịch bản) +- Rules (quy tắc) +- Config (cấu hình) + +**Process:** +1. Load data +2. Validate +3. Train NLU (hiểu ngôn ngữ) +4. Train Core (quản lý hội thoại) +5. Package model + +**Output:** +- File .tar.gz chứa trained model + +**4 Loại Training:** +1. **Full** - Train toàn bộ +2. **NLU-only** - Chỉ train language understanding +3. **Core-only** - Chỉ train dialogue management +4. **Incremental** - Fine-tune model có sẵn (nhanh nhất) + +**Tính Năng Nổi Bật:** +- ⚡ Caching - Skip phần không đổi +- 🔄 Augmentation - Tự tạo variations +- 🔍 Validation - Phát hiện lỗi +- 📊 Interactive - Train bằng chat +- 🎯 Comparison - So sánh configs + +**Best Practices:** +- ✅ 10-15 examples/intent minimum +- ✅ Version control everything +- ✅ Incremental training khi có thể +- ✅ Monitor metrics +- ✅ Test before deploy + +--- + +## Kết Luận + +Module Training là **nền tảng** của Rasa. Hiểu rõ cách training hoạt động giúp bạn: + +✅ Xây dựng chatbot chất lượng cao +✅ Optimize training time & resources +✅ Debug problems nhanh hơn +✅ Scale chatbot hiệu quả + +**Next Steps:** +1. Đọc thêm: [Model Configuration](docs/docs/model-configuration.mdx) +2. Practice: Train chatbot mẫu +3. Advanced: Custom components & policies + +**Happy Training!** 🚀🤖 diff --git a/VIETNAMESE_LANGUAGE_GUIDE.md b/VIETNAMESE_LANGUAGE_GUIDE.md new file mode 100644 index 000000000000..4b1086e2eb1c --- /dev/null +++ b/VIETNAMESE_LANGUAGE_GUIDE.md @@ -0,0 +1,635 @@ +# Hướng Dẫn Cấu Hình Rasa Cho Tiếng Việt + +## Tóm Tắt + +**Câu trả lời ngắn gọn:** Rasa **CÓ HỖ TRỢ** tiếng Việt, nhưng **KHÔNG TỐI ƯU 100%** với cấu hình mặc định. + +### Mức Độ Hỗ Trợ + +| Tính Năng | Hỗ Trợ | Chất Lượng | Ghi Chú | +|-----------|--------|-----------|---------| +| **Intent Classification** | ✅ Tốt | 75-85% | Hoạt động tốt với WhitespaceTokenizer | +| **Entity Extraction** | ⚠️ Trung bình | 60-70% | Cần nhiều training data | +| **Word Tokenization** | ⚠️ Trung bình | 60-75% | Tiếng Việt có từ ghép phức tạp | +| **Pre-trained Models** | ❌ Hạn chế | - | spaCy không có model tiếng Việt | +| **Custom Training** | ✅ Tốt | 70-90% | Tùy thuộc vào dữ liệu training | + +--- + +## Phân Tích Chi Tiết + +### 1. Tại Sao Tiếng Việt Khó Với NLU? + +Tiếng Việt có những đặc điểm riêng biệt: + +**a) Từ ghép phức tạp:** +``` +"Hồ Chí Minh" = 3 tokens nhưng là 1 entity +"máy tính" = 2 từ nhưng là 1 khái niệm +"TP.HCM" vs "Thành phố Hồ Chí Minh" = cùng ý nghĩa +``` + +**b) Dấu thanh & dấu chữ cái:** +``` +"ma" ≠ "mà" ≠ "má" ≠ "mả" ≠ "mã" ≠ "mạ" +``` + +**c) Whitespace tokenization không hoàn hảo:** +``` +Input: "Tôi muốn đặt vé máy bay đi Hồ Chí Minh" +WhitespaceTokenizer: ["Tôi", "muốn", "đặt", "vé", "máy", "bay", "đi", "Hồ", "Chí", "Minh"] +Lý tưởng: ["Tôi", "muốn", "đặt", "vé", "máy_bay", "đi", "Hồ_Chí_Minh"] +``` + +### 2. Rasa Hỗ Trợ Tiếng Việt Như Thế Nào? + +Theo [tài liệu chính thức](docs/docs/language-support.mdx:27), Rasa nói: + +> **"Not supported languages"**: Chinese (zh), Japanese (ja), Thai (th) + +**Tiếng Việt KHÔNG có trong danh sách này** → Nghĩa là **CÓ THỂ SỬ DỤNG** với WhitespaceTokenizer. + +**Ưu điểm:** +- ✅ Tiếng Việt có dấu cách giữa các từ (khác với tiếng Trung, Nhật, Thái) +- ✅ Có thể dùng pipeline mặc định mà không cần tokenizer đặc biệt +- ✅ DIETClassifier và TEDPolicy hoạt động tốt với tiếng Việt + +**Nhược điểm:** +- ❌ Không có pre-trained spaCy model cho tiếng Việt +- ❌ WhitespaceTokenizer không xử lý tốt từ ghép +- ❌ Cần nhiều training data hơn so với tiếng Anh + +--- + +## Cấu Hình Khuyến Nghị + +### Cách 1: Pipeline Cơ Bản (Nhanh & Đơn Giản) + +Thích hợp cho: **Dự án nhỏ, prototype, ít dữ liệu** + +**File `config.yml`:** +```yaml +language: vi + +pipeline: + # Tokenizer + - name: WhitespaceTokenizer + + # Featurizers + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + - name: CountVectorsFeaturizer + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 1 + max_ngram: 4 + + # Intent Classifier & Entity Extractor + - name: DIETClassifier + epochs: 200 # Tăng từ 100 lên 200 cho tiếng Việt + entity_recognition: True + intent_classification: True + + # Entity Synonym Mapper + - name: EntitySynonymMapper + + # Response Selector (nếu dùng FAQs) + - name: ResponseSelector + epochs: 200 + +policies: + - name: MemoizationPolicy + max_history: 5 + - name: TEDPolicy + max_history: 5 + epochs: 200 + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: "action_default_fallback" +``` + +**Ưu điểm:** +- ✅ Setup nhanh, không cần cài thêm dependencies +- ✅ Tốc độ training nhanh +- ✅ Phù hợp với chatbot đơn giản + +**Nhược điểm:** +- ⚠️ Accuracy thấp hơn với câu phức tạp +- ⚠️ Cần nhiều ví dụ training cho mỗi intent + +--- + +### Cách 2: Pipeline Nâng Cao (Chất Lượng Cao Hơn) + +Thích hợp cho: **Production, chatbot phức tạp, nhiều dữ liệu** + +**File `config.yml`:** +```yaml +language: vi + +pipeline: + # Tokenizer + - name: WhitespaceTokenizer + token_pattern: '(?u)\b\w+\b' # Custom regex cho tiếng Việt + + # Featurizers + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + + # Character n-grams (tốt cho tiếng Việt) + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 2 + max_ngram: 5 + + # Word n-grams + - name: CountVectorsFeaturizer + analyzer: word + min_ngram: 1 + max_ngram: 3 + + # DIET Classifier với cấu hình tối ưu + - name: DIETClassifier + epochs: 300 + batch_size: [64, 256] + embedding_dimension: 30 + number_of_transformer_layers: 2 + transformer_size: 256 + use_masked_language_model: True + entity_recognition: True + intent_classification: True + BILOU_flag: True + + # Fallback Classifier + - name: FallbackClassifier + threshold: 0.7 + ambiguity_threshold: 0.1 + + # Entity Synonym Mapper + - name: EntitySynonymMapper + + # Response Selector + - name: ResponseSelector + epochs: 300 + retrieval_intent: faq + +policies: + - name: MemoizationPolicy + max_history: 7 + + - name: TEDPolicy + max_history: 7 + epochs: 300 + batch_size: [32, 64] + number_of_transformer_layers: 2 + transformer_size: 256 + + - name: RulePolicy + core_fallback_threshold: 0.3 +``` + +**Ưu điểm:** +- ✅ Accuracy cao hơn 10-15% +- ✅ Xử lý tốt các câu phức tạp +- ✅ Fallback thông minh + +**Nhược điểm:** +- ⚠️ Training lâu hơn (2-5 lần) +- ⚠️ Cần RAM cao hơn (8GB+) + +--- + +### Cách 3: Sử Dụng Tokenizer Tiếng Việt Chuyên Dụng + +Để đạt kết quả **TỐT NHẤT**, sử dụng tokenizer tiếng Việt. + +#### Bước 1: Tạo Custom Tokenizer Component + +**File `components/vietnamese_tokenizer.py`:** + +```python +from typing import Any, Dict, List, Text +from rasa.nlu.tokenizers.tokenizer import Token, Tokenizer +from rasa.engine.recipes.default_recipe import DefaultV1Recipe +from rasa.shared.nlu.training_data.message import Message + +try: + from pyvi import ViTokenizer + PYVI_AVAILABLE = True +except ImportError: + PYVI_AVAILABLE = False + + +@DefaultV1Recipe.register( + DefaultV1Recipe.ComponentType.MESSAGE_TOKENIZER, is_trainable=False +) +class VietnameseTokenizer(Tokenizer): + """Tokenizer for Vietnamese using PyVi.""" + + @staticmethod + def required_packages() -> List[Text]: + return ["pyvi"] + + def tokenize(self, message: Message, attribute: Text) -> List[Token]: + """Tokenize Vietnamese text.""" + if not PYVI_AVAILABLE: + raise ImportError( + "PyVi is not installed. Install it with: pip install pyvi" + ) + + text = message.get(attribute) + + # Tokenize using PyVi + tokenized_text = ViTokenizer.tokenize(text) + words = tokenized_text.split() + + # Create Token objects + tokens = self._convert_words_to_tokens(words, text) + + return tokens +``` + +#### Bước 2: Cài Đặt PyVi + +**Trong Dockerfile:** +```dockerfile +FROM rasa/rasa:3.6.21-full + +# Cài đặt PyVi +RUN pip install pyvi underthesea +``` + +**Hoặc local:** +```bash +pip install pyvi underthesea +``` + +#### Bước 3: Cấu Hình + +**File `config.yml`:** +```yaml +language: vi + +pipeline: + # Sử dụng Vietnamese Tokenizer + - name: components.vietnamese_tokenizer.VietnameseTokenizer + + # Các component khác... + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 2 + max_ngram: 5 + - name: DIETClassifier + epochs: 300 +``` + +**Lợi ích:** +- ✅ Tokenization chính xác hơn 30-40% +- ✅ Xử lý tốt từ ghép: "máy_bay", "Hồ_Chí_Minh" +- ✅ Entity extraction tốt hơn + +--- + +## Ví Dụ Training Data + +### File `data/nlu.yml` + +```yaml +version: "3.1" + +nlu: +- intent: greet + examples: | + - xin chào + - chào bạn + - hello + - hi + - chào buổi sáng + - chào buổi chiều + - chào buổi tối + +- intent: goodbye + examples: | + - tạm biệt + - bye + - hẹn gặp lại + - see you + - chào tạm biệt + - bye bye + +- intent: book_flight + examples: | + - tôi muốn đặt vé máy bay + - đặt vé bay từ [Hà Nội](departure) đến [Hồ Chí Minh](destination) + - tôi muốn bay đi [Đà Nẵng](destination) vào [ngày mai](time) + - book vé máy bay đi [Nha Trang](destination) + - đặt vé từ [Sài Gòn](departure) đến [Hà Nội](destination) ngày [15/12](time) + - tôi cần vé bay đi [Phú Quốc](destination) + +- intent: ask_price + examples: | + - giá vé bao nhiêu + - vé máy bay giá bao nhiêu + - cho tôi biết giá vé + - giá cả như thế nào + - bao nhiêu tiền một vé + +- intent: faq/operating_hours + examples: | + - mấy giờ mở cửa + - giờ làm việc + - bao giờ bạn online + - thời gian hoạt động + +- intent: faq/contact + examples: | + - số điện thoại + - liên hệ như thế nào + - email của bạn + - tôi muốn gọi điện +``` + +### Mẹo Tạo Training Data Cho Tiếng Việt + +1. **Dùng cả từ có dấu và không dấu:** +```yaml +- tôi muốn đặt phòng +- toi muon dat phong +``` + +2. **Bao gồm variations:** +```yaml +- giá bao nhiêu +- giá cả ra sao +- bao nhiêu tiền +- giá thế nào +``` + +3. **Entities phổ biến:** +```yaml +- [Hà Nội](city) +- [TP.HCM](city) +- [Thành phố Hồ Chí Minh](city) # Synonym +- [Sài Gòn](city) # Synonym +``` + +4. **Synonyms (file `domain.yml`):** +```yaml +entities: + - city + +slots: + city: + type: text + mappings: + - type: from_entity + entity: city + +responses: + utter_greet: + - text: "Xin chào! Tôi có thể giúp gì cho bạn?" + +# Entity Synonyms +entities: + - entity: city + synonyms: + - "TP.HCM": "Hồ Chí Minh" + - "Sài Gòn": "Hồ Chí Minh" + - "HN": "Hà Nội" + - "Đà Nẵng": "Da Nang" +``` + +--- + +## Best Practices Cho Tiếng Việt + +### 1. Training Data + +**Số lượng tối thiểu:** +- **Intent Classification:** 15-30 ví dụ/intent +- **Entity Extraction:** 50+ ví dụ có entity +- **Tổng cộng:** 300+ câu cho chatbot đơn giản + +**Chất lượng:** +- ✅ Đa dạng cách diễn đạt +- ✅ Bao gồm typos phổ biến +- ✅ Cả formal và informal language +- ✅ Viết hoa và viết thường + +### 2. Hyperparameter Tuning + +Cho tiếng Việt, tăng số epochs: + +```yaml +pipeline: + - name: DIETClassifier + epochs: 200-300 # Thay vì 100 + +policies: + - name: TEDPolicy + epochs: 200-300 # Thay vì 100 +``` + +### 3. Character N-grams + +Quan trọng cho tiếng Việt vì xử lý dấu: + +```yaml + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 2 + max_ngram: 5 # Tăng lên 5-6 cho tiếng Việt +``` + +### 4. Testing & Evaluation + +```bash +# Test model +rasa test nlu --nlu data/nlu.yml + +# Cross-validation +rasa test nlu --nlu data/nlu.yml --cross-validation + +# Xem confusion matrix +rasa test nlu --nlu data/nlu.yml --report test_results/ +``` + +--- + +## Benchmark & Hiệu Suất + +### Kết Quả Thực Tế (từ community) + +| Pipeline | Intent Accuracy | Entity F1 | Training Time | +|----------|----------------|-----------|---------------| +| **Baseline (WhitespaceTokenizer)** | 72-78% | 60-65% | 2-5 phút | +| **Nâng Cao (Character n-grams)** | 80-88% | 68-75% | 10-20 phút | +| **PyVi Tokenizer** | 85-92% | 75-85% | 15-30 phút | + +**Nguồn tham khảo:** +- Rasa Community Forum: https://forum.rasa.com/ +- Các dự án Vietnam NLU trên GitHub + +### Cải Thiện Accuracy + +**Nếu accuracy < 70%:** +1. ✅ Thêm training data (x2-x3) +2. ✅ Tăng epochs lên 300-500 +3. ✅ Sử dụng PyVi tokenizer +4. ✅ Thêm nhiều character n-grams + +**Nếu entity extraction kém:** +1. ✅ Thêm nhiều ví dụ có entity (50+ cho mỗi entity type) +2. ✅ Dùng regex patterns cho entities cố định +3. ✅ Enable BILOU_flag trong DIETClassifier + +--- + +## Giải Pháp Thay Thế + +Nếu Rasa không đáp ứng được yêu cầu: + +### 1. Sử Dụng Pre-processing + +**Chuẩn hóa text trước khi đưa vào Rasa:** + +```python +from pyvi import ViTokenizer +from underthesea import text_normalize + +def preprocess_vietnamese(text): + # Normalize + text = text_normalize(text) + + # Tokenize + text = ViTokenizer.tokenize(text) + + return text + +# Trong custom action: +user_message = preprocess_vietnamese(user_message) +``` + +### 2. Hybrid Approach + +**Kết hợp Rasa với Vietnamese NLP libraries:** + +```yaml +# Dùng PhoBERT cho Intent Classification +# Dùng Rasa cho Dialogue Management +``` + +### 3. Các Framework Khác + +Nếu chỉ cần NLU cho tiếng Việt: +- **VnCoreNLP:** Toolkit NLP tiếng Việt +- **PhoBERT:** BERT model cho tiếng Việt +- **Underthesea:** Vietnamese NLP Toolkit + +--- + +## Docker Setup Cho Tiếng Việt + +### Dockerfile Với PyVi + +```dockerfile +FROM rasa/rasa:3.6.21-full + +USER root + +# Cài đặt Vietnamese NLP libraries +RUN pip install --no-cache-dir \ + pyvi==0.1.1 \ + underthesea==6.7.0 + +# Copy custom components +COPY components /app/components/ + +USER 1001 +``` + +### docker-compose.yml + +```yaml +version: '3.8' + +services: + rasa: + build: + context: . + dockerfile: Dockerfile.vi + ports: + - "5005:5005" + volumes: + - ./:/app + command: + - run + - --enable-api + - --cors + - "*" + environment: + - RASA_TELEMETRY_ENABLED=false + - LANG=vi_VN.UTF-8 # Quan trọng cho encoding + - LC_ALL=vi_VN.UTF-8 +``` + +--- + +## Kết Luận + +### Câu Trả Lời Cuối Cùng + +**Rasa có hỗ trợ tiếng Việt tốt không?** + +**Trả lời:** +- ✅ **CÓ**, Rasa hỗ trợ tiếng Việt +- ⚠️ **NHƯNG** không tối ưu như tiếng Anh +- 📊 **ACCURACY:** 70-90% (tùy cấu hình & data) +- 🚀 **KHUYẾN NGHỊ:** Dùng PyVi tokenizer + nhiều training data + +### Khi Nào Nên Dùng Rasa Cho Tiếng Việt? + +**✅ NÊN DÙNG:** +- Chatbot với dialogue management phức tạp +- Cần quản lý context & multi-turn conversation +- Có đủ thời gian & data để train +- Dự án dài hạn, cần customize + +**❌ KHÔNG NÊN DÙNG:** +- Chỉ cần simple FAQ bot → Dùng regex hoặc keyword matching +- Không có nhiều training data (< 200 câu) +- Cần accuracy > 95% ngay từ đầu +- Dự án ngắn hạn, cần kết quả nhanh + +### Lộ Trình Phát Triển + +1. **Week 1:** Setup với pipeline cơ bản + 100 câu training +2. **Week 2:** Test và thu thập thêm data từ users +3. **Week 3:** Tăng data lên 300-500 câu + tuning +4. **Week 4:** Deploy với PyVi tokenizer +5. **Ongoing:** Continuous improvement với user feedback + +--- + +## Tài Liệu Tham Khảo + +### Rasa Resources +- **Rasa Docs - Language Support:** https://rasa.com/docs/rasa/language-support +- **Rasa Forum:** https://forum.rasa.com/ +- **Rasa Components:** https://rasa.com/docs/rasa/components + +### Vietnamese NLP Tools +- **PyVi:** https://github.com/trungtv/pyvi +- **Underthesea:** https://github.com/undertheseanlp/underthesea +- **VnCoreNLP:** https://github.com/vncorenlp/VnCoreNLP +- **PhoBERT:** https://github.com/VinAIResearch/PhoBERT + +### Community Projects +- Rasa Vietnamese examples trên GitHub +- Vietnam NLP community discussions + +--- + +**Tóm lại:** Rasa **CÓ THỂ** dùng cho tiếng Việt và hoạt động **KHÁ TỐT** (75-85% accuracy) với cấu hình đúng và đủ training data. Để đạt kết quả tốt nhất, nên kết hợp với PyVi tokenizer và tối ưu hyperparameters cho tiếng Việt! 🇻🇳🚀 diff --git a/actions/actions_llm.py b/actions/actions_llm.py new file mode 100644 index 000000000000..b60586532477 --- /dev/null +++ b/actions/actions_llm.py @@ -0,0 +1,364 @@ +""" +Custom Rasa Actions with LLM Integration +Hybrid approach: Rasa + OpenAI/Claude +""" +import logging +from typing import Any, Text, Dict, List +from rasa_sdk import Action, Tracker +from rasa_sdk.executor import CollectingDispatcher +from rasa_sdk.events import SlotSet, FollowupAction + +# Import LLM modules +from actions.llm.providers import get_provider +from actions.llm.fallback import LLMFallbackHandler +from actions.llm.response_enhancer import ResponseEnhancer +from actions.llm.intent_clarifier import IntentClarifier + +logger = logging.getLogger(__name__) + + +# ============================================================================ +# Configuration - Change these to switch between providers +# ============================================================================ + +# Provider: 'openai' or 'claude' +LLM_PROVIDER = "openai" # Change to 'claude' to use Claude + +# Model names +OPENAI_MODEL = "gpt-4" # or "gpt-3.5-turbo" for cheaper option +CLAUDE_MODEL = "claude-3-5-sonnet-20241022" # or "claude-3-haiku-20240307" + +# Fallback threshold +CONFIDENCE_THRESHOLD = 0.7 + + +# ============================================================================ +# Initialize LLM Components +# ============================================================================ + +def get_llm_components(): + """Get initialized LLM components""" + try: + # Get provider + if LLM_PROVIDER == "openai": + provider = get_provider("openai", model=OPENAI_MODEL) + elif LLM_PROVIDER == "claude": + provider = get_provider("claude", model=CLAUDE_MODEL) + else: + raise ValueError(f"Unknown provider: {LLM_PROVIDER}") + + # Initialize components + fallback_handler = LLMFallbackHandler( + provider=provider, + confidence_threshold=CONFIDENCE_THRESHOLD + ) + response_enhancer = ResponseEnhancer(provider=provider) + intent_clarifier = IntentClarifier(provider=provider) + + return fallback_handler, response_enhancer, intent_clarifier + + except Exception as e: + logger.error(f"❌ Failed to initialize LLM components: {e}") + return None, None, None + + +# Initialize once +FALLBACK_HANDLER, RESPONSE_ENHANCER, INTENT_CLARIFIER = get_llm_components() + + +# ============================================================================ +# Action: LLM Fallback +# ============================================================================ + +class ActionLLMFallback(Action): + """ + Fallback to LLM when Rasa confidence is low + + Usage in config.yml: + policies: + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: "action_llm_fallback" + """ + + def name(self) -> Text: + return "action_llm_fallback" + + def run( + self, + dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any], + ) -> List[Dict[Text, Any]]: + + if not FALLBACK_HANDLER or not FALLBACK_HANDLER.provider.is_available(): + # LLM not available + dispatcher.utter_message( + text="Xin lỗi, tôi không hiểu. Bạn có thể diễn đạt lại không?" + ) + return [] + + # Get user message + user_message = tracker.latest_message.get("text", "") + + # Get intent info for logging + intent_info = tracker.latest_message.get("intent", {}) + + # Build context from conversation history + context = FALLBACK_HANDLER.build_context(tracker.events) + + # Generate response using LLM + try: + llm_response = FALLBACK_HANDLER.generate_response( + user_message=user_message, + context=context, + intent_info=intent_info + ) + + dispatcher.utter_message(text=llm_response) + + # Log metrics + return [SlotSet("last_fallback_used", True)] + + except Exception as e: + logger.error(f"❌ LLM fallback failed: {e}") + dispatcher.utter_message( + text="Xin lỗi, tôi đang gặp sự cố. Bạn có thể thử lại sau không?" + ) + return [] + + +# ============================================================================ +# Action: Show Flights (with LLM enhancement) +# ============================================================================ + +class ActionShowFlights(Action): + """ + Show flight search results with LLM-enhanced response + """ + + def name(self) -> Text: + return "action_show_flights" + + def run( + self, + dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any], + ) -> List[Dict[Text, Any]]: + + # Get slots + departure = tracker.get_slot("departure") + destination = tracker.get_slot("destination") + date = tracker.get_slot("travel_date") + passengers = tracker.get_slot("num_passengers") or 1 + + # Mock database query (replace with real DB call) + flights_data = { + "departure": departure, + "destination": destination, + "date": date, + "passengers": passengers, + "results": [ + { + "airline": "Vietnam Airlines", + "flight_number": "VN123", + "departure_time": "08:00", + "arrival_time": "10:15", + "price": "2,500,000", + "duration": "2h 15m", + "aircraft": "Boeing 787" + }, + { + "airline": "VietJet Air", + "flight_number": "VJ456", + "departure_time": "14:30", + "arrival_time": "16:45", + "price": "1,800,000", + "duration": "2h 15m", + "aircraft": "Airbus A321" + } + ] + } + + # Enhance response with LLM + if RESPONSE_ENHANCER and RESPONSE_ENHANCER.provider.is_available(): + try: + enhanced_response = RESPONSE_ENHANCER.enhance_flight_results( + flights_data=flights_data + ) + dispatcher.utter_message(text=enhanced_response) + + except Exception as e: + logger.error(f"❌ Response enhancement failed: {e}") + # Fallback to simple template + dispatcher.utter_message( + text=f"Tìm thấy {len(flights_data['results'])} chuyến bay " + f"từ {departure} đến {destination}." + ) + else: + # No LLM available, use simple response + dispatcher.utter_message( + text=f"Tìm thấy {len(flights_data['results'])} chuyến bay." + ) + + return [SlotSet("flight_search_done", True)] + + +# ============================================================================ +# Action: Confirm Booking (with LLM enhancement) +# ============================================================================ + +class ActionConfirmBooking(Action): + """ + Confirm booking with LLM-enhanced message + """ + + def name(self) -> Text: + return "action_confirm_booking" + + def run( + self, + dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any], + ) -> List[Dict[Text, Any]]: + + # Mock booking (replace with real booking API) + booking_data = { + "booking_code": "ABC123XYZ", + "passenger_name": tracker.get_slot("passenger_name") or "Quý khách", + "flight_number": "VN123", + "departure": tracker.get_slot("departure"), + "destination": tracker.get_slot("destination"), + "date": tracker.get_slot("travel_date"), + "seat": "12A", + "price": "2,500,000" + } + + # Enhance confirmation with LLM + if RESPONSE_ENHANCER and RESPONSE_ENHANCER.provider.is_available(): + try: + enhanced_confirmation = RESPONSE_ENHANCER.enhance_booking_confirmation( + booking_data=booking_data + ) + dispatcher.utter_message(text=enhanced_confirmation) + + except Exception as e: + logger.error(f"❌ Confirmation enhancement failed: {e}") + dispatcher.utter_message( + text=f"✅ Đặt vé thành công! " + f"Mã đặt chỗ: {booking_data['booking_code']}" + ) + else: + dispatcher.utter_message( + text=f"✅ Đặt vé thành công! Mã: {booking_data['booking_code']}" + ) + + return [ + SlotSet("booking_code", booking_data["booking_code"]), + SlotSet("booking_confirmed", True) + ] + + +# ============================================================================ +# Action: Clarify Intent +# ============================================================================ + +class ActionClarifyIntent(Action): + """ + Use LLM to clarify ambiguous intents + + Triggered when top 2 intents have similar confidence + """ + + def name(self) -> Text: + return "action_clarify_intent" + + def run( + self, + dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any], + ) -> List[Dict[Text, Any]]: + + if not INTENT_CLARIFIER or not INTENT_CLARIFIER.provider.is_available(): + # LLM not available, ask user directly + dispatcher.utter_message( + text="Xin lỗi, bạn có thể nói rõ hơn không?" + ) + return [] + + # Get intent ranking + intent_ranking = tracker.latest_message.get("intent_ranking", []) + + if not INTENT_CLARIFIER.is_ambiguous(intent_ranking): + # Not ambiguous, proceed normally + return [] + + user_message = tracker.latest_message.get("text", "") + context = FALLBACK_HANDLER.build_context(tracker.events) if FALLBACK_HANDLER else "" + + try: + # Clarify intent using LLM + clarified_intent = INTENT_CLARIFIER.clarify_intent( + user_message=user_message, + intent_ranking=intent_ranking, + context=context + ) + + # Or ask user for clarification + # clarification_question = INTENT_CLARIFIER.get_clarification_question( + # intent_ranking=intent_ranking + # ) + # dispatcher.utter_message(text=clarification_question) + + return [SlotSet("clarified_intent", clarified_intent)] + + except Exception as e: + logger.error(f"❌ Intent clarification failed: {e}") + dispatcher.utter_message( + text="Xin lỗi, bạn có thể diễn đạt lại không?" + ) + return [] + + +# ============================================================================ +# Action: Handle Out of Scope +# ============================================================================ + +class ActionHandleOutOfScope(Action): + """ + Handle out-of-scope questions with LLM + """ + + def name(self) -> Text: + return "action_handle_out_of_scope" + + def run( + self, + dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any], + ) -> List[Dict[Text, Any]]: + + user_message = tracker.latest_message.get("text", "") + + if FALLBACK_HANDLER and FALLBACK_HANDLER.provider.is_available(): + try: + response = FALLBACK_HANDLER.handle_out_of_scope(user_message) + dispatcher.utter_message(text=response) + + except Exception as e: + logger.error(f"❌ Out-of-scope handling failed: {e}") + dispatcher.utter_message( + text="Xin lỗi, tôi chỉ hỗ trợ đặt vé máy bay. " + "Tôi có thể giúp bạn tìm chuyến bay không? ✈️" + ) + else: + dispatcher.utter_message( + text="Xin lỗi, tôi chỉ hỗ trợ đặt vé máy bay. " + "Bạn cần giúp gì về vé máy bay không?" + ) + + return [] diff --git a/actions/llm/__init__.py b/actions/llm/__init__.py new file mode 100644 index 000000000000..29e8011842b6 --- /dev/null +++ b/actions/llm/__init__.py @@ -0,0 +1,20 @@ +""" +LLM Integration Module for Rasa +Supports: OpenAI GPT-4, Claude AI, and other LLMs +""" + +from .providers import OpenAIProvider, ClaudeProvider, LLMProvider +from .fallback import LLMFallbackHandler +from .response_enhancer import ResponseEnhancer +from .intent_clarifier import IntentClarifier + +__all__ = [ + "OpenAIProvider", + "ClaudeProvider", + "LLMProvider", + "LLMFallbackHandler", + "ResponseEnhancer", + "IntentClarifier", +] + +__version__ = "1.0.0" diff --git a/actions/llm/fallback.py b/actions/llm/fallback.py new file mode 100644 index 000000000000..4265e09cc7f0 --- /dev/null +++ b/actions/llm/fallback.py @@ -0,0 +1,189 @@ +""" +LLM Fallback Handler - Handle low confidence intents +""" +import logging +from typing import List, Dict, Optional, Any +from .providers import LLMProvider + +logger = logging.getLogger(__name__) + + +class LLMFallbackHandler: + """ + Handles fallback to LLM when Rasa confidence is low + """ + + def __init__( + self, + provider: LLMProvider, + confidence_threshold: float = 0.7, + context_length: int = 5 + ): + """ + Args: + provider: LLM provider instance + confidence_threshold: Trigger fallback below this confidence + context_length: Number of previous messages to include as context + """ + self.provider = provider + self.confidence_threshold = confidence_threshold + self.context_length = context_length + + self.system_prompt = self._get_default_system_prompt() + + def _get_default_system_prompt(self) -> str: + """Get default system prompt""" + return """Bạn là trợ lý đặt vé máy bay thông minh và thân thiện. + +QUY TẮC QUAN TRỌNG: +1. CHỈ giúp về đặt vé máy bay (booking, hủy vé, đổi lịch, hỏi giá) +2. Nếu user hỏi ngoài topic → Lịch sự từ chối và chuyển hướng về đặt vé +3. Trả lời NGẮN GỌN, rõ ràng (tối đa 3 câu) +4. Luôn hỏi thông tin CẦN THIẾT để giúp user +5. KHÔNG BAO GIỜ bịa thông tin chuyến bay hoặc giá vé + +PHONG CÁCH: +- Thân thiện, nhiệt tình +- Gọi user bằng "bạn" +- Dùng emoji phù hợp (✈️, 🛫, 💰, 📅) + +VÍ DỤ TỐT: +User: "Thời tiết Paris thế nào?" +Bot: "Tôi không có thông tin thời tiết, nhưng tôi có thể giúp bạn đặt vé bay đến Paris! ✈️ Bạn muốn xem các chuyến bay không?" + +VÍ DỤ XẤU: +Bot: "Xin lỗi tôi không biết." ← Không helpful, không redirect +""" + + def set_system_prompt(self, prompt: str): + """Update system prompt""" + self.system_prompt = prompt + + def should_fallback(self, confidence: float) -> bool: + """Check if should fallback to LLM""" + return confidence < self.confidence_threshold + + def build_context(self, events: List[Dict]) -> str: + """ + Build conversation context from tracker events + + Args: + events: List of tracker events + + Returns: + Formatted context string + """ + context_messages = [] + count = 0 + + # Get last N messages + for event in reversed(events): + if count >= self.context_length: + break + + if event.get("event") == "user": + context_messages.append(f"User: {event.get('text', '')}") + count += 1 + elif event.get("event") == "bot": + text = event.get("text") or event.get("data", {}).get("text", "") + if text: + context_messages.append(f"Bot: {text}") + + # Reverse to chronological order + context_messages.reverse() + + return "\n".join(context_messages) if context_messages else "No previous context." + + def generate_response( + self, + user_message: str, + context: str = "", + intent_info: Optional[Dict] = None + ) -> str: + """ + Generate fallback response using LLM + + Args: + user_message: Current user message + context: Previous conversation context + intent_info: Rasa intent detection info (for debugging) + + Returns: + Generated response + """ + if not self.provider.is_available(): + logger.warning("⚠️ LLM provider not available, using default fallback") + return "Xin lỗi, tôi không hiểu. Bạn có thể diễn đạt lại không?" + + # Build messages + messages = [ + {"role": "system", "content": self.system_prompt} + ] + + # Add context if available + if context: + messages.append({ + "role": "user", + "content": f"Ngữ cảnh hội thoại trước:\n{context}" + }) + messages.append({ + "role": "assistant", + "content": "Tôi đã hiểu ngữ cảnh." + }) + + # Add current message + messages.append({ + "role": "user", + "content": user_message + }) + + # Log fallback + logger.info( + f"🔄 LLM Fallback triggered | " + f"User: '{user_message[:50]}...' | " + f"Intent: {intent_info.get('name') if intent_info else 'unknown'} " + f"({intent_info.get('confidence', 0):.2f})" + ) + + try: + response = self.provider.generate(messages) + logger.info(f"✅ LLM fallback response generated") + return response + + except Exception as e: + logger.error(f"❌ LLM fallback failed: {e}") + return "Xin lỗi, hệ thống đang gặp sự cố. Bạn có thể thử lại sau được không?" + + def handle_out_of_scope(self, user_message: str) -> str: + """ + Handle out-of-scope questions + + Args: + user_message: User's out-of-scope message + + Returns: + Polite redirect response + """ + messages = [ + { + "role": "system", + "content": """Bạn là trợ lý đặt vé máy bay. + User vừa hỏi câu NGOÀI chức năng của bạn. + + Hãy: + 1. Lịch sự từ chối (không thô lỗ) + 2. Giải thích bạn CHỈ giúp đặt vé máy bay + 3. Hỏi xem có thể giúp họ đặt vé không + + NGẮN GỌN (2-3 câu), thân thiện.""" + }, + { + "role": "user", + "content": user_message + } + ] + + try: + return self.provider.generate(messages, temperature=0.5) + except: + return "Xin lỗi, tôi chỉ hỗ trợ đặt vé máy bay. Tôi có thể giúp bạn tìm chuyến bay không? ✈️" diff --git a/actions/llm/intent_clarifier.py b/actions/llm/intent_clarifier.py new file mode 100644 index 000000000000..96101d7ade24 --- /dev/null +++ b/actions/llm/intent_clarifier.py @@ -0,0 +1,214 @@ +""" +Intent Clarifier - Use LLM to clarify ambiguous intents +""" +import logging +from typing import List, Dict, Optional +from .providers import LLMProvider + +logger = logging.getLogger(__name__) + + +class IntentClarifier: + """ + Use LLM to clarify when Rasa has multiple similar confidence intents + """ + + def __init__( + self, + provider: LLMProvider, + ambiguity_threshold: float = 0.2 + ): + """ + Args: + provider: LLM provider instance + ambiguity_threshold: Clarify if top 2 intents differ by less than this + """ + self.provider = provider + self.ambiguity_threshold = ambiguity_threshold + + # Intent descriptions for LLM context + self.intent_descriptions = self._get_default_intent_descriptions() + + def _get_default_intent_descriptions(self) -> Dict[str, str]: + """Get default intent descriptions""" + return { + "greet": "User chào hỏi, bắt đầu hội thoại", + "goodbye": "User chào tạm biệt, kết thúc hội thoại", + "book_flight": "User muốn đặt vé máy bay mới", + "cancel_booking": "User muốn hủy vé đã đặt", + "reschedule_flight": "User muốn đổi lịch bay (change date/time)", + "ask_price": "User hỏi về giá vé", + "ask_flight_status": "User hỏi tình trạng chuyến bay", + "provide_info": "User cung cấp thông tin (địa điểm, ngày giờ, v.v.)", + "confirm": "User xác nhận (yes, ok, đồng ý)", + "deny": "User từ chối (no, không, thôi)", + "ask_help": "User yêu cầu trợ giúp, hướng dẫn", + } + + def set_intent_descriptions(self, descriptions: Dict[str, str]): + """Update intent descriptions""" + self.intent_descriptions.update(descriptions) + + def is_ambiguous(self, intent_ranking: List[Dict]) -> bool: + """ + Check if intent is ambiguous + + Args: + intent_ranking: List of intents with confidence scores + + Returns: + True if ambiguous + """ + if len(intent_ranking) < 2: + return False + + top1 = intent_ranking[0]["confidence"] + top2 = intent_ranking[1]["confidence"] + + # Ambiguous if difference is small + return (top1 - top2) < self.ambiguity_threshold + + def clarify_intent( + self, + user_message: str, + intent_ranking: List[Dict], + context: Optional[str] = None + ) -> str: + """ + Use LLM to clarify which intent is correct + + Args: + user_message: User's message + intent_ranking: Top intents from Rasa + context: Conversation context + + Returns: + Clarified intent name + """ + if not self.provider.is_available(): + logger.warning("⚠️ LLM not available for clarification") + return intent_ranking[0]["name"] # Use Rasa's top prediction + + # Get top 3 intents + top_intents = intent_ranking[:3] + + # Build intent descriptions + intent_info = [] + for i, intent_data in enumerate(top_intents, 1): + intent_name = intent_data["name"] + confidence = intent_data["confidence"] + description = self.intent_descriptions.get( + intent_name, + "Không có mô tả" + ) + + intent_info.append( + f"{i}. {intent_name} (confidence: {confidence:.2f})\n" + f" Mô tả: {description}" + ) + + intent_info_text = "\n".join(intent_info) + + prompt = f""" +User nói: "{user_message}" + +Rasa phát hiện các intents có thể: +{intent_info_text} + +{"Ngữ cảnh: " + context if context else ""} + +NHIỆM VỤ: Chọn intent PHÙ HỢP NHẤT với câu nói của user. + +QUY TẮC: +1. Phân tích ý định CHÍNH của user +2. Xem xét ngữ cảnh (nếu có) +3. Chọn 1 trong các intents trên + +TRẢ LỜI: Chỉ tên intent, KHÔNG giải thích. + +Ví dụ output: book_flight +""" + + try: + messages = [{"role": "user", "content": prompt}] + + clarified = self.provider.generate( + messages, + temperature=0.1, # Low temp for consistency + max_tokens=20 + ).strip() + + # Validate returned intent + valid_intents = [i["name"] for i in top_intents] + + if clarified in valid_intents: + logger.info( + f"🔍 Intent clarified: '{user_message[:30]}...' " + f"→ {clarified} " + f"(was: {intent_ranking[0]['name']})" + ) + return clarified + else: + logger.warning( + f"⚠️ LLM returned invalid intent: {clarified}. " + f"Using Rasa's top: {intent_ranking[0]['name']}" + ) + return intent_ranking[0]["name"] + + except Exception as e: + logger.error(f"❌ Intent clarification failed: {e}") + return intent_ranking[0]["name"] + + def get_clarification_question( + self, + intent_ranking: List[Dict] + ) -> str: + """ + Generate question to ask user for clarification + + Args: + intent_ranking: Top intents + + Returns: + Clarification question + """ + if not self.provider.is_available(): + return "Xin lỗi, bạn có thể nói rõ hơn được không?" + + top_intents = intent_ranking[:2] + + intent_names = [ + self.intent_descriptions.get(i["name"], i["name"]) + for i in top_intents + ] + + prompt = f""" +Tạo câu hỏi ngắn gọn để XÁC NHẬN ý định của user. + +User có thể muốn: +1. {intent_names[0]} +2. {intent_names[1]} + +YÊU CẦU: +- Hỏi user muốn làm gì trong 2 options trên +- Thân thiện, lịch sự +- Ngắn gọn (1 câu) +- Dễ trả lời + +Ví dụ tốt: +"Bạn muốn đặt vé mới hay hủy vé đã đặt ạ?" +""" + + try: + messages = [{"role": "user", "content": prompt}] + question = self.provider.generate( + messages, + temperature=0.7, + max_tokens=100 + ) + + logger.info("❓ Clarification question generated") + return question + + except: + return "Xin lỗi, bạn muốn làm gì ạ?" diff --git a/actions/llm/providers.py b/actions/llm/providers.py new file mode 100644 index 000000000000..e7512f1c2557 --- /dev/null +++ b/actions/llm/providers.py @@ -0,0 +1,243 @@ +""" +LLM Providers - OpenAI, Claude, and base provider +""" +import os +import logging +from abc import ABC, abstractmethod +from typing import List, Dict, Optional, Any + +logger = logging.getLogger(__name__) + + +class LLMProvider(ABC): + """Base class for LLM providers""" + + def __init__(self, api_key: Optional[str] = None, model: Optional[str] = None): + self.api_key = api_key + self.model = model + self._client = None + + @abstractmethod + def generate(self, messages: List[Dict[str, str]], **kwargs) -> str: + """Generate response from LLM""" + pass + + @abstractmethod + def is_available(self) -> bool: + """Check if provider is available""" + pass + + +class OpenAIProvider(LLMProvider): + """OpenAI GPT provider""" + + def __init__( + self, + api_key: Optional[str] = None, + model: str = "gpt-4", + temperature: float = 0.7, + max_tokens: int = 500 + ): + super().__init__(api_key, model) + self.temperature = temperature + self.max_tokens = max_tokens + + # Get API key from env if not provided + if not self.api_key: + self.api_key = os.getenv("OPENAI_API_KEY") + + self._initialize_client() + + def _initialize_client(self): + """Initialize OpenAI client""" + try: + from openai import OpenAI + self._client = OpenAI(api_key=self.api_key) + logger.info(f"✅ OpenAI client initialized with model: {self.model}") + except ImportError: + logger.error("❌ OpenAI package not installed. Run: pip install openai") + self._client = None + except Exception as e: + logger.error(f"❌ Failed to initialize OpenAI: {e}") + self._client = None + + def generate( + self, + messages: List[Dict[str, str]], + temperature: Optional[float] = None, + max_tokens: Optional[int] = None, + **kwargs + ) -> str: + """ + Generate response from OpenAI + + Args: + messages: List of message dicts with 'role' and 'content' + temperature: Override default temperature + max_tokens: Override default max_tokens + + Returns: + Generated text response + """ + if not self.is_available(): + raise RuntimeError("OpenAI client not available") + + try: + response = self._client.chat.completions.create( + model=self.model, + messages=messages, + temperature=temperature or self.temperature, + max_tokens=max_tokens or self.max_tokens, + **kwargs + ) + + generated_text = response.choices[0].message.content + + # Log token usage + usage = response.usage + logger.info( + f"🤖 OpenAI response generated | " + f"Tokens: {usage.total_tokens} " + f"(prompt: {usage.prompt_tokens}, " + f"completion: {usage.completion_tokens})" + ) + + return generated_text + + except Exception as e: + logger.error(f"❌ OpenAI generation failed: {e}") + raise + + def is_available(self) -> bool: + """Check if OpenAI is available""" + return self._client is not None and self.api_key is not None + + +class ClaudeProvider(LLMProvider): + """Anthropic Claude provider""" + + def __init__( + self, + api_key: Optional[str] = None, + model: str = "claude-3-5-sonnet-20241022", + temperature: float = 0.7, + max_tokens: int = 1024 + ): + super().__init__(api_key, model) + self.temperature = temperature + self.max_tokens = max_tokens + + # Get API key from env if not provided + if not self.api_key: + self.api_key = os.getenv("ANTHROPIC_API_KEY") + + self._initialize_client() + + def _initialize_client(self): + """Initialize Claude client""" + try: + from anthropic import Anthropic + self._client = Anthropic(api_key=self.api_key) + logger.info(f"✅ Claude client initialized with model: {self.model}") + except ImportError: + logger.error("❌ Anthropic package not installed. Run: pip install anthropic") + self._client = None + except Exception as e: + logger.error(f"❌ Failed to initialize Claude: {e}") + self._client = None + + def generate( + self, + messages: List[Dict[str, str]], + temperature: Optional[float] = None, + max_tokens: Optional[int] = None, + **kwargs + ) -> str: + """ + Generate response from Claude + + Args: + messages: List of message dicts with 'role' and 'content' + First message should be 'system' role (will be extracted) + temperature: Override default temperature + max_tokens: Override default max_tokens + + Returns: + Generated text response + """ + if not self.is_available(): + raise RuntimeError("Claude client not available") + + try: + # Claude API separates system message from conversation + system_message = "" + conversation_messages = [] + + for msg in messages: + if msg["role"] == "system": + system_message = msg["content"] + else: + conversation_messages.append(msg) + + # Ensure alternating user/assistant messages + # If first message is not user, prepend a user message + if conversation_messages and conversation_messages[0]["role"] != "user": + conversation_messages.insert(0, { + "role": "user", + "content": "Hello" + }) + + response = self._client.messages.create( + model=self.model, + max_tokens=max_tokens or self.max_tokens, + temperature=temperature or self.temperature, + system=system_message if system_message else None, + messages=conversation_messages, + **kwargs + ) + + generated_text = response.content[0].text + + # Log token usage + usage = response.usage + logger.info( + f"🤖 Claude response generated | " + f"Tokens: input={usage.input_tokens}, " + f"output={usage.output_tokens}" + ) + + return generated_text + + except Exception as e: + logger.error(f"❌ Claude generation failed: {e}") + raise + + def is_available(self) -> bool: + """Check if Claude is available""" + return self._client is not None and self.api_key is not None + + +def get_provider(provider_name: str = "openai", **kwargs) -> LLMProvider: + """ + Factory function to get LLM provider + + Args: + provider_name: 'openai' or 'claude' + **kwargs: Provider-specific arguments + + Returns: + LLMProvider instance + """ + providers = { + "openai": OpenAIProvider, + "claude": ClaudeProvider, + } + + provider_class = providers.get(provider_name.lower()) + if not provider_class: + raise ValueError( + f"Unknown provider: {provider_name}. " + f"Available: {list(providers.keys())}" + ) + + return provider_class(**kwargs) diff --git a/actions/llm/response_enhancer.py b/actions/llm/response_enhancer.py new file mode 100644 index 000000000000..a3ebc3201cb4 --- /dev/null +++ b/actions/llm/response_enhancer.py @@ -0,0 +1,204 @@ +""" +Response Enhancer - Make Rasa responses more natural using LLM +""" +import logging +import json +from typing import Dict, List, Any, Optional +from .providers import LLMProvider + +logger = logging.getLogger(__name__) + + +class ResponseEnhancer: + """ + Enhance Rasa responses to be more natural and conversational + """ + + def __init__(self, provider: LLMProvider): + """ + Args: + provider: LLM provider instance + """ + self.provider = provider + + def enhance_flight_results( + self, + flights_data: Dict[str, Any], + user_preferences: Optional[Dict] = None + ) -> str: + """ + Generate natural response for flight search results + + Args: + flights_data: Flight search results + user_preferences: User preferences (if any) + + Returns: + Natural, formatted response + """ + if not self.provider.is_available(): + logger.warning("⚠️ LLM not available, using template") + return self._template_flight_results(flights_data) + + prompt = f""" +Tạo response thân thiện, chuyên nghiệp cho kết quả tìm vé máy bay. + +THÔNG TIN TÌM KIẾM: +- Từ: {flights_data.get('departure', 'N/A')} +- Đến: {flights_data.get('destination', 'N/A')} +- Ngày: {flights_data.get('date', 'N/A')} +- Số hành khách: {flights_data.get('passengers', 1)} + +KẾT QUẢ TÌM ĐƯỢC: +{json.dumps(flights_data.get('results', []), indent=2, ensure_ascii=False)} + +YÊU CẦU: +1. Giới thiệu ngắn gọn (1 câu) +2. Trình bày TỪNG chuyến bay rõ ràng: + - Hãng hàng không + mã chuyến + - Giờ khởi hành → Giờ đến + - Giá vé (định dạng VNĐ dễ đọc) + - 1-2 ưu điểm nổi bật +3. Hỏi user muốn chọn chuyến nào +4. Dùng emoji phù hợp: ✈️, 🛫, ⏰, 💰 +5. Ngắn gọn, dễ đọc + +CHÚ Ý: Chỉ dùng thông tin có sẵn, KHÔNG bịa thêm. +""" + + try: + messages = [{"role": "user", "content": prompt}] + response = self.provider.generate( + messages, + temperature=0.7, + max_tokens=500 + ) + + logger.info("✨ Flight results enhanced by LLM") + return response + + except Exception as e: + logger.error(f"❌ Enhancement failed: {e}") + return self._template_flight_results(flights_data) + + def _template_flight_results(self, flights_data: Dict) -> str: + """Fallback template for flight results""" + results = flights_data.get('results', []) + + if not results: + return "Xin lỗi, không tìm thấy chuyến bay phù hợp. Bạn có thể thử ngày khác không?" + + text = f"Tìm thấy {len(results)} chuyến bay:\n\n" + + for i, flight in enumerate(results, 1): + text += f"{i}. {flight.get('airline', '')} {flight.get('flight_number', '')}\n" + text += f" {flight.get('departure_time', '')} → {flight.get('arrival_time', '')}\n" + text += f" Giá: {flight.get('price', '')}đ\n\n" + + text += "Bạn muốn đặt chuyến nào?" + return text + + def enhance_booking_confirmation( + self, + booking_data: Dict[str, Any] + ) -> str: + """ + Generate natural booking confirmation + + Args: + booking_data: Booking details + + Returns: + Natural confirmation message + """ + if not self.provider.is_available(): + return f"✅ Đặt vé thành công! Mã đặt chỗ: {booking_data.get('booking_code', 'N/A')}" + + prompt = f""" +Tạo response XÁC NHẬN ĐẶT VÉ thành công, vui vẻ và chuyên nghiệp. + +THÔNG TIN ĐẶT VÉ: +{json.dumps(booking_data, indent=2, ensure_ascii=False)} + +YÊU CẦU: +1. Chúc mừng ngắn gọn +2. Mã đặt chỗ (nổi bật) +3. Tóm tắt chuyến bay (1-2 dòng) +4. Hướng dẫn tiếp theo (check email, làm thủ tục, v.v.) +5. Dùng emoji: ✅, ✈️, 🎉, 📧 +6. NGẮN GỌN (tối đa 5 câu) +""" + + try: + messages = [{"role": "user", "content": prompt}] + response = self.provider.generate( + messages, + temperature=0.7, + max_tokens=300 + ) + + logger.info("✨ Booking confirmation enhanced") + return response + + except: + return f"✅ Đặt vé thành công! Mã đặt chỗ: {booking_data.get('booking_code', 'N/A')}" + + def enhance_error_message( + self, + error_type: str, + error_details: Optional[str] = None + ) -> str: + """ + Generate friendly error message + + Args: + error_type: Type of error (e.g., 'payment_failed', 'flight_full') + error_details: Additional details + + Returns: + Friendly error message + """ + if not self.provider.is_available(): + return "Xin lỗi, có lỗi xảy ra. Vui lòng thử lại sau." + + error_contexts = { + "payment_failed": "Thanh toán không thành công", + "flight_full": "Chuyến bay đã hết chỗ", + "booking_expired": "Phiên đặt vé đã hết hạn", + "invalid_date": "Ngày không hợp lệ", + "system_error": "Lỗi hệ thống" + } + + error_msg = error_contexts.get(error_type, "Có lỗi xảy ra") + + prompt = f""" +Tạo thông báo LỖI thân thiện, không làm user buồn. + +LỖI: {error_msg} +Chi tiết: {error_details or 'Không có'} + +YÊU CẦU: +1. Xin lỗi chân thành +2. Giải thích ngắn gọn vấn đề +3. Đề xuất giải pháp/bước tiếp theo +4. Thể hiện sẵn sàng hỗ trợ +5. Tích cực, không tiêu cực +6. 2-3 câu + +Ví dụ TỐT: +"Rất xin lỗi, chuyến bay này đã hết chỗ 😔 Tôi có thể giúp bạn tìm chuyến bay khác cùng ngày hoặc ngày gần nhất được không?" +""" + + try: + messages = [{"role": "user", "content": prompt}] + response = self.provider.generate( + messages, + temperature=0.6, + max_tokens=200 + ) + + logger.info(f"✨ Error message enhanced: {error_type}") + return response + + except: + return f"Xin lỗi, {error_msg.lower()}. Bạn có muốn thử lại không?" diff --git a/config/llm_requirements.txt b/config/llm_requirements.txt new file mode 100644 index 000000000000..9894cd7934b9 --- /dev/null +++ b/config/llm_requirements.txt @@ -0,0 +1,22 @@ +# LLM Integration Dependencies +# Install with: pip install -r config/llm_requirements.txt + +# Core Rasa SDK +rasa-sdk>=3.6.0 + +# OpenAI +openai>=1.0.0 + +# Anthropic Claude +anthropic>=0.7.0 + +# Environment variables +python-dotenv>=1.0.0 + +# Optional: Caching +redis>=5.0.0 # For distributed caching +diskcache>=5.6.0 # For local caching + +# Optional: Monitoring +sentry-sdk>=1.40.0 # Error tracking +prometheus-client>=0.19.0 # Metrics diff --git a/examples/hybrid_bot/config.yml b/examples/hybrid_bot/config.yml new file mode 100644 index 000000000000..a50a6faf5a33 --- /dev/null +++ b/examples/hybrid_bot/config.yml @@ -0,0 +1,68 @@ +# Configuration for Hybrid Bot (Rasa + LLM) +# This demonstrates best practices for combining Rasa with LLM + +recipe: default.v1 +language: vi # Vietnamese +assistant_id: hybrid_flight_booking_bot + +# ============================================================================ +# NLU Pipeline +# ============================================================================ +pipeline: + # Tokenization + - name: WhitespaceTokenizer + + # Featurizers + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + + # Character n-grams (good for Vietnamese) + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 2 + max_ngram: 5 + + # Word n-grams + - name: CountVectorsFeaturizer + analyzer: word + min_ngram: 1 + max_ngram: 2 + + # Intent Classifier + Entity Extractor + - name: DIETClassifier + epochs: 200 + entity_recognition: true + intent_classification: true + use_masked_language_model: true + # Return top 5 intents for clarification + ranking_length: 5 + + # Fallback Classifier + - name: FallbackClassifier + threshold: 0.7 # Match with LLM fallback threshold + ambiguity_threshold: 0.1 + + # Entity Synonym Mapper + - name: EntitySynonymMapper + +# ============================================================================ +# Dialogue Policies +# ============================================================================ +policies: + # Memorize exact patterns + - name: MemoizationPolicy + max_history: 5 + + # Transformer-based dialogue + - name: TEDPolicy + max_history: 5 + epochs: 200 + batch_size: [32, 64] + + # Rule-based policy + - name: RulePolicy + # IMPORTANT: Core fallback triggers LLM + core_fallback_threshold: 0.3 + core_fallback_action_name: "action_llm_fallback" + # Also handle NLU fallback + enable_fallback_prediction: true diff --git a/examples/hybrid_bot/domain.yml b/examples/hybrid_bot/domain.yml new file mode 100644 index 000000000000..beda2104e978 --- /dev/null +++ b/examples/hybrid_bot/domain.yml @@ -0,0 +1,160 @@ +# Domain for Hybrid Flight Booking Bot + +version: "3.1" + +# ============================================================================ +# Intents +# ============================================================================ +intents: + # Greetings & closings + - greet + - goodbye + - affirm + - deny + + # Core booking intents + - book_flight + - cancel_booking + - reschedule_flight + - check_booking + + # Information requests + - ask_price + - ask_flight_status + - provide_departure + - provide_destination + - provide_date + - provide_passenger_info + + # Help & support + - ask_help + - chitchat + + # Fallback + - nlu_fallback + - out_of_scope + +# ============================================================================ +# Entities +# ============================================================================ +entities: + - departure + - destination + - travel_date + - num_passengers + - passenger_name + - booking_code + - flight_number + +# ============================================================================ +# Slots +# ============================================================================ +slots: + departure: + type: text + mappings: + - type: from_entity + entity: departure + + destination: + type: text + mappings: + - type: from_entity + entity: destination + + travel_date: + type: text + mappings: + - type: from_entity + entity: travel_date + + num_passengers: + type: float + mappings: + - type: from_entity + entity: num_passengers + + passenger_name: + type: text + mappings: + - type: from_entity + entity: passenger_name + + booking_code: + type: text + mappings: + - type: from_entity + entity: booking_code + + # Internal slots + flight_search_done: + type: bool + initial_value: false + mappings: + - type: custom + + booking_confirmed: + type: bool + initial_value: false + mappings: + - type: custom + + last_fallback_used: + type: bool + initial_value: false + mappings: + - type: custom + + clarified_intent: + type: text + mappings: + - type: custom + +# ============================================================================ +# Responses (Templates) +# ============================================================================ +responses: + utter_greet: + - text: "Xin chào! Tôi là trợ lý đặt vé máy bay. Tôi có thể giúp gì bạn? ✈️" + + utter_goodbye: + - text: "Tạm biệt! Chúc bạn có chuyến bay tốt! 🛫" + + utter_ask_departure: + - text: "Bạn muốn bay từ đâu ạ?" + + utter_ask_destination: + - text: "Bạn muốn bay đến đâu ạ?" + + utter_ask_date: + - text: "Bạn muốn bay vào ngày nào? 📅" + + utter_ask_passengers: + - text: "Bạn đặt vé cho bao nhiêu người?" + + utter_ask_confirm: + - text: "Bạn có chắc muốn đặt vé này không?" + + utter_default: + - text: "Xin lỗi, tôi không hiểu. Bạn có thể nói rõ hơn không?" + + utter_iamabot: + - text: "Tôi là chatbot hỗ trợ đặt vé máy bay, được xây dựng bằng Rasa và AI. 🤖" + +# ============================================================================ +# Actions +# ============================================================================ +actions: + # LLM-powered actions + - action_llm_fallback + - action_show_flights + - action_confirm_booking + - action_clarify_intent + - action_handle_out_of_scope + +# ============================================================================ +# Session Config +# ============================================================================ +session_config: + session_expiration_time: 60 # minutes + carry_over_slots_to_new_session: true diff --git a/examples/hybrid_bot/endpoints.yml b/examples/hybrid_bot/endpoints.yml new file mode 100644 index 000000000000..350a80ec402e --- /dev/null +++ b/examples/hybrid_bot/endpoints.yml @@ -0,0 +1,34 @@ +# Endpoints configuration for Hybrid Bot + +# ============================================================================ +# Action Server (Custom Actions with LLM) +# ============================================================================ +action_endpoint: + url: "http://localhost:5055/webhook" + +# ============================================================================ +# Optional: Tracker Store (MongoDB) +# ============================================================================ +# Uncomment to persist conversations +# tracker_store: +# type: mongod +# url: mongodb://localhost:27017 +# db: rasa_hybrid +# username: rasa +# password: your_password + +# ============================================================================ +# Optional: Event Broker (for analytics) +# ============================================================================ +# event_broker: +# type: kafka +# url: localhost +# port: 9092 +# topic: rasa_events + +# ============================================================================ +# Optional: Model Server +# ============================================================================ +# models: +# url: http://localhost:5002 +# wait_time_between_pulls: 10 diff --git a/examples/it_store_bot/actions/__init__.py b/examples/it_store_bot/actions/__init__.py new file mode 100644 index 000000000000..b538f01f7ad0 --- /dev/null +++ b/examples/it_store_bot/actions/__init__.py @@ -0,0 +1 @@ +# IT Store Bot Actions Package diff --git a/examples/it_store_bot/actions/actions_it_store.py b/examples/it_store_bot/actions/actions_it_store.py new file mode 100644 index 000000000000..e90691031062 --- /dev/null +++ b/examples/it_store_bot/actions/actions_it_store.py @@ -0,0 +1,730 @@ +""" +Custom Actions for IT Store Chatbot +Handles product search, comparison, pricing, and recommendations +""" + +from typing import Any, Text, Dict, List +from rasa_sdk import Action, Tracker +from rasa_sdk.executor import CollectingDispatcher +from rasa_sdk.events import SlotSet +import logging + +logger = logging.getLogger(__name__) + + +# ===== PRODUCT DATABASE ===== + +PRODUCT_DATABASE = { + "laptop": [ + { + "id": "LP001", + "name": "ASUS ROG Strix G15", + "brand": "ASUS", + "category": "laptop", + "type": "gaming", + "price": 28990000, + "specs": { + "cpu": "AMD Ryzen 7 6800H", + "gpu": "NVIDIA RTX 3060 6GB", + "ram": "16GB DDR5", + "storage": "512GB NVMe SSD", + "display": "15.6\" FHD 144Hz" + }, + "stock": True, + "warranty": "24 tháng", + "promotion": "Giảm 10% + Tặng chuột gaming" + }, + { + "id": "LP002", + "name": "MSI Katana GF66", + "brand": "MSI", + "category": "laptop", + "type": "gaming", + "price": 24990000, + "specs": { + "cpu": "Intel i7-12650H", + "gpu": "NVIDIA RTX 3050 Ti 4GB", + "ram": "16GB DDR4", + "storage": "512GB NVMe SSD", + "display": "15.6\" FHD 144Hz" + }, + "stock": True, + "warranty": "24 tháng", + "promotion": None + }, + { + "id": "LP003", + "name": "Dell Latitude 5420", + "brand": "Dell", + "category": "laptop", + "type": "office", + "price": 15990000, + "specs": { + "cpu": "Intel i5-1135G7", + "ram": "8GB DDR4", + "storage": "256GB NVMe SSD", + "display": "14\" FHD" + }, + "stock": True, + "warranty": "36 tháng", + "promotion": None + }, + { + "id": "LP004", + "name": "HP ProBook 450 G9", + "brand": "HP", + "category": "laptop", + "type": "office", + "price": 21490000, + "specs": { + "cpu": "Intel i7-1255U", + "ram": "16GB DDR4", + "storage": "512GB NVMe SSD", + "display": "15.6\" FHD" + }, + "stock": True, + "warranty": "24 tháng", + "promotion": "Giảm 5%" + } + ], + "server": [ + { + "id": "SV001", + "name": "Dell PowerEdge R740", + "brand": "Dell", + "category": "server", + "price": 145000000, + "specs": { + "cpu": "2x Intel Xeon Gold 6230 (20 cores mỗi CPU)", + "ram": "128GB DDR4 ECC", + "storage": "4x 1.2TB SAS HDD", + "raid": "RAID 10", + "power": "2x 750W redundant" + }, + "stock": True, + "warranty": "36 tháng on-site", + "promotion": "Giảm 8% cho đơn từ 100 triệu" + }, + { + "id": "SV002", + "name": "HP ProLiant DL380 Gen10", + "brand": "HP", + "category": "server", + "price": 98000000, + "specs": { + "cpu": "2x Intel Xeon Silver 4214 (12 cores mỗi CPU)", + "ram": "64GB DDR4 ECC", + "storage": "2x 960GB SSD", + "raid": "RAID 1", + "power": "2x 800W redundant" + }, + "stock": True, + "warranty": "36 tháng on-site", + "promotion": "Hỗ trợ setup miễn phí" + }, + { + "id": "SV003", + "name": "Lenovo ThinkSystem SR650", + "brand": "Lenovo", + "category": "server", + "price": 112000000, + "specs": { + "cpu": "2x Intel Xeon Gold 5218 (16 cores mỗi CPU)", + "ram": "96GB DDR4 ECC", + "storage": "4x 2TB SATA HDD", + "raid": "RAID 5", + "power": "2x 750W redundant" + }, + "stock": False, + "warranty": "36 tháng", + "promotion": None + } + ], + "switch": [ + { + "id": "SW001", + "name": "Cisco Catalyst 2960-X 48 Port", + "brand": "Cisco", + "category": "switch", + "price": 42500000, + "specs": { + "ports": "48x Gigabit Ethernet + 2x 10G SFP+", + "type": "Layer 2 Managed", + "power": "PoE+ 740W", + "throughput": "216 Gbps" + }, + "stock": True, + "warranty": "Lifetime", + "promotion": None + }, + { + "id": "SW002", + "name": "HPE OfficeConnect 1920S 48G", + "brand": "HPE", + "category": "switch", + "price": 18900000, + "specs": { + "ports": "48x Gigabit Ethernet + 4x SFP", + "type": "Layer 2+ Smart Managed", + "power": "Non-PoE", + "throughput": "176 Gbps" + }, + "stock": True, + "warranty": "Lifetime", + "promotion": "Giảm 5%" + } + ], + "camera": [ + { + "id": "CM001", + "name": "Hikvision DS-2CD2143G2-I", + "brand": "Hikvision", + "category": "camera", + "price": 2890000, + "specs": { + "resolution": "4MP", + "technology": "AcuSense (AI nhận diện người/xe)", + "night_vision": "30m", + "type": "IP Dome" + }, + "stock": True, + "warranty": "24 tháng", + "promotion": "Mua 10 tặng 2" + }, + { + "id": "CM002", + "name": "Dahua IPC-HDW3441TM-AS", + "brand": "Dahua", + "category": "camera", + "price": 1990000, + "specs": { + "resolution": "4MP", + "technology": "AI SMD Plus", + "night_vision": "30m", + "type": "IP Dome với Mic tích hợp" + }, + "stock": True, + "warranty": "24 tháng", + "promotion": "Bundle: 8 camera + NVR = 18 triệu" + } + ], + "software": [ + { + "id": "SW001", + "name": "Windows 11 Pro", + "brand": "Microsoft", + "category": "software", + "price": 5490000, + "specs": { + "type": "Operating System", + "license": "Retail FPP", + "devices": "1 PC" + }, + "stock": True, + "warranty": "Vĩnh viễn", + "promotion": None + }, + { + "id": "SW002", + "name": "Windows Server 2022 Standard", + "brand": "Microsoft", + "category": "software", + "price": 24900000, + "specs": { + "type": "Server OS", + "license": "16 Core", + "support": "5 năm mainstream" + }, + "stock": True, + "warranty": "Vĩnh viễn", + "promotion": None + }, + { + "id": "SW003", + "name": "Office 2021 Professional Plus", + "brand": "Microsoft", + "category": "software", + "price": 8900000, + "specs": { + "type": "Office Suite", + "apps": "Word, Excel, PowerPoint, Outlook, Access, Publisher", + "license": "1 PC" + }, + "stock": True, + "warranty": "Vĩnh viễn", + "promotion": "Mua 5+ giảm 10%" + } + ] +} + + +def format_price(price): + """Format price to Vietnamese currency""" + return f"{price:,.0f}đ".replace(",", ".") + + +def format_product_card(product): + """Format product information as a card""" + specs_text = "\n".join([f"• {k.replace('_', ' ').title()}: {v}" + for k, v in product['specs'].items()]) + + stock_text = "✅ Còn hàng" if product['stock'] else "❌ Hết hàng" + promo_text = f"\n🎁 Khuyến mãi: {product['promotion']}" if product['promotion'] else "" + + return f"""**{product['name']}** ({product['brand']}) +💰 Giá: {format_price(product['price'])} + +**Thông số kỹ thuật:** +{specs_text} + +🛡️ Bảo hành: {product['warranty']} +{stock_text}{promo_text}""" + + +def search_products(product_type=None, brand=None, price_max=None, use_case=None): + """Search products based on filters""" + results = [] + + # Get products by type + if product_type: + type_map = { + "máy tính": "laptop", + "laptop": "laptop", + "máy chủ": "server", + "server": "server", + "switch": "switch", + "switch mạng": "switch", + "camera": "camera", + "phần mềm": "software", + "software": "software" + } + category = type_map.get(product_type.lower()) + if category and category in PRODUCT_DATABASE: + results = PRODUCT_DATABASE[category].copy() + else: + # Get all products + for products in PRODUCT_DATABASE.values(): + results.extend(products) + + # Filter by brand + if brand: + results = [p for p in results if p['brand'].lower() == brand.lower()] + + # Filter by price + if price_max: + try: + # Extract number from price string (e.g., "25 triệu" -> 25000000) + if "triệu" in str(price_max): + max_price = float(price_max.split()[0]) * 1000000 + results = [p for p in results if p['price'] <= max_price] + except: + pass + + # Filter by use case + if use_case and 'type' in results[0]: + use_case_map = { + "gaming": "gaming", + "chơi game": "gaming", + "văn phòng": "office", + "office": "office" + } + uc = use_case_map.get(use_case.lower()) + if uc: + results = [p for p in results if p.get('type') == uc] + + return results + + +# ===== CUSTOM ACTIONS ===== + +class ActionSearchProduct(Action): + """Search for products based on user criteria""" + + def name(self) -> Text: + return "action_search_product" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + product_type = tracker.get_slot("product_type") + brand = tracker.get_slot("brand") + price_range = tracker.get_slot("price_range") + use_case = tracker.get_slot("use_case") + + logger.info(f"Searching products: type={product_type}, brand={brand}, price={price_range}, use_case={use_case}") + + results = search_products(product_type, brand, price_range, use_case) + + if not results: + dispatcher.utter_message(text="Xin lỗi, tôi không tìm thấy sản phẩm phù hợp. Bạn có thể thử tiêu chí khác?") + return [] + + # Limit to top 3 results + results = results[:3] + + message = f"🔍 Tìm thấy {len(results)} sản phẩm phù hợp:\n\n" + + for i, product in enumerate(results, 1): + message += f"**{i}. {product['name']}**\n" + message += f"💰 {format_price(product['price'])}\n" + message += f"{'✅ Còn hàng' if product['stock'] else '❌ Hết hàng'}\n" + if product['promotion']: + message += f"🎁 {product['promotion']}\n" + message += "\n" + + message += "Bạn muốn xem chi tiết sản phẩm nào?" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionCompareProducts(Action): + """Compare two or more products""" + + def name(self) -> Text: + return "action_compare_products" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + # Get recent entities or search results + product_name = tracker.get_slot("product_name") + product_type = tracker.get_slot("product_type") + + if product_type: + results = search_products(product_type)[:2] + else: + # Default comparison + results = PRODUCT_DATABASE['laptop'][:2] + + if len(results) < 2: + dispatcher.utter_message(text="Vui lòng cho tôi biết 2 sản phẩm bạn muốn so sánh.") + return [] + + p1, p2 = results[0], results[1] + + message = f"""⚖️ **So Sánh: {p1['name']} vs {p2['name']}** + +**💰 Giá:** +• {p1['name']}: {format_price(p1['price'])} +• {p2['name']}: {format_price(p2['price'])} + +**🔧 Thông Số:** +{p1['name']}: +""" + for k, v in p1['specs'].items(): + message += f"• {k.replace('_', ' ').title()}: {v}\n" + + message += f"\n{p2['name']}:\n" + for k, v in p2['specs'].items(): + message += f"• {k.replace('_', ' ').title()}: {v}\n" + + message += f""" +**🛡️ Bảo Hành:** +• {p1['name']}: {p1['warranty']} +• {p2['name']}: {p2['warranty']} + +**💡 Nhận Xét:** +""" + + if p1['price'] < p2['price']: + message += f"• {p1['name']} rẻ hơn {format_price(p2['price'] - p1['price'])}\n" + else: + message += f"• {p2['name']} rẻ hơn {format_price(p1['price'] - p2['price'])}\n" + + message += "\nBạn cần thêm thông tin gì?" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionShowPrice(Action): + """Show price and availability""" + + def name(self) -> Text: + return "action_show_price" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + product_type = tracker.get_slot("product_type") + product_name = tracker.get_slot("product_name") + + results = search_products(product_type) + + if not results: + dispatcher.utter_message(text="Vui lòng cho tôi biết sản phẩm bạn muốn hỏi giá.") + return [] + + message = "💰 **Bảng Giá:**\n\n" + + for product in results[:5]: + message += f"• {product['name']}: {format_price(product['price'])}" + if product['promotion']: + message += f" 🎁 {product['promotion']}" + message += "\n" + + message += "\nGiá đã bao gồm VAT. Liên hệ để được báo giá chi tiết!" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionShowSpecifications(Action): + """Show detailed product specifications""" + + def name(self) -> Text: + return "action_show_specifications" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + product_type = tracker.get_slot("product_type") + results = search_products(product_type) + + if not results: + dispatcher.utter_message(text="Vui lòng cho tôi biết sản phẩm bạn muốn xem thông số.") + return [] + + product = results[0] + message = format_product_card(product) + + dispatcher.utter_message(text=message) + + return [] + + +class ActionCheckStock(Action): + """Check product availability""" + + def name(self) -> Text: + return "action_check_stock" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + product_type = tracker.get_slot("product_type") + results = search_products(product_type) + + if not results: + dispatcher.utter_message(text="Vui lòng cho tôi biết sản phẩm bạn muốn kiểm tra.") + return [] + + message = "📦 **Tình Trạng Kho:**\n\n" + + for product in results[:5]: + status = "✅ Còn hàng" if product['stock'] else "❌ Hết hàng (liên hệ đặt trước)" + message += f"• {product['name']}: {status}\n" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionShowWarranty(Action): + """Show warranty information""" + + def name(self) -> Text: + return "action_show_warranty" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + message = """🛡️ **Chính Sách Bảo Hành:** + +**Laptop & PC:** +• Bảo hành 12-36 tháng tùy hãng +• Bảo hành tại trung tâm hoặc đổi mới trong 7 ngày +• Hỗ trợ kỹ thuật miễn phí + +**Máy Chủ:** +• Bảo hành 36 tháng +• Bảo hành on-site (tại chỗ) +• Phản hồi trong 4-24h + +**Camera & Switch:** +• Bảo hành 24 tháng - Lifetime +• Đổi mới trong 30 ngày +• Hỗ trợ kỹ thuật suốt đời + +**Phần Mềm:** +• Hỗ trợ kỹ thuật miễn phí +• Cập nhật liên tục +• Đổi trả trong 7 ngày nếu lỗi + +Liên hệ hotline: 1900-xxxx""" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionShowPromotions(Action): + """Show current promotions""" + + def name(self) -> Text: + return "action_show_promotions" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + message = """🎁 **Chương Trình Khuyến Mãi Tháng Này:** + +**💻 Laptop Gaming:** +• Giảm 10-15% ASUS ROG series +• Tặng chuột + balo gaming (trị giá 2 triệu) + +**🖥️ Máy Chủ:** +• Giảm 8% đơn hàng từ 100 triệu +• Miễn phí setup và cài đặt +• Hỗ trợ vay 0% lãi suất + +**📹 Camera:** +• Mua 10 tặng 2 camera cùng loại +• Miễn phí lắp đặt trong bán kính 50km +• Tặng HDD 1TB cho gói trọn bộ + +**💿 Phần Mềm:** +• Giảm 10% khi mua từ 5 license trở lên +• Tặng 1 năm Microsoft 365 khi mua Windows Server + +Liên hệ ngay để được tư vấn chi tiết!""" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionRecommendProduct(Action): + """Recommend products based on use case""" + + def name(self) -> Text: + return "action_recommend_product" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + use_case = tracker.get_slot("use_case") + product_type = tracker.get_slot("product_type") + + # Default recommendations + if "văn phòng" in str(use_case).lower() or "office" in str(use_case).lower(): + results = [p for p in PRODUCT_DATABASE['laptop'] if p.get('type') == 'office'] + message = "💼 **Gợi ý Laptop Văn Phòng:**\n\n" + elif "gaming" in str(use_case).lower() or "chơi game" in str(use_case).lower(): + results = [p for p in PRODUCT_DATABASE['laptop'] if p.get('type') == 'gaming'] + message = "🎮 **Gợi ý Laptop Gaming:**\n\n" + elif product_type == "máy chủ" or product_type == "server": + results = PRODUCT_DATABASE['server'][:2] + message = "🖥️ **Gợi ý Máy Chủ Doanh Nghiệp:**\n\n" + else: + results = PRODUCT_DATABASE['laptop'][:2] + message = "💡 **Sản Phẩm Đề Xuất:**\n\n" + + for product in results: + message += format_product_card(product) + "\n\n---\n\n" + + message += "Bạn muốn tìm hiểu thêm về sản phẩm nào?" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionProvideSupport(Action): + """Provide technical support information""" + + def name(self) -> Text: + return "action_provide_support" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + message = """🛠️ **Hỗ Trợ Kỹ Thuật:** + +**📞 Liên Hệ:** +• Hotline: 1900-xxxx (24/7) +• Email: support@techstore.vn +• Chat: Qua website hoặc Zalo + +**💻 Hỗ Trợ Từ Xa:** +• Cài đặt hệ điều hành +• Cấu hình server +• Setup camera & switch +• Khắc phục sự cố + +**🏢 Hỗ Trợ Tại Chỗ:** +• Lắp đặt thiết bị +• Cấu hình hệ thống +• Đào tạo sử dụng +• Bảo trì định kỳ + +**📚 Tài Liệu:** +• Hướng dẫn sử dụng chi tiết +• Video tutorial +• Knowledge base + +Bạn cần hỗ trợ về vấn đề gì cụ thể?""" + + dispatcher.utter_message(text=message) + + return [] + + +class ActionShowCategory(Action): + """Show product categories""" + + def name(self) -> Text: + return "action_show_category" + + def run(self, dispatcher: CollectingDispatcher, + tracker: Tracker, + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: + + message = """📁 **Danh Mục Sản Phẩm TechStore:** + +**💻 Máy Tính & Laptop:** +• PC Desktop (Văn phòng, Gaming, Workstation) +• Laptop (Dell, HP, ASUS, MSI, Lenovo) +• Linh kiện máy tính + +**🖥️ Máy Chủ (Server):** +• Dell PowerEdge +• HP ProLiant +• Lenovo ThinkSystem +• Tower & Rack Server + +**🔌 Thiết Bị Mạng:** +• Switch (Cisco, HPE, D-Link) +• Router +• Firewall +• Access Point + +**📹 Camera An Ninh:** +• IP Camera (Hikvision, Dahua) +• NVR & DVR +• Hệ thống giám sát + +**💿 Phần Mềm:** +• Windows (11, Server) +• Microsoft Office +• Antivirus +• Software chuyên dụng + +Bạn quan tâm danh mục nào?""" + + dispatcher.utter_message(text=message) + + return [] diff --git a/examples/it_store_bot/config.yml b/examples/it_store_bot/config.yml new file mode 100644 index 000000000000..81c460780a9b --- /dev/null +++ b/examples/it_store_bot/config.yml @@ -0,0 +1,30 @@ +recipe: default.v1 +language: vi + +pipeline: + - name: WhitespaceTokenizer + - name: RegexFeaturizer + - name: LexicalSyntacticFeaturizer + - name: CountVectorsFeaturizer + - name: CountVectorsFeaturizer + analyzer: char_wb + min_ngram: 1 + max_ngram: 4 + - name: DIETClassifier + epochs: 200 + entity_recognition: true + ranking_length: 5 + - name: EntitySynonymMapper + - name: ResponseSelector + epochs: 100 + - name: FallbackClassifier + threshold: 0.7 + +policies: + - name: MemoizationPolicy + - name: TEDPolicy + max_history: 5 + epochs: 100 + - name: RulePolicy + core_fallback_threshold: 0.3 + core_fallback_action_name: action_default_fallback diff --git a/examples/it_store_bot/data/nlu.yml b/examples/it_store_bot/data/nlu.yml new file mode 100644 index 000000000000..277eac53cfec --- /dev/null +++ b/examples/it_store_bot/data/nlu.yml @@ -0,0 +1,193 @@ +version: "3.1" + +nlu: + - intent: greet + examples: | + - xin chào + - chào bạn + - hello + - hi + - chào + - hế lô + - chào buổi sáng + - chào buổi chiều + - chúc buổi tối tốt lành + + - intent: goodbye + examples: | + - tạm biệt + - bye + - goodbye + - hẹn gặp lại + - cảm ơn tạm biệt + - thôi tôi đi đây + - ok bye + + - intent: affirm + examples: | + - đúng + - đúng rồi + - ok + - được + - đồng ý + - chính xác + - yes + - yeah + - vâng + + - intent: deny + examples: | + - không + - không phải + - sai rồi + - no + - không đúng + - chưa đúng + - không đồng ý + + - intent: thank + examples: | + - cảm ơn + - cảm ơn bạn + - thanks + - thank you + - cảm ơn nhiều + - cảm ơn nhé + - thanks a lot + + - intent: search_product + examples: | + - tìm [laptop](product_type) + - tìm [máy tính](product_type) gaming + - tôi cần [laptop](product_type) gaming dưới [25 triệu](price_range) + - tìm [máy chủ](product_type) [Dell](brand) + - cho tôi xem [camera](product_type) an ninh + - tìm [switch](product_type) mạng [48 port](specification) + - cần [laptop](product_type) cho [văn phòng](use_case) + - tìm [máy tính](product_type) cho [thiết kế đồ họa](use_case) + - có [laptop](product_type) [ASUS](brand) nào không + - tìm [server](product_type) dưới [100 triệu](price_range) + - [phần mềm](product_type) [Windows](product_name) + - tìm [máy chủ](product_type) cho [doanh nghiệp](use_case) + - [laptop](product_type) gaming tầm [30 triệu](price_range) + - [camera IP](product_type) [4MP](specification) + - [switch](product_type) [Cisco](brand) [24 port](specification) + - tìm [laptop](product_type) [Dell Latitude](product_name) + - [máy tính](product_type) chơi game + - [server](product_type) [HPE](brand) + + - intent: compare_products + examples: | + - so sánh [Dell PowerEdge R740](product_name) và [HP ProLiant DL380](product_name) + - so sánh 2 [laptop](product_type) này + - khác nhau gì giữa [ASUS ROG](product_name) và [MSI](brand) + - [switch Cisco](product_type) so với [HPE](brand) thế nào + - so sánh [camera Hikvision](product_name) với [Dahua](brand) + - [Windows 11 Pro](product_name) khác [Windows 11 Home](product_name) gì + - nên mua [laptop](product_type) nào + - sản phẩm nào tốt hơn + - cho tôi so sánh [máy chủ](product_type) [Dell](brand) và [HP](brand) + + - intent: ask_price + examples: | + - giá [laptop](product_type) này bao nhiêu + - [máy chủ Dell](product_name) giá bao nhiêu + - bao nhiêu tiền + - giá + - giá bán + - giá cả thế nào + - [camera](product_type) này bao nhiêu + - hỏi giá [switch](product_type) + - [Windows Server](product_name) giá bao nhiêu + - có khuyến mãi gì không + - giảm giá không + + - intent: ask_specifications + examples: | + - thông số kỹ thuật + - cấu hình + - specs + - [laptop](product_type) này cấu hình thế nào + - [máy chủ](product_type) có bao nhiêu RAM + - [camera](product_type) độ phân giải bao nhiêu + - [switch](product_type) có mấy port + - chi tiết sản phẩm + - thông tin kỹ thuật + - [server](product_type) dùng CPU gì + + - intent: ask_stock + examples: | + - còn hàng không + - có sẵn không + - còn không + - hết hàng chưa + - khi nào có hàng + - [laptop](product_type) này còn không + - [máy chủ](product_type) có sẵn không + - kiểm tra tồn kho + + - intent: ask_warranty + examples: | + - bảo hành bao lâu + - chế độ bảo hành + - warranty + - thời gian bảo hành + - [laptop](product_type) bảo hành thế nào + - [máy chủ](product_type) có bảo hành không + - chính sách bảo hành + + - intent: ask_promotion + examples: | + - có khuyến mãi gì không + - chương trình giảm giá + - promotion + - ưu đãi + - có giảm giá không + - khuyến mãi tháng này + - deal tốt nhất + + - intent: technical_support + examples: | + - hướng dẫn cài đặt + - cách setup + - support + - hỗ trợ kỹ thuật + - cài [Windows Server](product_name) thế nào + - cấu hình [switch](product_type) + - kết nối [camera](product_type) + - sửa lỗi + - troubleshoot + - không hoạt động + + - intent: recommend_product + examples: | + - tư vấn [laptop](product_type) + - gợi ý sản phẩm + - nên mua gì + - recommend + - [máy tính](product_type) nào tốt + - tư vấn giải pháp [camera](product_type) cho [văn phòng 500m2](use_case) + - [laptop](product_type) cho [sinh viên](use_case) + - [server](product_type) phù hợp cho [doanh nghiệp nhỏ](use_case) + - chọn [switch](product_type) gì cho [50 nhân viên](use_case) + + - intent: ask_category + examples: | + - có những loại sản phẩm gì + - danh mục + - categories + - bán gì + - sản phẩm nào + - tôi muốn xem [laptop](product_type) + - xem [máy chủ](product_type) + - danh sách [camera](product_type) + + - intent: out_of_scope + examples: | + - thời tiết hôm nay thế nào + - bạn tên gì + - bạn là ai + - đặt vé máy bay + - nhà hàng gần đây + - kể chuyện cười + - hát bài hát diff --git a/examples/it_store_bot/data/stories.yml b/examples/it_store_bot/data/stories.yml new file mode 100644 index 000000000000..404db4270dc6 --- /dev/null +++ b/examples/it_store_bot/data/stories.yml @@ -0,0 +1,78 @@ +version: "3.1" + +stories: + - story: greet and search laptop + steps: + - intent: greet + - action: utter_greet + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + + - story: search product with price range + steps: + - intent: search_product + entities: + - product_type: "laptop" + - price_range: "25 triệu" + - action: action_search_product + + - story: compare products + steps: + - intent: compare_products + entities: + - product_type: "server" + - action: action_compare_products + + - story: ask price + steps: + - intent: ask_price + entities: + - product_type: "laptop" + - action: action_show_price + + - story: check stock + steps: + - intent: ask_stock + entities: + - product_type: "camera" + - action: action_check_stock + + - story: ask for recommendations + steps: + - intent: recommend_product + entities: + - product_type: "laptop" + - use_case: "gaming" + - action: action_recommend_product + + - story: ask promotions + steps: + - intent: ask_promotion + - action: action_show_promotions + + - story: ask warranty + steps: + - intent: ask_warranty + - action: action_show_warranty + + - story: technical support + steps: + - intent: technical_support + - action: action_provide_support + + - story: show categories + steps: + - intent: ask_category + - action: action_show_category + + - story: out of scope + steps: + - intent: out_of_scope + - action: utter_out_of_scope + + - story: goodbye + steps: + - intent: goodbye + - action: utter_goodbye diff --git a/examples/it_store_bot/domain.yml b/examples/it_store_bot/domain.yml new file mode 100644 index 000000000000..7a98cbdad648 --- /dev/null +++ b/examples/it_store_bot/domain.yml @@ -0,0 +1,115 @@ +version: "3.1" + +intents: + - greet + - goodbye + - affirm + - deny + - thank + - search_product + - compare_products + - ask_price + - ask_specifications + - ask_stock + - ask_warranty + - ask_promotion + - technical_support + - recommend_product + - ask_category + - out_of_scope + +entities: + - product_type + - product_name + - brand + - price_range + - specification + - use_case + - quantity + +slots: + product_type: + type: text + influence_conversation: true + mappings: + - type: from_entity + entity: product_type + + product_name: + type: text + influence_conversation: true + mappings: + - type: from_entity + entity: product_name + + brand: + type: text + influence_conversation: false + mappings: + - type: from_entity + entity: brand + + price_range: + type: text + influence_conversation: true + mappings: + - type: from_entity + entity: price_range + + use_case: + type: text + influence_conversation: true + mappings: + - type: from_entity + entity: use_case + + quantity: + type: float + influence_conversation: false + mappings: + - type: from_entity + entity: quantity + +responses: + utter_greet: + - text: "Xin chào! Tôi là trợ lý AI của TechStore. Tôi có thể giúp bạn tìm kiếm và tư vấn sản phẩm IT như máy tính, máy chủ, switch, camera, và phần mềm. Bạn cần tìm sản phẩm gì hôm nay?" + + utter_goodbye: + - text: "Cảm ơn bạn đã liên hệ TechStore! Chúc bạn một ngày tốt lành. Hẹn gặp lại!" + - text: "Rất vui được hỗ trợ bạn! Nếu cần thêm thông tin, đừng ngại liên hệ lại nhé. Tạm biệt!" + + utter_thank: + - text: "Rất vui được giúp đỡ bạn! 😊" + - text: "Không có gì! Tôi luôn sẵn sàng hỗ trợ bạn." + + utter_ask_product_type: + - text: "Bạn đang tìm kiếm loại sản phẩm nào?\n• Máy tính/Laptop\n• Máy chủ (Server)\n• Switch mạng\n• Camera an ninh\n• Phần mềm" + + utter_ask_budget: + - text: "Bạn có ngân sách dự kiến bao nhiêu cho sản phẩm này?" + + utter_ask_use_case: + - text: "Bạn sẽ sử dụng sản phẩm cho mục đích gì?\n• Văn phòng\n• Gaming\n• Doanh nghiệp\n• Thiết kế đồ họa\n• Khác" + + utter_default: + - text: "Xin lỗi, tôi chưa hiểu rõ yêu cầu của bạn. Bạn có thể nói rõ hơn được không?" + - text: "Tôi có thể giúp bạn tìm kiếm sản phẩm, so sánh giá, hoặc tư vấn giải pháp IT. Bạn cần gì?" + + utter_out_of_scope: + - text: "Xin lỗi, câu hỏi này nằm ngoài phạm vi tư vấn sản phẩm IT của tôi. Tôi chỉ có thể hỗ trợ về máy tính, máy chủ, thiết bị mạng, camera và phần mềm. Bạn có câu hỏi nào khác không?" + +actions: + - action_search_product + - action_compare_products + - action_show_price + - action_show_specifications + - action_check_stock + - action_show_warranty + - action_show_promotions + - action_recommend_product + - action_provide_support + - action_show_category + +session_config: + session_expiration_time: 60 + carry_over_slots_to_new_session: true diff --git a/examples/it_store_bot/endpoints.yml b/examples/it_store_bot/endpoints.yml new file mode 100644 index 000000000000..86bc425b74c2 --- /dev/null +++ b/examples/it_store_bot/endpoints.yml @@ -0,0 +1,2 @@ +action_endpoint: + url: "http://localhost:5055/webhook" diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 000000000000..0e09122af26c --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,293 @@ + + + + + + TechStore AI - Trợ Lý Tư Vấn Sản Phẩm IT Thông Minh + + + + + +
+
+ + +
+
+ + +
+
+
+

Trợ Lý AI Tư Vấn Sản Phẩm IT

+

Tìm kiếm, so sánh và tư vấn sản phẩm công nghệ thông tin chuyên nghiệp với AI

+
+
+ AI Thông Minh +
+
+ Tư Vấn Nhanh +
+
+ Chuyên Nghiệp +
+
+ +
+
+
+ + Máy Chủ +
+
+ + Máy Tính +
+
+ + Switch +
+
+ + Camera +
+
+
+
+ + +
+
+

Danh Mục Sản Phẩm

+
+
+
+ +
+

Máy Tính

+

PC Desktop, Workstation, Gaming PC

+
+
+
+ +
+

Laptop

+

Laptop văn phòng, Gaming, Workstation

+
+
+
+ +
+

Máy Chủ

+

Server Dell, HP, Lenovo, Tower/Rack

+
+
+
+ +
+

Switch Mạng

+

Switch Cisco, HPE, Managed/Unmanaged

+
+
+
+ +
+

Camera An Ninh

+

IP Camera, NVR, DVR, Camera AI

+
+
+
+ +
+

Phần Mềm

+

Windows, Office, Antivirus, CAD

+
+
+
+
+ + +
+
+

Tính Năng Chatbot AI

+
+
+
+ +
+

Tìm Kiếm Thông Minh

+

Tìm sản phẩm theo tên, thông số kỹ thuật, giá cả, hoặc nhu cầu sử dụng

+
+ Xem ví dụ +
+
+
+
+ +
+

So Sánh Sản Phẩm

+

So sánh chi tiết 2-3 sản phẩm về cấu hình, giá cả, ưu nhược điểm

+
+ Xem ví dụ +
+
+
+
+ +
+

Tư Vấn Chuyên Nghiệp

+

Gợi ý sản phẩm phù hợp dựa trên mục đích sử dụng và ngân sách

+
+ Xem ví dụ +
+
+
+
+ +
+

Thông Số Kỹ Thuật

+

Giải thích chi tiết cấu hình, tính năng, khả năng tương thích

+
+ Xem ví dụ +
+
+
+
+ +
+

Báo Giá & Khuyến Mãi

+

Kiểm tra giá, tồn kho, chương trình khuyến mãi hiện hành

+
+ Xem ví dụ +
+
+
+
+ +
+

Hỗ Trợ Kỹ Thuật

+

Hướng dẫn cài đặt, khắc phục sự cố, chính sách bảo hành

+
+ Xem ví dụ +
+
+
+
+
+ + +
+
+
+
+
5000+
+
Sản Phẩm
+
+
+
95%
+
Độ Chính Xác
+
+
+
24/7
+
Hoạt Động
+
+
+
<3s
+
Thời Gian Phản Hồi
+
+
+
+
+ + +
+
+
+
+ +
+
+

TechStore AI Assistant

+

+ Đang hoạt động +

+
+
+ +
+ +
+
+
+ +
+
+

Xin chào! Tôi là trợ lý AI của TechStore. Tôi có thể giúp bạn:

+
    +
  • 🔍 Tìm kiếm sản phẩm IT
  • +
  • ⚖️ So sánh máy tính, máy chủ, switch, camera
  • +
  • 💡 Tư vấn giải pháp phù hợp
  • +
  • 💰 Báo giá và kiểm tra khuyến mãi
  • +
  • 🛠️ Hỗ trợ kỹ thuật
  • +
+

Bạn cần tìm sản phẩm gì hôm nay?

+
+
+
+ +
+
+ + + +
+
+ + +
+
+
+ + + + + + + + + + diff --git a/frontend/script.js b/frontend/script.js new file mode 100644 index 000000000000..892c675ea2ce --- /dev/null +++ b/frontend/script.js @@ -0,0 +1,482 @@ +// Configuration +const RASA_SERVER_URL = 'http://localhost:5005'; +const USER_ID = 'user_' + Math.random().toString(36).substr(2, 9); + +// Chat state +let chatOpen = false; +let conversationHistory = []; + +// Initialize +document.addEventListener('DOMContentLoaded', function() { + console.log('TechStore AI initialized'); + // Auto-open chat after 3 seconds for demo + setTimeout(() => { + if (!chatOpen) { + const badge = document.querySelector('.chat-badge'); + if (badge) { + badge.style.animation = 'pulse 1s infinite'; + } + } + }, 3000); +}); + +// Toggle chat widget +function toggleChat() { + const chatWidget = document.getElementById('chatWidget'); + const chatToggle = document.getElementById('chatToggle'); + const badge = document.querySelector('.chat-badge'); + + chatOpen = !chatOpen; + + if (chatOpen) { + chatWidget.classList.add('open'); + chatToggle.style.display = 'none'; + if (badge) badge.style.display = 'none'; + scrollToBottom(); + } else { + chatWidget.classList.remove('open'); + chatToggle.style.display = 'flex'; + } +} + +function openChat() { + if (!chatOpen) { + toggleChat(); + } +} + +function closeChat() { + if (chatOpen) { + toggleChat(); + } +} + +// Handle key press in input +function handleKeyPress(event) { + if (event.key === 'Enter') { + sendMessage(); + } +} + +// Send message to Rasa +async function sendMessage() { + const input = document.getElementById('chatInput'); + const message = input.value.trim(); + + if (!message) return; + + // Clear input + input.value = ''; + + // Add user message to chat + addMessage(message, 'user'); + + // Hide quick replies after first message + hideQuickReplies(); + + // Show typing indicator + showTypingIndicator(); + + try { + // Send to Rasa + const response = await fetch(`${RASA_SERVER_URL}/webhooks/rest/webhook`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + sender: USER_ID, + message: message + }) + }); + + // Hide typing indicator + hideTypingIndicator(); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + // Add bot responses + if (data && data.length > 0) { + data.forEach((msg, index) => { + setTimeout(() => { + if (msg.text) { + addMessage(msg.text, 'bot'); + } + if (msg.image) { + addImage(msg.image, 'bot'); + } + if (msg.custom) { + handleCustomMessage(msg.custom); + } + }, index * 500); + }); + } else { + addMessage('Xin lỗi, tôi không hiểu câu hỏi của bạn. Bạn có thể hỏi lại được không?', 'bot'); + } + + } catch (error) { + console.error('Error sending message:', error); + hideTypingIndicator(); + + // Fallback response when Rasa server is not available + addMessage( + '⚠️ Hiện tại hệ thống đang trong chế độ demo. Để kết nối với Rasa server, vui lòng:\n\n' + + '1. Chạy Rasa server: rasa run --enable-api --cors "*"\n' + + '2. Chạy action server: rasa run actions\n\n' + + 'Tôi sẽ demo một số tính năng cho bạn:', + 'bot' + ); + + // Demo response based on keywords + setTimeout(() => { + const demoResponse = generateDemoResponse(message); + addMessage(demoResponse, 'bot'); + }, 1000); + } +} + +// Generate demo response (fallback when Rasa is not running) +function generateDemoResponse(message) { + const lowerMessage = message.toLowerCase(); + + // Laptop queries + if (lowerMessage.includes('laptop') || lowerMessage.includes('máy tính xách tay')) { + if (lowerMessage.includes('gaming')) { + return '🎮 **Laptop Gaming Đề Xuất:**\n\n' + + '**1. ASUS ROG Strix G15**\n' + + '• CPU: AMD Ryzen 7 6800H\n' + + '• GPU: RTX 3060 6GB\n' + + '• RAM: 16GB DDR5\n' + + '• Màn hình: 15.6" FHD 144Hz\n' + + '• Giá: 28,990,000đ\n\n' + + '**2. MSI Katana GF66**\n' + + '• CPU: Intel i7-12650H\n' + + '• GPU: RTX 3050 Ti 4GB\n' + + '• RAM: 16GB DDR4\n' + + '• Màn hình: 15.6" FHD 144Hz\n' + + '• Giá: 24,990,000đ\n\n' + + 'Bạn muốn xem chi tiết sản phẩm nào?'; + } else { + return '💼 **Laptop Văn Phòng Phổ Biến:**\n\n' + + '**1. Dell Latitude 5420**\n' + + '• CPU: Intel i5-1135G7\n' + + '• RAM: 8GB\n' + + '• SSD: 256GB NVMe\n' + + '• Giá: 15,990,000đ\n\n' + + '**2. HP ProBook 450 G9**\n' + + '• CPU: Intel i7-1255U\n' + + '• RAM: 16GB\n' + + '• SSD: 512GB\n' + + '• Giá: 21,490,000đ\n\n' + + 'Bạn có ngân sách cụ thể không?'; + } + } + + // Server queries + if (lowerMessage.includes('máy chủ') || lowerMessage.includes('server')) { + return '🖥️ **Máy Chủ Doanh Nghiệp:**\n\n' + + '**1. Dell PowerEdge R740**\n' + + '• CPU: 2x Intel Xeon Gold 6230 (20 cores/40 threads mỗi CPU)\n' + + '• RAM: 128GB DDR4 ECC\n' + + '• Storage: 4x 1.2TB SAS HDD\n' + + '• Giá: 145,000,000đ\n\n' + + '**2. HP ProLiant DL380 Gen10**\n' + + '• CPU: 2x Intel Xeon Silver 4214 (12 cores/24 threads)\n' + + '• RAM: 64GB DDR4 ECC\n' + + '• Storage: 2x 960GB SSD\n' + + '• Giá: 98,000,000đ\n\n' + + 'Doanh nghiệp bạn cần máy chủ cho mục đích gì?'; + } + + // Camera queries + if (lowerMessage.includes('camera')) { + return '📹 **Giải Pháp Camera An Ninh:**\n\n' + + '**1. Hikvision DS-2CD2143G2-I**\n' + + '• Độ phân giải: 4MP\n' + + '• Công nghệ: AcuSense (nhận diện người/xe)\n' + + '• Tầm nhìn ban đêm: 30m\n' + + '• Giá: 2,890,000đ/camera\n\n' + + '**2. Dahua IPC-HDW3441TM-AS**\n' + + '• Độ phân giải: 4MP\n' + + '• Tích hợp Mic\n' + + '• AI SMD Plus\n' + + '• Giá: 1,990,000đ/camera\n\n' + + '**Gói Trọn Bộ Văn Phòng 500m2:**\n' + + '• 12 camera IP 4MP\n' + + '• 1 NVR 16 kênh Hikvision\n' + + '• 1 HDD 4TB\n' + + '• Phụ kiện lắp đặt\n' + + '• Giá: 38,900,000đ (bao gồm setup)\n\n' + + 'Bạn cần bao nhiêu camera?'; + } + + // Switch queries + if (lowerMessage.includes('switch')) { + return '🔌 **Switch Mạng Doanh Nghiệp:**\n\n' + + '**1. Cisco Catalyst 2960-X 48 Port**\n' + + '• 48 port Gigabit + 2 port 10G SFP+\n' + + '• Layer 2 Managed\n' + + '• Lifetime warranty\n' + + '• Giá: 42,500,000đ\n\n' + + '**2. HPE OfficeConnect 1920S 48G**\n' + + '• 48 port Gigabit + 4 port SFP\n' + + '• Layer 2+ Smart Managed\n' + + '• Giá: 18,900,000đ\n\n' + + 'Bạn cần switch cho văn phòng bao nhiêu nhân viên?'; + } + + // Software queries + if (lowerMessage.includes('phần mềm') || lowerMessage.includes('software')) { + return '💿 **Phần Mềm Thương Mại:**\n\n' + + '**Microsoft:**\n' + + '• Windows 11 Pro: 5,490,000đ\n' + + '• Windows Server 2022 Standard: 24,900,000đ\n' + + '• Office 2021 Professional Plus: 8,900,000đ\n' + + '• Microsoft 365 Business: 189,000đ/tháng/user\n\n' + + '**Antivirus:**\n' + + '• Kaspersky Endpoint Security: 450,000đ/user/năm\n' + + '• ESET Protect Advanced: 520,000đ/user/năm\n\n' + + '**CAD/Design:**\n' + + '• AutoCAD 2024: 45,500,000đ/năm\n' + + '• SolidWorks 2024: 8,900 USD/năm\n\n' + + 'Bạn cần license cho bao nhiêu máy?'; + } + + // Comparison queries + if (lowerMessage.includes('so sánh') || lowerMessage.includes('compare')) { + return '⚖️ **So Sánh Sản Phẩm:**\n\n' + + 'Tôi có thể giúp bạn so sánh chi tiết về:\n' + + '• Hiệu năng và cấu hình\n' + + '• Giá cả và tính năng\n' + + '• Ưu điểm và nhược điểm\n\n' + + 'Bạn muốn so sánh 2 sản phẩm nào? (VD: "So sánh Dell PowerEdge R740 và HP ProLiant DL380")'; + } + + // Price/promotion queries + if (lowerMessage.includes('giá') || lowerMessage.includes('khuyến mãi') || lowerMessage.includes('promotion')) { + return '🎁 **Chương Trình Khuyến Mãi Tháng Này:**\n\n' + + '**1. Laptop Gaming:**\n' + + '• Giảm 10-15% cho ASUS ROG series\n' + + '• Tặng kèm chuột + balo gaming\n\n' + + '**2. Máy Chủ:**\n' + + '• Giảm 8% cho đơn hàng từ 100 triệu\n' + + '• Hỗ trợ setup miễn phí\n\n' + + '**3. Giải pháp Camera:**\n' + + '• Mua 10 tặng 2 camera\n' + + '• Miễn phí lắp đặt trong 50km\n\n' + + 'Bạn quan tâm sản phẩm nào?'; + } + + // Technical support + if (lowerMessage.includes('cài đặt') || lowerMessage.includes('hướng dẫn') || lowerMessage.includes('support')) { + return '🛠️ **Hỗ Trợ Kỹ Thuật:**\n\n' + + 'Chúng tôi cung cấp:\n' + + '• Hướng dẫn cài đặt chi tiết\n' + + '• Hỗ trợ cấu hình từ xa\n' + + '• Bảo hành tận nơi\n' + + '• Hotline 24/7: 1900-xxxx\n\n' + + 'Bạn cần hỗ trợ về vấn đề gì?'; + } + + // Default response + return '👋 Tôi có thể giúp bạn:\n\n' + + '🔍 **Tìm kiếm sản phẩm:** "Tìm laptop gaming dưới 30 triệu"\n' + + '⚖️ **So sánh:** "So sánh Dell R740 và HP DL380"\n' + + '💡 **Tư vấn:** "Tư vấn giải pháp camera cho văn phòng"\n' + + '💰 **Báo giá:** "Giá máy chủ Dell PowerEdge"\n' + + '🛠️ **Hỗ trợ:** "Hướng dẫn cài Windows Server"\n\n' + + 'Bạn cần tìm sản phẩm gì?'; +} + +// Add message to chat +function addMessage(text, sender) { + const messagesContainer = document.getElementById('chatMessages'); + const messageDiv = document.createElement('div'); + messageDiv.className = `message ${sender}-message`; + + const avatar = document.createElement('div'); + avatar.className = 'message-avatar'; + avatar.innerHTML = sender === 'bot' ? '' : ''; + + const content = document.createElement('div'); + content.className = 'message-content'; + + // Parse text for better formatting + const formattedText = formatMessage(text); + content.innerHTML = formattedText; + + messageDiv.appendChild(avatar); + messageDiv.appendChild(content); + + messagesContainer.appendChild(messageDiv); + + // Store in history + conversationHistory.push({ + text: text, + sender: sender, + timestamp: new Date() + }); + + scrollToBottom(); +} + +// Format message text +function formatMessage(text) { + // Convert markdown-style formatting + let formatted = text + .replace(/\*\*(.+?)\*\*/g, '$1') // Bold + .replace(/\n/g, '
') // Line breaks + .replace(/• /g, '• '); // Bullets + + return formatted; +} + +// Add image to chat +function addImage(imageUrl, sender) { + const messagesContainer = document.getElementById('chatMessages'); + const messageDiv = document.createElement('div'); + messageDiv.className = `message ${sender}-message`; + + const avatar = document.createElement('div'); + avatar.className = 'message-avatar'; + avatar.innerHTML = ''; + + const content = document.createElement('div'); + content.className = 'message-content'; + content.innerHTML = ``; + + messageDiv.appendChild(avatar); + messageDiv.appendChild(content); + messagesContainer.appendChild(messageDiv); + + scrollToBottom(); +} + +// Handle custom messages (e.g., product cards) +function handleCustomMessage(customData) { + if (customData.type === 'product') { + addProductCard(customData); + } else if (customData.type === 'product_list') { + customData.products.forEach(product => { + addProductCard(product); + }); + } +} + +// Add product card +function addProductCard(product) { + const messagesContainer = document.getElementById('chatMessages'); + const messageDiv = document.createElement('div'); + messageDiv.className = 'message bot-message'; + + const avatar = document.createElement('div'); + avatar.className = 'message-avatar'; + avatar.innerHTML = ''; + + const content = document.createElement('div'); + content.className = 'message-content'; + + const card = document.createElement('div'); + card.className = 'product-card'; + card.innerHTML = ` +

${product.name}

+
${product.price}
+
${product.specs || ''}
+ ${product.stock ? `
✓ Còn hàng
` : ''} + `; + + content.appendChild(card); + messageDiv.appendChild(avatar); + messageDiv.appendChild(content); + messagesContainer.appendChild(messageDiv); + + scrollToBottom(); +} + +// Show typing indicator +function showTypingIndicator() { + const messagesContainer = document.getElementById('chatMessages'); + const typingDiv = document.createElement('div'); + typingDiv.className = 'message bot-message'; + typingDiv.id = 'typingIndicator'; + + const avatar = document.createElement('div'); + avatar.className = 'message-avatar'; + avatar.innerHTML = ''; + + const content = document.createElement('div'); + content.className = 'message-content'; + content.innerHTML = '
'; + + typingDiv.appendChild(avatar); + typingDiv.appendChild(content); + messagesContainer.appendChild(typingDiv); + + scrollToBottom(); +} + +// Hide typing indicator +function hideTypingIndicator() { + const typingIndicator = document.getElementById('typingIndicator'); + if (typingIndicator) { + typingIndicator.remove(); + } +} + +// Scroll to bottom of chat +function scrollToBottom() { + const messagesContainer = document.getElementById('chatMessages'); + setTimeout(() => { + messagesContainer.scrollTop = messagesContainer.scrollHeight; + }, 100); +} + +// Hide quick replies +function hideQuickReplies() { + const quickReplies = document.getElementById('quickReplies'); + if (quickReplies) { + quickReplies.style.display = 'none'; + } +} + +// Send quick reply +function sendQuickReply(text) { + document.getElementById('chatInput').value = text; + sendMessage(); +} + +// Ask about category +function askAboutCategory(category) { + openChat(); + setTimeout(() => { + document.getElementById('chatInput').value = `Tôi muốn xem ${category}`; + sendMessage(); + }, 300); +} + +// Ask example question +function askExample(question) { + openChat(); + setTimeout(() => { + document.getElementById('chatInput').value = question; + sendMessage(); + }, 300); +} + +// Smooth scroll for navigation +document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + e.preventDefault(); + const target = document.querySelector(this.getAttribute('href')); + if (target) { + target.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + }); +}); diff --git a/frontend/style.css b/frontend/style.css new file mode 100644 index 000000000000..f57b6f79e750 --- /dev/null +++ b/frontend/style.css @@ -0,0 +1,760 @@ +/* Reset & Base Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary-color: #2563eb; + --primary-dark: #1e40af; + --secondary-color: #10b981; + --accent-color: #f59e0b; + --text-dark: #1f2937; + --text-light: #6b7280; + --bg-light: #f9fafb; + --bg-white: #ffffff; + --border-color: #e5e7eb; + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; + line-height: 1.6; + color: var(--text-dark); + background-color: var(--bg-light); +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; +} + +/* Header */ +.header { + background: var(--bg-white); + box-shadow: var(--shadow-sm); + position: sticky; + top: 0; + z-index: 100; +} + +.header .container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 20px; +} + +.logo { + display: flex; + align-items: center; + gap: 10px; + font-size: 24px; + font-weight: bold; + color: var(--primary-color); +} + +.logo i { + font-size: 28px; +} + +.nav { + display: flex; + gap: 30px; +} + +.nav a { + text-decoration: none; + color: var(--text-dark); + font-weight: 500; + transition: color 0.3s; +} + +.nav a:hover { + color: var(--primary-color); +} + +/* Hero Section */ +.hero { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 80px 20px; + position: relative; + overflow: hidden; +} + +.hero::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url('data:image/svg+xml,'); + opacity: 0.3; +} + +.hero .container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 60px; + align-items: center; + position: relative; + z-index: 1; +} + +.hero-content h1 { + font-size: 48px; + margin-bottom: 20px; + line-height: 1.2; +} + +.hero-content p { + font-size: 20px; + margin-bottom: 30px; + opacity: 0.9; +} + +.hero-features { + display: flex; + gap: 15px; + margin-bottom: 30px; + flex-wrap: wrap; +} + +.feature-tag { + background: rgba(255, 255, 255, 0.2); + padding: 8px 16px; + border-radius: 20px; + font-size: 14px; + backdrop-filter: blur(10px); +} + +.feature-tag i { + margin-right: 5px; +} + +.cta-button { + background: var(--bg-white); + color: var(--primary-color); + border: none; + padding: 15px 30px; + font-size: 18px; + font-weight: 600; + border-radius: 10px; + cursor: pointer; + transition: transform 0.3s, box-shadow 0.3s; + box-shadow: var(--shadow-lg); +} + +.cta-button:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-xl); +} + +.cta-button i { + margin-right: 8px; +} + +.hero-image { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + position: relative; +} + +.floating-card { + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + padding: 30px; + border-radius: 15px; + text-align: center; + animation: float 3s ease-in-out infinite; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.floating-card i { + font-size: 40px; + margin-bottom: 10px; + display: block; +} + +.floating-card span { + font-size: 14px; + font-weight: 500; +} + +@keyframes float { + 0%, 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-20px); + } +} + +/* Categories Section */ +.categories { + padding: 80px 20px; + background: var(--bg-white); +} + +.section-title { + text-align: center; + font-size: 36px; + margin-bottom: 50px; + color: var(--text-dark); +} + +.category-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 30px; +} + +.category-card { + background: var(--bg-white); + border: 2px solid var(--border-color); + border-radius: 15px; + padding: 30px; + text-align: center; + cursor: pointer; + transition: all 0.3s; +} + +.category-card:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); + border-color: var(--primary-color); +} + +.category-icon { + width: 80px; + height: 80px; + margin: 0 auto 20px; + background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); + border-radius: 20px; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 36px; +} + +.category-card h3 { + font-size: 22px; + margin-bottom: 10px; + color: var(--text-dark); +} + +.category-card p { + color: var(--text-light); + font-size: 14px; +} + +/* Features Section */ +.features { + padding: 80px 20px; + background: var(--bg-light); +} + +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 30px; +} + +.feature-item { + background: var(--bg-white); + padding: 30px; + border-radius: 15px; + box-shadow: var(--shadow-md); + transition: transform 0.3s; +} + +.feature-item:hover { + transform: translateY(-5px); +} + +.feature-icon { + width: 60px; + height: 60px; + background: linear-gradient(135deg, var(--secondary-color), #059669); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 28px; + margin-bottom: 20px; +} + +.feature-item h3 { + font-size: 20px; + margin-bottom: 10px; + color: var(--text-dark); +} + +.feature-item p { + color: var(--text-light); + margin-bottom: 15px; + line-height: 1.6; +} + +.feature-example { + display: inline-flex; + align-items: center; + gap: 8px; + color: var(--primary-color); + font-size: 14px; + font-weight: 500; + cursor: pointer; + padding: 8px 12px; + border-radius: 6px; + transition: background 0.3s; +} + +.feature-example:hover { + background: var(--bg-light); +} + +/* Stats Section */ +.stats { + padding: 60px 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 40px; + text-align: center; +} + +.stat-number { + font-size: 48px; + font-weight: bold; + margin-bottom: 10px; +} + +.stat-label { + font-size: 18px; + opacity: 0.9; +} + +/* Chat Widget */ +.chat-widget { + position: fixed; + bottom: 100px; + right: 30px; + width: 400px; + height: 600px; + background: var(--bg-white); + border-radius: 20px; + box-shadow: var(--shadow-xl); + display: none; + flex-direction: column; + z-index: 1000; + overflow: hidden; +} + +.chat-widget.open { + display: flex; +} + +.chat-header { + background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); + color: white; + padding: 20px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.chat-header-content { + display: flex; + align-items: center; + gap: 12px; +} + +.bot-avatar { + width: 45px; + height: 45px; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; +} + +.chat-header-text h3 { + font-size: 16px; + margin-bottom: 3px; +} + +.chat-status { + font-size: 12px; + opacity: 0.9; + display: flex; + align-items: center; + gap: 6px; +} + +.status-dot { + width: 8px; + height: 8px; + background: var(--secondary-color); + border-radius: 50%; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.chat-close { + background: none; + border: none; + color: white; + font-size: 20px; + cursor: pointer; + padding: 5px; + opacity: 0.8; + transition: opacity 0.3s; +} + +.chat-close:hover { + opacity: 1; +} + +.chat-messages { + flex: 1; + overflow-y: auto; + padding: 20px; + background: var(--bg-light); +} + +.message { + display: flex; + gap: 10px; + margin-bottom: 20px; + animation: slideIn 0.3s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.message-avatar { + width: 35px; + height: 35px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + font-size: 16px; +} + +.bot-message .message-avatar { + background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); + color: white; +} + +.user-message { + flex-direction: row-reverse; +} + +.user-message .message-avatar { + background: var(--secondary-color); + color: white; +} + +.message-content { + background: var(--bg-white); + padding: 12px 16px; + border-radius: 12px; + max-width: 70%; + box-shadow: var(--shadow-sm); +} + +.user-message .message-content { + background: var(--primary-color); + color: white; +} + +.message-content p { + margin-bottom: 8px; +} + +.message-content p:last-child { + margin-bottom: 0; +} + +.message-content ul { + margin: 10px 0; + padding-left: 20px; +} + +.message-content ul li { + margin: 5px 0; +} + +.product-card { + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 12px; + margin: 10px 0; + background: var(--bg-light); +} + +.product-card h4 { + color: var(--primary-color); + margin-bottom: 8px; +} + +.product-card .price { + font-size: 18px; + font-weight: bold; + color: var(--accent-color); + margin: 8px 0; +} + +.product-card .specs { + font-size: 13px; + color: var(--text-light); + line-height: 1.5; +} + +.typing-indicator { + display: flex; + gap: 4px; + padding: 10px; +} + +.typing-indicator span { + width: 8px; + height: 8px; + background: var(--text-light); + border-radius: 50%; + animation: typing 1.4s infinite; +} + +.typing-indicator span:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-indicator span:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes typing { + 0%, 60%, 100% { + transform: translateY(0); + } + 30% { + transform: translateY(-10px); + } +} + +.quick-replies { + padding: 10px 15px 5px; + display: flex; + gap: 8px; + flex-wrap: wrap; + background: var(--bg-white); + border-top: 1px solid var(--border-color); +} + +.quick-reply { + background: var(--bg-light); + border: 1px solid var(--border-color); + padding: 6px 12px; + border-radius: 15px; + font-size: 13px; + cursor: pointer; + transition: all 0.3s; + color: var(--text-dark); +} + +.quick-reply:hover { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.quick-reply i { + margin-right: 4px; + font-size: 12px; +} + +.chat-input-container { + background: var(--bg-white); + border-top: 1px solid var(--border-color); +} + +.chat-input-wrapper { + display: flex; + padding: 15px; + gap: 10px; +} + +.chat-input { + flex: 1; + border: 1px solid var(--border-color); + border-radius: 25px; + padding: 12px 20px; + font-size: 14px; + outline: none; + transition: border-color 0.3s; +} + +.chat-input:focus { + border-color: var(--primary-color); +} + +.chat-send { + width: 45px; + height: 45px; + background: var(--primary-color); + color: white; + border: none; + border-radius: 50%; + cursor: pointer; + transition: background 0.3s, transform 0.3s; + font-size: 16px; +} + +.chat-send:hover { + background: var(--primary-dark); + transform: scale(1.05); +} + +.chat-send:active { + transform: scale(0.95); +} + +/* Chat Toggle Button */ +.chat-toggle { + position: fixed; + bottom: 30px; + right: 30px; + width: 60px; + height: 60px; + background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); + color: white; + border: none; + border-radius: 50%; + font-size: 24px; + cursor: pointer; + box-shadow: var(--shadow-lg); + transition: transform 0.3s; + z-index: 999; +} + +.chat-toggle:hover { + transform: scale(1.1); +} + +.chat-badge { + position: absolute; + top: -5px; + right: -5px; + background: var(--accent-color); + color: white; + width: 24px; + height: 24px; + border-radius: 50%; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; +} + +/* Footer */ +.footer { + background: var(--text-dark); + color: white; + text-align: center; + padding: 30px 20px; +} + +.footer p { + opacity: 0.8; + margin: 5px 0; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .hero .container { + grid-template-columns: 1fr; + gap: 40px; + } + + .hero-content h1 { + font-size: 36px; + } + + .hero-image { + display: none; + } + + .nav { + display: none; + } + + .chat-widget { + width: 100%; + height: 100%; + bottom: 0; + right: 0; + border-radius: 0; + } + + .category-grid, + .features-grid { + grid-template-columns: 1fr; + } + + .section-title { + font-size: 28px; + } +} + +/* Scrollbar Styling */ +.chat-messages::-webkit-scrollbar { + width: 6px; +} + +.chat-messages::-webkit-scrollbar-track { + background: var(--bg-light); +} + +.chat-messages::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 3px; +} + +.chat-messages::-webkit-scrollbar-thumb:hover { + background: var(--text-light); +} diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 000000000000..1220bfc2c4b1 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,144 @@ +# Training Data Tools + +Công cụ hỗ trợ tạo và validate training data cho Rasa. + +## 🛠️ Công Cụ + +### 1. generate_training_data.py + +Tự động generate training data từ templates. + +**Sử dụng:** +```bash +python tools/generate_training_data.py +``` + +**Tính năng:** +- ✅ Generate examples từ templates +- ✅ Tự động annotate entities +- ✅ Augment data (synonyms, typos) +- ✅ Validate data ngay sau khi generate + +**Output:** +- `generated_nlu.yml` - File NLU data mới + +### 2. validate_training_data.py + +Kiểm tra chất lượng training data. + +**Sử dụng:** +```bash +# Validate single file +python tools/validate_training_data.py data/nlu.yml + +# Validate IT store bot +python tools/validate_training_data.py examples/it_store_bot/data/nlu.yml +``` + +**Kiểm tra:** +- ❌ **Errors** (phải fix): + - Intent có quá ít examples (< 10) + - Duplicate examples quá nhiều (> 10%) + - 2 intents có examples giống nhau + +- ⚠️ **Warnings** (nên fix): + - Intent có ít examples (< 20) + - Examples quá ngắn (< 2 từ) + - Examples quá giống nhau + - Entity được dùng quá ít + +**Output:** +``` +📊 VALIDATION REPORT +=================== +📈 STATISTICS: + • Total Intents: 15 + • Total Examples: 320 + • Average Examples per Intent: 21.3 + +❌ ERRORS (2): + ❌ Intent 'search_product': Only 8 examples (minimum: 10) + ❌ Intents 'search' and 'find' have 3 identical examples! + +⚠️ WARNINGS (1): + ⚠️ Intent 'ask_price': Only 12 examples (recommended: 20) +``` + +## 📝 Examples + +### Generate Data + +```python +from generate_training_data import TrainingDataGenerator + +generator = TrainingDataGenerator() + +# Generate 50 examples per intent +examples = generator.generate_intent_examples('search_product', 50) + +# Generate complete NLU file +generator.generate_nlu_file('output.yml') +``` + +### Annotate Entities + +```python +from generate_training_data import EntityAnnotator + +annotator = EntityAnnotator() + +# Annotate single text +text = "tìm laptop Dell" +annotated = annotator.annotate(text) +# Output: "tìm [laptop](product_type) [Dell](brand)" + +# Annotate entire file +annotator.annotate_file('input.yml', 'output.yml') +``` + +### Validate Data + +```python +from validate_training_data import TrainingDataValidator + +validator = TrainingDataValidator() + +# Validate file +report = validator.validate_file('data/nlu.yml') + +# Print report +validator.print_report(report) +``` + +## 🎯 Workflow Đề Xuất + +```bash +# 1. Generate training data +python tools/generate_training_data.py + +# 2. Validate data +python tools/validate_training_data.py generated_nlu.yml + +# 3. Fix errors nếu có + +# 4. Validate bằng Rasa +rasa data validate + +# 5. Train +rasa train + +# 6. Test +rasa test nlu --nlu generated_nlu.yml +``` + +## 🔧 Requirements + +```bash +pip install pyyaml +``` + +## 📚 Resources + +- Xem `TRAINING_DATA_GUIDE_VI.md` để học chi tiết +- Xem `training_templates/` để có templates +- Xem `QUICK_REFERENCE.md` để tra cứu nhanh diff --git a/tools/generate_training_data.py b/tools/generate_training_data.py new file mode 100644 index 000000000000..2561957b12b0 --- /dev/null +++ b/tools/generate_training_data.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python3 +""" +Script to generate training data automatically +Usage: python generate_training_data.py +""" + +import random +from typing import List, Dict +import yaml + + +# ============ DATA GENERATORS ============ + +class TrainingDataGenerator: + """Generate diverse training examples""" + + def __init__(self): + self.templates = { + 'search_product': [ + "tìm {product}", + "cho tôi xem {product}", + "có {product} nào không", + "tôi muốn mua {product}", + "{product} giá bao nhiêu", + "tìm {product} {brand}", + "{product} {brand} có không", + "cho xem {product} dưới {price}", + "tìm {product} cho {use_case}", + "{product} {use_case}", + ], + 'ask_price': [ + "giá bao nhiêu", + "{product} giá bao nhiêu", + "giá {product} {brand}", + "bao nhiêu tiền", + "hỏi giá {product}", + "giá cả thế nào", + "{product} này giá bn", + ], + 'compare_products': [ + "so sánh {product1} và {product2}", + "{product1} so với {product2}", + "khác nhau gì giữa {brand1} và {brand2}", + "{brand1} tốt hơn {brand2} không", + "nên chọn {product} nào", + ], + } + + self.products = ['laptop', 'máy tính', 'máy chủ', 'server', 'camera', 'switch'] + self.brands = ['Dell', 'HP', 'ASUS', 'MSI', 'Lenovo', 'Cisco', 'Hikvision'] + self.prices = ['10 triệu', '20 triệu', '30 triệu', '50 triệu', '100 triệu'] + self.use_cases = ['gaming', 'văn phòng', 'sinh viên', 'doanh nghiệp', 'thiết kế'] + + def generate_intent_examples(self, intent_name: str, num_examples: int = 50) -> List[str]: + """Generate examples for an intent""" + if intent_name not in self.templates: + print(f"Warning: No template for intent '{intent_name}'") + return [] + + examples = [] + templates = self.templates[intent_name] + + for _ in range(num_examples): + template = random.choice(templates) + + # Replace placeholders + example = template + if '{product}' in template: + example = example.replace('{product}', random.choice(self.products)) + if '{brand}' in template: + example = example.replace('{brand}', random.choice(self.brands)) + if '{price}' in template: + example = example.replace('{price}', random.choice(self.prices)) + if '{use_case}' in template: + example = example.replace('{use_case}', random.choice(self.use_cases)) + if '{product1}' in template: + example = example.replace('{product1}', random.choice(self.products)) + if '{product2}' in template: + example = example.replace('{product2}', random.choice(self.products)) + if '{brand1}' in template: + example = example.replace('{brand1}', random.choice(self.brands)) + if '{brand2}' in template: + example = example.replace('{brand2}', random.choice(self.brands)) + + # Avoid duplicates + if example not in examples: + examples.append(example) + + return examples + + def generate_nlu_file(self, output_path: str): + """Generate complete NLU file""" + nlu_data = { + 'version': '3.1', + 'nlu': [] + } + + for intent_name in self.templates.keys(): + examples = self.generate_intent_examples(intent_name, num_examples=50) + examples_text = '\n - '.join([''] + examples) + + nlu_data['nlu'].append({ + 'intent': intent_name, + 'examples': examples_text + }) + + with open(output_path, 'w', encoding='utf-8') as f: + yaml.dump(nlu_data, f, allow_unicode=True, sort_keys=False) + + print(f"✅ Generated NLU file: {output_path}") + print(f" Total intents: {len(self.templates)}") + print(f" Total examples: {sum(len(self.generate_intent_examples(i, 50)) for i in self.templates.keys())}") + + +# ============ ENTITY ANNOTATOR ============ + +class EntityAnnotator: + """Automatically annotate entities in examples""" + + def __init__(self): + self.entity_patterns = { + 'product_type': ['laptop', 'máy tính', 'máy chủ', 'server', 'camera', 'switch'], + 'brand': ['Dell', 'HP', 'ASUS', 'MSI', 'Lenovo', 'Cisco', 'Hikvision', 'Dahua'], + 'price_range': ['10 triệu', '20 triệu', '30 triệu', 'dưới 50 triệu'], + } + + def annotate(self, text: str) -> str: + """Annotate entities in text""" + annotated = text + + for entity_type, patterns in self.entity_patterns.items(): + for pattern in patterns: + if pattern in annotated and f'[{pattern}]' not in annotated: + annotated = annotated.replace(pattern, f'[{pattern}]({entity_type})') + + return annotated + + def annotate_file(self, input_path: str, output_path: str): + """Annotate entities in an NLU file""" + with open(input_path, 'r', encoding='utf-8') as f: + data = yaml.safe_load(f) + + if 'nlu' not in data: + print("Error: Not a valid NLU file") + return + + for intent_data in data['nlu']: + if 'examples' in intent_data: + examples = intent_data['examples'].split('\n') + annotated_examples = [] + + for example in examples: + if example.strip().startswith('- '): + text = example.strip()[2:] # Remove '- ' + annotated = self.annotate(text) + annotated_examples.append(f" - {annotated}") + else: + annotated_examples.append(example) + + intent_data['examples'] = '\n'.join(annotated_examples) + + with open(output_path, 'w', encoding='utf-8') as f: + yaml.dump(data, f, allow_unicode=True, sort_keys=False) + + print(f"✅ Annotated file saved: {output_path}") + + +# ============ DATA AUGMENTER ============ + +class DataAugmenter: + """Augment existing training data""" + + def __init__(self): + self.variations = { + 'laptop': ['máy tính', 'máy tính xách tay', 'notebook', 'laptop'], + 'máy chủ': ['server', 'máy chủ', 'may chu'], + 'camera': ['cam', 'camera', 'camera an ninh'], + } + + self.typos = { + 'bao nhiêu': ['bao nhiu', 'bn'], + 'tìm': ['tim', 'tiem'], + 'có': ['co'], + } + + def augment_examples(self, examples: List[str]) -> List[str]: + """Create variations of examples""" + augmented = examples.copy() + + for example in examples[:]: # Copy to avoid modifying during iteration + # Synonym replacement + for original, variations in self.variations.items(): + if original in example: + for variation in variations: + new_example = example.replace(original, variation) + if new_example not in augmented: + augmented.append(new_example) + + # Add typos (10% of examples) + if random.random() < 0.1: + for correct, typo_list in self.typos.items(): + if correct in example: + typo = random.choice(typo_list) + new_example = example.replace(correct, typo) + if new_example not in augmented: + augmented.append(new_example) + + return augmented + + +# ============ VALIDATOR ============ + +class DataValidator: + """Validate training data quality""" + + def __init__(self): + self.min_examples_per_intent = 10 + self.max_examples_per_intent = 500 + + def validate_nlu_file(self, file_path: str) -> Dict: + """Validate NLU file and return report""" + with open(file_path, 'r', encoding='utf-8') as f: + data = yaml.safe_load(f) + + report = { + 'total_intents': 0, + 'total_examples': 0, + 'warnings': [], + 'errors': [] + } + + if 'nlu' not in data: + report['errors'].append("Invalid NLU file format") + return report + + intent_examples_count = {} + + for intent_data in data['nlu']: + intent_name = intent_data.get('intent', 'unknown') + examples_text = intent_data.get('examples', '') + examples = [e.strip() for e in examples_text.split('\n') if e.strip().startswith('-')] + + num_examples = len(examples) + intent_examples_count[intent_name] = num_examples + report['total_examples'] += num_examples + + # Check minimum examples + if num_examples < self.min_examples_per_intent: + report['warnings'].append( + f"Intent '{intent_name}' has only {num_examples} examples (min: {self.min_examples_per_intent})" + ) + + # Check maximum examples + if num_examples > self.max_examples_per_intent: + report['warnings'].append( + f"Intent '{intent_name}' has {num_examples} examples (max: {self.max_examples_per_intent})" + ) + + # Check for duplicates + unique_examples = set(examples) + if len(unique_examples) < len(examples): + duplicates = len(examples) - len(unique_examples) + report['warnings'].append( + f"Intent '{intent_name}' has {duplicates} duplicate examples" + ) + + report['total_intents'] = len(intent_examples_count) + + return report + + def print_report(self, report: Dict): + """Print validation report""" + print("\n" + "=" * 60) + print("📊 TRAINING DATA VALIDATION REPORT") + print("=" * 60) + print(f"\n✓ Total Intents: {report['total_intents']}") + print(f"✓ Total Examples: {report['total_examples']}") + print(f"✓ Average Examples per Intent: {report['total_examples'] / report['total_intents']:.1f}") + + if report['errors']: + print(f"\n❌ ERRORS ({len(report['errors'])}):") + for error in report['errors']: + print(f" • {error}") + + if report['warnings']: + print(f"\n⚠️ WARNINGS ({len(report['warnings'])}):") + for warning in report['warnings']: + print(f" • {warning}") + + if not report['errors'] and not report['warnings']: + print("\n✅ All checks passed!") + + print("=" * 60 + "\n") + + +# ============ MAIN ============ + +def main(): + """Main function with examples""" + print("=" * 60) + print("🤖 RASA TRAINING DATA GENERATOR") + print("=" * 60) + + # Example 1: Generate new NLU data + print("\n1️⃣ Generating NLU data...") + generator = TrainingDataGenerator() + generator.generate_nlu_file('generated_nlu.yml') + + # Example 2: Annotate entities + print("\n2️⃣ Annotating entities...") + annotator = EntityAnnotator() + # annotator.annotate_file('input.yml', 'output_annotated.yml') + + # Example 3: Validate data + print("\n3️⃣ Validating data...") + validator = DataValidator() + report = validator.validate_nlu_file('generated_nlu.yml') + validator.print_report(report) + + print("\n✅ Done! Check the generated files.") + + +if __name__ == '__main__': + main() diff --git a/tools/validate_training_data.py b/tools/validate_training_data.py new file mode 100644 index 000000000000..a2f5f34da254 --- /dev/null +++ b/tools/validate_training_data.py @@ -0,0 +1,360 @@ +#!/usr/bin/env python3 +""" +Validate Rasa training data quality +Usage: python validate_training_data.py +""" + +import sys +import yaml +from pathlib import Path +from collections import Counter, defaultdict +from typing import Dict, List, Tuple +import re + + +class TrainingDataValidator: + """Comprehensive training data validation""" + + def __init__(self): + self.warnings = [] + self.errors = [] + self.stats = {} + + # Thresholds + self.MIN_EXAMPLES = 10 + self.RECOMMENDED_EXAMPLES = 20 + self.MAX_EXAMPLES = 500 + self.MIN_WORD_LENGTH = 2 + self.DUPLICATE_THRESHOLD = 0.1 # 10% duplicates is too much + + def validate_file(self, file_path: str) -> Dict: + """Main validation function""" + print(f"\n{'='*70}") + print(f"🔍 VALIDATING: {file_path}") + print(f"{'='*70}\n") + + try: + with open(file_path, 'r', encoding='utf-8') as f: + data = yaml.safe_load(f) + except Exception as e: + self.errors.append(f"Failed to load file: {str(e)}") + return self._generate_report() + + if 'nlu' not in data: + self.errors.append("Invalid NLU file format - missing 'nlu' key") + return self._generate_report() + + # Run all checks + self._check_version(data) + self._check_intents(data['nlu']) + self._check_examples_quality(data['nlu']) + self._check_entities(data['nlu']) + self._check_intent_similarity(data['nlu']) + + return self._generate_report() + + def _check_version(self, data: Dict): + """Check Rasa version""" + if 'version' not in data: + self.warnings.append("Missing 'version' field") + elif data['version'] != '3.1': + self.warnings.append(f"Version is {data['version']}, recommended: 3.1") + + def _check_intents(self, nlu_data: List[Dict]): + """Check intents structure and count""" + intent_examples = {} + + for item in nlu_data: + if 'intent' not in item: + # Might be synonym, regex, lookup + continue + + intent_name = item['intent'] + examples_text = item.get('examples', '') + examples = self._parse_examples(examples_text) + + intent_examples[intent_name] = examples + + # Check minimum examples + num_examples = len(examples) + if num_examples < self.MIN_EXAMPLES: + self.errors.append( + f"❌ Intent '{intent_name}': Only {num_examples} examples " + f"(minimum: {self.MIN_EXAMPLES})" + ) + elif num_examples < self.RECOMMENDED_EXAMPLES: + self.warnings.append( + f"⚠️ Intent '{intent_name}': Only {num_examples} examples " + f"(recommended: {self.RECOMMENDED_EXAMPLES})" + ) + + # Check maximum examples + if num_examples > self.MAX_EXAMPLES: + self.warnings.append( + f"⚠️ Intent '{intent_name}': {num_examples} examples " + f"(might be too many, consider reviewing)" + ) + + self.stats['total_intents'] = len(intent_examples) + self.stats['total_examples'] = sum(len(ex) for ex in intent_examples.values()) + self.stats['intent_examples'] = intent_examples + + def _check_examples_quality(self, nlu_data: List[Dict]): + """Check quality of examples""" + for item in nlu_data: + if 'intent' not in item: + continue + + intent_name = item['intent'] + examples = self.stats['intent_examples'].get(intent_name, []) + + if not examples: + continue + + # Check for duplicates + duplicates = len(examples) - len(set(examples)) + if duplicates > 0: + dup_rate = duplicates / len(examples) + if dup_rate > self.DUPLICATE_THRESHOLD: + self.errors.append( + f"❌ Intent '{intent_name}': {duplicates} duplicate examples " + f"({dup_rate*100:.1f}%)" + ) + else: + self.warnings.append( + f"⚠️ Intent '{intent_name}': {duplicates} duplicate examples" + ) + + # Check for very short examples + short_examples = [ex for ex in examples if len(ex.split()) < self.MIN_WORD_LENGTH] + if short_examples: + self.warnings.append( + f"⚠️ Intent '{intent_name}': {len(short_examples)} examples " + f"with < {self.MIN_WORD_LENGTH} words" + ) + + # Check for very similar examples (simple heuristic) + similar_count = self._count_similar_examples(examples) + if similar_count > len(examples) * 0.3: # >30% similar + self.warnings.append( + f"⚠️ Intent '{intent_name}': Many similar examples detected " + f"(diversity might be low)" + ) + + # Check variation in length + lengths = [len(ex.split()) for ex in examples] + if max(lengths) - min(lengths) < 3: + self.warnings.append( + f"⚠️ Intent '{intent_name}': Low length variation " + f"(all examples have similar length)" + ) + + def _check_entities(self, nlu_data: List[Dict]): + """Check entity annotations""" + entity_counts = defaultdict(int) + + for item in nlu_data: + if 'intent' not in item: + continue + + intent_name = item['intent'] + examples = self.stats['intent_examples'].get(intent_name, []) + + for example in examples: + # Find entity annotations [text](entity_type) + entities = re.findall(r'\[([^\]]+)\]\(([^)]+)\)', example) + for _, entity_type in entities: + entity_counts[entity_type] += 1 + + self.stats['entity_counts'] = dict(entity_counts) + + # Check if entities are used consistently + for entity_type, count in entity_counts.items(): + if count < 5: + self.warnings.append( + f"⚠️ Entity '{entity_type}': Only used {count} times " + f"(might need more examples)" + ) + + def _check_intent_similarity(self, nlu_data: List[Dict]): + """Check for potentially overlapping intents""" + intent_examples = self.stats.get('intent_examples', {}) + + if len(intent_examples) < 2: + return + + intent_names = list(intent_examples.keys()) + + for i, intent1 in enumerate(intent_names): + for intent2 in intent_names[i+1:]: + examples1 = set(self._normalize_examples(intent_examples[intent1])) + examples2 = set(self._normalize_examples(intent_examples[intent2])) + + overlap = examples1 & examples2 + if overlap: + self.errors.append( + f"❌ Intents '{intent1}' and '{intent2}' have {len(overlap)} " + f"identical examples!" + ) + + # Check semantic similarity (simple word overlap) + similarity = self._calculate_intent_similarity(examples1, examples2) + if similarity > 0.5: + self.warnings.append( + f"⚠️ Intents '{intent1}' and '{intent2}' seem very similar " + f"(similarity: {similarity:.2%})" + ) + + def _parse_examples(self, examples_text: str) -> List[str]: + """Parse examples from YAML text""" + examples = [] + for line in examples_text.split('\n'): + line = line.strip() + if line.startswith('- '): + # Remove entity annotations for counting + example = line[2:].strip() + examples.append(example) + return examples + + def _normalize_examples(self, examples: List[str]) -> List[str]: + """Normalize examples for comparison (remove entity annotations)""" + normalized = [] + for ex in examples: + # Remove entity annotations [text](type) + clean = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', ex) + clean = clean.lower().strip() + normalized.append(clean) + return normalized + + def _count_similar_examples(self, examples: List[str]) -> int: + """Count potentially similar examples""" + # Simple heuristic: count examples that start with same 2 words + normalized = self._normalize_examples(examples) + prefixes = [] + + for ex in normalized: + words = ex.split() + if len(words) >= 2: + prefix = ' '.join(words[:2]) + prefixes.append(prefix) + + # Count duplicates in prefixes + prefix_counts = Counter(prefixes) + similar = sum(count - 1 for count in prefix_counts.values() if count > 1) + return similar + + def _calculate_intent_similarity(self, examples1: set, examples2: set) -> float: + """Calculate similarity between two sets of examples""" + if not examples1 or not examples2: + return 0.0 + + # Word-level Jaccard similarity + words1 = set() + words2 = set() + + for ex in examples1: + words1.update(ex.split()) + for ex in examples2: + words2.update(ex.split()) + + intersection = words1 & words2 + union = words1 | words2 + + if not union: + return 0.0 + + return len(intersection) / len(union) + + def _generate_report(self) -> Dict: + """Generate validation report""" + return { + 'stats': self.stats, + 'warnings': self.warnings, + 'errors': self.errors + } + + def print_report(self, report: Dict): + """Print beautiful report""" + stats = report['stats'] + warnings = report['warnings'] + errors = report['errors'] + + print(f"\n{'='*70}") + print("📊 VALIDATION REPORT") + print(f"{'='*70}\n") + + # Stats + if stats: + print("📈 STATISTICS:") + print(f" • Total Intents: {stats.get('total_intents', 0)}") + print(f" • Total Examples: {stats.get('total_examples', 0)}") + + if stats.get('total_intents', 0) > 0: + avg = stats.get('total_examples', 0) / stats.get('total_intents', 1) + print(f" • Average Examples per Intent: {avg:.1f}") + + if stats.get('entity_counts'): + print(f"\n Entities Found:") + for entity, count in sorted(stats['entity_counts'].items()): + print(f" - {entity}: {count} occurrences") + + if stats.get('intent_examples'): + print(f"\n Examples per Intent:") + for intent, examples in sorted(stats['intent_examples'].items()): + print(f" - {intent}: {len(examples)} examples") + + # Errors + if errors: + print(f"\n{'='*70}") + print(f"❌ ERRORS ({len(errors)}):") + print(f"{'='*70}") + for error in errors: + print(f" {error}") + + # Warnings + if warnings: + print(f"\n{'='*70}") + print(f"⚠️ WARNINGS ({len(warnings)}):") + print(f"{'='*70}") + for warning in warnings: + print(f" {warning}") + + # Summary + print(f"\n{'='*70}") + if not errors and not warnings: + print("✅ ALL CHECKS PASSED! Training data looks good.") + elif errors: + print(f"❌ FAILED: {len(errors)} error(s) found. Please fix before training.") + else: + print(f"⚠️ PASSED WITH WARNINGS: {len(warnings)} warning(s).") + print(" Consider addressing warnings for better quality.") + print(f"{'='*70}\n") + + +def main(): + """Main function""" + if len(sys.argv) < 2: + print("Usage: python validate_training_data.py ") + print("\nExample:") + print(" python validate_training_data.py data/nlu.yml") + sys.exit(1) + + file_path = sys.argv[1] + + if not Path(file_path).exists(): + print(f"❌ Error: File '{file_path}' not found") + sys.exit(1) + + validator = TrainingDataValidator() + report = validator.validate_file(file_path) + validator.print_report(report) + + # Exit code + if report['errors']: + sys.exit(1) # Fail with errors + else: + sys.exit(0) # Success + + +if __name__ == '__main__': + main() diff --git a/training_templates/QUICK_REFERENCE.md b/training_templates/QUICK_REFERENCE.md new file mode 100644 index 000000000000..be1c60f6b632 --- /dev/null +++ b/training_templates/QUICK_REFERENCE.md @@ -0,0 +1,289 @@ +# Training Data Quick Reference + +## 📋 Tóm Tắt Nhanh + +### Cấu Trúc File + +```yaml +version: "3.1" + +nlu: # Dạy bot hiểu ngôn ngữ + - intent: tên_intent + examples: | + - câu ví dụ 1 + - câu với [entity](entity_type) + +stories: # Dạy bot hội thoại + - story: tên story + steps: + - intent: user_intent + - action: bot_action + +rules: # Quy tắc cố định + - rule: tên rule + steps: + - intent: user_intent + - action: bot_action +``` + +--- + +## 🎯 NLU Syntax + +### Basic Intent +```yaml +- intent: greet + examples: | + - xin chào + - hello + - hi +``` + +### Intent with Entity +```yaml +- intent: search_product + examples: | + - tìm [laptop](product_type) + - [laptop](product_type) [ASUS](brand) dưới [20 triệu](price) +``` + +### Synonym +```yaml +- synonym: laptop + examples: | + - laptop + - máy tính + - notebook +``` + +### Lookup Table +```yaml +- lookup: brands + examples: | + - Dell + - HP + - ASUS +``` + +### Regex +```yaml +- regex: phone_number + examples: | + - \d{10} + - \d{3}[-.\s]\d{3}[-.\s]\d{4} +``` + +--- + +## 📖 Stories Syntax + +### Basic Story +```yaml +- story: simple flow + steps: + - intent: greet + - action: utter_greet + - intent: goodbye + - action: utter_goodbye +``` + +### Story with Entities +```yaml +- story: search flow + steps: + - intent: search_product + entities: + - product_type: "laptop" + - slot_was_set: + - product_type: "laptop" + - action: action_search_product +``` + +### Story with OR +```yaml +- story: user confirms or denies + steps: + - action: utter_ask_confirm + - or: + - intent: affirm + - intent: deny + - action: action_handle_response +``` + +### Story with Checkpoint +```yaml +- story: greet user + steps: + - intent: greet + - action: utter_greet + - checkpoint: after_greet + +- story: greet then search + steps: + - checkpoint: after_greet + - intent: search_product + - action: action_search_product +``` + +--- + +## ⚖️ Rules Syntax + +### Simple Rule +```yaml +- rule: say goodbye + steps: + - intent: goodbye + - action: utter_goodbye +``` + +### Rule with Condition +```yaml +- rule: greet only once + condition: + - slot_was_set: + - user_greeted: false + steps: + - intent: greet + - action: utter_greet +``` + +### Form Activation +```yaml +- rule: activate form + steps: + - intent: book_flight + - action: booking_form + - active_loop: booking_form +``` + +--- + +## 💡 Best Practices Cheat Sheet + +### ✅ DO + +```yaml +# ✅ Đa dạng, tự nhiên +- intent: search_product + examples: | + - tìm laptop + - cho tôi xem máy tính + - có laptop nào không + - laptop gaming dưới 20 triệu + - tôi cần mua laptop ASUS +``` + +### ❌ DON'T + +```yaml +# ❌ Giống nhau quá +- intent: search_product + examples: | + - tìm laptop Dell + - tìm laptop HP + - tìm laptop ASUS + - tìm laptop MSI +``` + +--- + +## 📊 Số Lượng Examples + +| Intent Type | Min | Khuyến Nghị | +|-------------|-----|-------------| +| Đơn giản | 10-15 | 20-30 | +| Trung bình | 20-30 | 50-100 | +| Phức tạp | 30-50 | 100-200 | + +--- + +## 🔧 Commands Thường Dùng + +```bash +# Validate data +rasa data validate + +# Train +rasa train + +# Test NLU +rasa test nlu --nlu data/nlu.yml + +# Interactive learning +rasa interactive + +# Shell +rasa shell +rasa shell --debug +rasa shell nlu +``` + +--- + +## 🎨 Entity Annotation Format + +``` +[giá trị](tên_entity) + +Examples: +- tìm [laptop](product_type) +- [Dell R740](product_name) giá bao nhiêu +- dưới [20 triệu](price_range) +``` + +--- + +## 🚀 Quick Start Template + +```yaml +version: "3.1" + +nlu: + - intent: greet + examples: | + - xin chào + - hello + + - intent: search_product + examples: | + - tìm [laptop](product_type) + - [laptop](product_type) [Dell](brand) + +stories: + - story: basic flow + steps: + - intent: greet + - action: utter_greet + - intent: search_product + - action: action_search_product + +rules: + - rule: say goodbye + steps: + - intent: goodbye + - action: utter_goodbye +``` + +--- + +## 🔍 Common Errors + +| Error | Cause | Fix | +|-------|-------|-----| +| Intent not found | Intent trong story không có trong NLU | Thêm intent vào nlu.yml | +| Entity not recognized | Entity không được define | Thêm vào domain.yml | +| Low accuracy | Thiếu training data | Thêm examples | +| Overfitting | Examples quá giống nhau | Đa dạng hóa | + +--- + +## 📝 Template Checklist + +- [ ] Mỗi intent ≥ 20 examples +- [ ] Examples đa dạng (ngắn, dài, typo...) +- [ ] Entities được annotate đầy đủ +- [ ] Stories cover main flows +- [ ] Rules dùng đúng chỗ +- [ ] `rasa data validate` pass +- [ ] Test accuracy > 85% diff --git a/training_templates/README.md b/training_templates/README.md new file mode 100644 index 000000000000..03980fca1a39 --- /dev/null +++ b/training_templates/README.md @@ -0,0 +1,224 @@ +# Training Data Templates + +Templates sẵn sàng để bắt đầu project Rasa chatbot nhanh chóng. + +## 📁 Files + +### 1. ecommerce_nlu_template.yml + +Template NLU data cho chatbot e-commerce/bán hàng. + +**Bao gồm 20+ intents:** +- Greetings (greet, goodbye, thank...) +- Product search (search_product, browse_category) +- Product info (ask_price, ask_specs, ask_stock, ask_warranty...) +- Comparison (compare_products, recommend_product) +- Shopping cart (add_to_cart, view_cart, checkout...) +- Order tracking (track_order, cancel_order...) +- Support (technical_support, contact_agent...) + +**Entities:** +- product_type, product_name, brand +- price_range, quantity +- use_case, specification +- order_id + +**Total:** 200+ training examples + +### 2. ecommerce_stories_template.yml + +Template stories cho e-commerce flows. + +**Bao gồm 30+ stories:** +- Basic flows (greet → search → goodbye) +- Product discovery (search → ask specs → compare) +- Purchase flows (search → add to cart → checkout) +- Information queries (price, stock, warranty...) +- Order tracking +- Error handling + +### 3. QUICK_REFERENCE.md + +Cheat sheet tra cứu nhanh syntax Rasa. + +**Nội dung:** +- NLU syntax (intent, entity, synonym, lookup, regex) +- Stories syntax (basic, with entities, OR, checkpoint) +- Rules syntax +- Best practices +- Common commands +- Common errors + +## 🚀 Cách Sử Dụng + +### Option 1: Copy Template + +```bash +# Copy NLU template +cp training_templates/ecommerce_nlu_template.yml data/nlu.yml + +# Copy stories template +cp training_templates/ecommerce_stories_template.yml data/stories.yml + +# Edit theo nhu cầu của bạn +``` + +### Option 2: Tham Khảo + +```bash +# Xem template để học cách viết +cat training_templates/ecommerce_nlu_template.yml + +# Copy từng phần cần thiết +``` + +### Option 3: Customize + +```bash +# Tạo file mới dựa trên template +cp training_templates/ecommerce_nlu_template.yml my_custom_nlu.yml + +# Sửa đổi: +# 1. Xóa intents không cần +# 2. Thêm intents mới +# 3. Thêm examples +# 4. Thêm entities +``` + +## 🎯 Use Cases + +### E-Commerce / Bán Hàng + +**File:** `ecommerce_nlu_template.yml`, `ecommerce_stories_template.yml` + +**Phù hợp cho:** +- Shop online (điện tử, thời trang, thực phẩm...) +- Showroom (ô tô, điện thoại, máy tính...) +- B2B sales (thiết bị công nghiệp, phần mềm...) + +**Tính năng:** +- Tìm sản phẩm theo filter (giá, brand, specs...) +- So sánh sản phẩm +- Giỏ hàng & checkout +- Tracking đơn hàng + +### Customer Support + +**Tạo từ template:** + +```yaml +nlu: + - intent: report_issue + examples: | + - sản phẩm bị lỗi + - [laptop](device) không khởi động + - [máy in](device) bị [kẹt giấy](issue) + + - intent: ask_solution + examples: | + - làm thế nào để sửa + - cách khắc phục +``` + +### Booking / Reservation + +**Tạo từ template:** + +```yaml +nlu: + - intent: book_appointment + examples: | + - đặt lịch hẹn + - book appointment [ngày mai](date) + - đặt chỗ lúc [3 giờ chiều](time) +``` + +## 📝 Customization Guide + +### 1. Thêm Intent Mới + +```yaml +# Thêm vào file nlu.yml +nlu: + - intent: your_new_intent + examples: | + - example 1 + - example 2 + - example với [entity](entity_type) +``` + +### 2. Thêm Entity + +```yaml +# Thêm lookup table +nlu: + - lookup: your_entity + examples: | + - value 1 + - value 2 +``` + +### 3. Thêm Story + +```yaml +# Thêm vào stories.yml +stories: + - story: your story name + steps: + - intent: user_intent + - action: bot_action +``` + +## 🔧 Validation + +Sau khi customize, validate data: + +```bash +# Validate bằng tool +python tools/validate_training_data.py data/nlu.yml + +# Validate bằng Rasa +rasa data validate +``` + +## 💡 Tips + +### Khi Bắt Đầu Project Mới + +1. **Copy template phù hợp** +2. **Xóa intents không cần** +3. **Customize entities cho domain của bạn** +4. **Thêm examples thật từ users** +5. **Train và test** + +### Khi Mở Rộng Project + +1. **Giữ nguyên template làm reference** +2. **Thêm intents mới vào file riêng** +3. **Merge khi đã test kỹ** + +### Best Practices + +- ✅ Mỗi intent ≥ 20 examples +- ✅ Examples đa dạng +- ✅ Test thường xuyên +- ✅ Version control (git) + +## 📚 Resources + +- **Hướng dẫn chi tiết:** `TRAINING_DATA_GUIDE_VI.md` +- **Quick reference:** `QUICK_REFERENCE.md` +- **Tools:** `tools/` folder +- **Examples:** `examples/it_store_bot/` + +## 🎓 Learning Path + +1. Đọc `QUICK_REFERENCE.md` (15 phút) +2. Xem `ecommerce_nlu_template.yml` (30 phút) +3. Đọc `TRAINING_DATA_GUIDE_VI.md` (2 giờ) +4. Thực hành với template (4 giờ) +5. Build chatbot riêng (∞) + +--- + +**Happy training!** 🚀 diff --git a/training_templates/ecommerce_nlu_template.yml b/training_templates/ecommerce_nlu_template.yml new file mode 100644 index 000000000000..89a1851ec645 --- /dev/null +++ b/training_templates/ecommerce_nlu_template.yml @@ -0,0 +1,374 @@ +version: "3.1" + +# ======================================== +# TEMPLATE: E-Commerce Chatbot NLU Data +# Use Case: Bán hàng online (sản phẩm công nghệ) +# ======================================== + +nlu: + # ============ GREETINGS & PLEASANTRIES ============ + + - intent: greet + examples: | + - xin chào + - chào bạn + - hello + - hi + - chào buổi sáng + - chào buổi chiều + - chào buổi tối + - hey + - hế lô + - alo + + - intent: goodbye + examples: | + - tạm biệt + - bye + - goodbye + - hẹn gặp lại + - tạm biệt nhé + - bye bye + - thôi tôi đi đây + - ok tạm biệt + + - intent: thank + examples: | + - cảm ơn + - cảm ơn bạn + - thanks + - thank you + - cảm ơn nhiều + - cảm ơn nhé + - thanks a lot + - cảm ơn bạn nhiều + + - intent: affirm + examples: | + - đúng + - đúng rồi + - ok + - được + - đồng ý + - yes + - yeah + - vâng + - ừ + - okie + + - intent: deny + examples: | + - không + - không phải + - no + - không đúng + - sai rồi + - thôi + - không cần + + # ============ PRODUCT SEARCH ============ + + - intent: search_product + examples: | + - tìm [laptop](product_type) + - tìm [máy tính](product_type) + - cho tôi xem [laptop](product_type) + - có [laptop](product_type) nào không + - tôi muốn mua [laptop](product_type) + - [laptop](product_type) gaming + - tìm [laptop](product_type) [ASUS](brand) + - [laptop](product_type) [Dell](brand) có không + - cho xem [máy chủ](product_type) + - tìm [server](product_type) [HP](brand) + - [camera](product_type) an ninh + - tìm [switch](product_type) mạng + - [phần mềm](product_type) [Windows](product_name) + - tìm [laptop](product_type) dưới [20 triệu](price_range) + - [laptop](product_type) giá [từ 15 đến 25 triệu](price_range) + - tìm [laptop](product_type) cho [sinh viên](use_case) + - [máy tính](product_type) cho [văn phòng](use_case) + - [laptop](product_type) [chơi game](use_case) + - tìm [máy chủ](product_type) cho [doanh nghiệp](use_case) + + - intent: browse_category + examples: | + - xem danh mục + - có những loại sản phẩm gì + - categories + - cho tôi xem tất cả sản phẩm + - sản phẩm nào có + - bán gì + - xem [laptop](product_type) + - danh sách [máy chủ](product_type) + + # ============ PRODUCT INFORMATION ============ + + - intent: ask_price + examples: | + - giá bao nhiêu + - bao nhiêu tiền + - giá + - giá cả + - [laptop](product_type) này giá bao nhiêu + - giá [Dell R740](product_name) + - hỏi giá [máy chủ](product_type) + - giá thành sản phẩm + - giá bán + - giá bao nhiêu vậy + - giá bn + - bao nhiu + - mấy tiền + + - intent: ask_specifications + examples: | + - thông số kỹ thuật + - cấu hình + - specs + - chi tiết sản phẩm + - [laptop](product_type) này cấu hình gì + - [máy chủ](product_type) có bao nhiêu RAM + - thông tin kỹ thuật + - [camera](product_type) độ phân giải bao nhiêu + - [switch](product_type) có mấy port + - CPU gì + - RAM bao nhiêu + - dùng ổ cứng gì + + - intent: ask_stock + examples: | + - còn hàng không + - có sẵn không + - còn không + - hết hàng chưa + - khi nào có hàng + - [laptop](product_type) này còn không + - kiểm tra tồn kho + - có sẵn hàng không + - còn bán không + + - intent: ask_warranty + examples: | + - bảo hành bao lâu + - chế độ bảo hành + - warranty + - thời gian bảo hành + - [laptop](product_type) bảo hành thế nào + - chính sách bảo hành + - bảo hành như thế nào + - bảo hành mấy tháng + + - intent: ask_promotion + examples: | + - có khuyến mãi không + - chương trình giảm giá + - promotion + - ưu đãi + - deal + - giảm giá không + - có sale không + - khuyến mãi gì + - khuyến mãi tháng này + + # ============ PRODUCT COMPARISON ============ + + - intent: compare_products + examples: | + - so sánh [Dell R740](product_name) và [HP DL380](product_name) + - so sánh 2 [laptop](product_type) này + - khác nhau gì + - khác biệt gì giữa [ASUS ROG](product_name) và [MSI](brand) + - [Dell](brand) tốt hơn [HP](brand) không + - so sánh [laptop](product_type) [Dell](brand) với [HP](brand) + - nên chọn cái nào + - sản phẩm nào tốt hơn + - compare [server](product_type) + + - intent: recommend_product + examples: | + - tư vấn [laptop](product_type) + - gợi ý sản phẩm + - nên mua gì + - recommend + - [laptop](product_type) nào tốt + - tư vấn cho tôi + - giúp tôi chọn [laptop](product_type) + - [laptop](product_type) cho [sinh viên](use_case) + - tư vấn [máy chủ](product_type) cho [doanh nghiệp nhỏ](use_case) + + # ============ SHOPPING CART ============ + + - intent: add_to_cart + examples: | + - thêm vào giỏ + - cho vào giỏ hàng + - add to cart + - tôi lấy cái này + - mua cái này + - đặt [2](quantity) cái + - thêm [3](quantity) [laptop](product_type) + - lấy [1](quantity) [Dell R740](product_name) + + - intent: view_cart + examples: | + - xem giỏ hàng + - giỏ hàng của tôi + - xem cart + - tôi đặt gì rồi + - kiểm tra giỏ hàng + + - intent: remove_from_cart + examples: | + - xóa khỏi giỏ + - bỏ ra + - remove + - không lấy cái này + - xóa [laptop](product_type) + + - intent: checkout + examples: | + - thanh toán + - checkout + - đặt hàng + - order + - tôi muốn đặt hàng + - tiến hành thanh toán + - mua hàng + + # ============ ORDER & DELIVERY ============ + + - intent: track_order + examples: | + - kiểm tra đơn hàng + - đơn hàng của tôi + - track order + - đơn hàng [#12345](order_id) đâu rồi + - kiểm tra đơn [#12345](order_id) + - order đã giao chưa + + - intent: ask_delivery + examples: | + - giao hàng mất bao lâu + - ship bao lâu + - thời gian giao hàng + - phí vận chuyển + - có giao hàng miễn phí không + - ship hàng thế nào + - giao hàng như thế nào + + - intent: cancel_order + examples: | + - hủy đơn hàng + - cancel order + - tôi muốn hủy đơn + - hủy đơn [#12345](order_id) + - không đặt nữa + + # ============ CUSTOMER SUPPORT ============ + + - intent: technical_support + examples: | + - hỗ trợ kỹ thuật + - support + - cần hỗ trợ + - help + - hướng dẫn cài đặt + - cách sử dụng + - không hoạt động + - bị lỗi + + - intent: contact_agent + examples: | + - nói chuyện với người thật + - tôi muốn gặp nhân viên + - chuyển cho nhân viên + - talk to human + - live chat + + - intent: complaint + examples: | + - khiếu nại + - complaint + - sản phẩm bị lỗi + - tôi không hài lòng + - dịch vụ kém + + # ============ OUT OF SCOPE ============ + + - intent: out_of_scope + examples: | + - thời tiết hôm nay + - bạn tên gì + - bạn là ai + - kể chuyện cười + - hát bài hát + - đặt vé máy bay + - nhà hàng gần đây + + # ============ ENTITIES ============ + + # Synonyms + - synonym: laptop + examples: | + - laptop + - máy tính + - máy tính xách tay + - notebook + - pc xách tay + + - synonym: máy chủ + examples: | + - máy chủ + - server + - may chu + - máy chủ server + + - synonym: camera + examples: | + - camera + - cam + - camera an ninh + - camera giám sát + + # Lookup Tables + - lookup: brands + examples: | + - Dell + - HP + - Lenovo + - ASUS + - MSI + - Cisco + - HPE + - Hikvision + - Dahua + - Microsoft + + - lookup: product_types + examples: | + - laptop + - máy tính + - máy chủ + - server + - switch + - switch mạng + - camera + - camera an ninh + - phần mềm + - software + + # Regex + - regex: order_id + examples: | + - \#\d{5,8} + - ORDER-\d{6} + - ORD\d{4,6} + + - regex: price_pattern + examples: | + - \d+\s?(triệu|tr|trieu) + - \d+\s?(ngàn|k|ngan) + - \d+\s?(đồng|dong|vnd) + + - regex: quantity_pattern + examples: | + - \d+\s?(cái|chiếc|con|bộ) diff --git a/training_templates/ecommerce_stories_template.yml b/training_templates/ecommerce_stories_template.yml new file mode 100644 index 000000000000..bd47b87d9a9c --- /dev/null +++ b/training_templates/ecommerce_stories_template.yml @@ -0,0 +1,333 @@ +version: "3.1" + +# ======================================== +# TEMPLATE: E-Commerce Stories +# Common conversation flows +# ======================================== + +stories: + + # ============ BASIC FLOWS ============ + + - story: greet and search product + steps: + - intent: greet + - action: utter_greet + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + + - story: direct search without greeting + steps: + - intent: search_product + entities: + - product_type: "laptop" + - brand: "Dell" + - action: action_search_product + + - story: browse category then select + steps: + - intent: browse_category + - action: action_show_categories + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + + # ============ PRODUCT DISCOVERY ============ + + - story: search with price filter + steps: + - intent: search_product + entities: + - product_type: "laptop" + - price_range: "20 triệu" + - slot_was_set: + - product_type: "laptop" + - price_range: "20 triệu" + - action: action_search_product + - intent: ask_specifications + - action: action_show_specifications + + - story: search by use case + steps: + - intent: search_product + entities: + - product_type: "laptop" + - use_case: "gaming" + - action: action_search_product + - intent: ask_price + - action: action_show_price + + - story: recommendation flow + steps: + - intent: recommend_product + entities: + - product_type: "laptop" + - use_case: "sinh viên" + - action: action_recommend_product + - intent: affirm + - action: utter_ask_add_to_cart + - intent: affirm + - action: action_add_to_cart + + # ============ PRODUCT COMPARISON ============ + + - story: compare then choose + steps: + - intent: compare_products + entities: + - product_type: "laptop" + - action: action_compare_products + - intent: search_product + entities: + - product_name: "Dell Latitude" + - action: action_show_product_details + - intent: add_to_cart + - action: action_add_to_cart + + - story: ask specs then compare + steps: + - intent: search_product + entities: + - product_type: "server" + - action: action_search_product + - intent: ask_specifications + - action: action_show_specifications + - intent: compare_products + - action: action_compare_products + + # ============ PURCHASE FLOW ============ + + - story: complete purchase flow + steps: + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + - intent: add_to_cart + entities: + - quantity: "1" + - action: action_add_to_cart + - action: utter_ask_continue_shopping + - intent: deny + - action: utter_ask_checkout + - intent: affirm + - action: checkout_form + - active_loop: checkout_form + - active_loop: null + - action: action_process_checkout + + - story: add multiple items + steps: + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + - intent: add_to_cart + - action: action_add_to_cart + - action: utter_ask_continue_shopping + - intent: affirm + - intent: search_product + entities: + - product_type: "chuột" + - action: action_search_product + - intent: add_to_cart + - action: action_add_to_cart + - intent: checkout + - action: checkout_form + + - story: view cart and modify + steps: + - intent: view_cart + - action: action_show_cart + - intent: remove_from_cart + entities: + - product_name: "laptop Dell" + - action: action_remove_from_cart + - intent: checkout + - action: checkout_form + + # ============ INFORMATION QUERIES ============ + + - story: check stock before buying + steps: + - intent: search_product + entities: + - product_name: "ASUS ROG" + - action: action_search_product + - intent: ask_stock + - action: action_check_stock + - intent: ask_price + - action: action_show_price + - intent: add_to_cart + - action: action_add_to_cart + + - story: ask warranty and promotion + steps: + - intent: search_product + - action: action_search_product + - intent: ask_warranty + - action: action_show_warranty + - intent: ask_promotion + - action: action_show_promotions + - intent: affirm + - action: action_add_to_cart + + - story: price comparison + steps: + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + - intent: ask_price + - action: action_show_price + - intent: search_product + entities: + - brand: "HP" + - action: action_search_product + - intent: ask_price + - action: action_show_price + + # ============ ORDER TRACKING ============ + + - story: track existing order + steps: + - intent: track_order + entities: + - order_id: "#12345" + - action: action_track_order + - intent: ask_delivery + - action: action_show_delivery_info + + - story: cancel order + steps: + - intent: cancel_order + entities: + - order_id: "#12345" + - action: utter_ask_cancel_confirmation + - intent: affirm + - action: action_cancel_order + - action: utter_order_cancelled + + # ============ CUSTOMER SUPPORT ============ + + - story: technical support request + steps: + - intent: technical_support + - action: action_provide_support_options + - intent: contact_agent + - action: action_transfer_to_agent + + - story: complaint handling + steps: + - intent: complaint + - action: utter_apologize + - action: action_create_ticket + - action: utter_ticket_created + + # ============ ERROR HANDLING ============ + + - story: out of stock alternative + steps: + - intent: search_product + - action: action_search_product + - intent: add_to_cart + - action: action_check_stock + - slot_was_set: + - stock_available: false + - action: utter_out_of_stock + - action: action_suggest_alternatives + + - story: handle unclear request + steps: + - intent: search_product + - action: action_search_product + - slot_was_set: + - products_found: 0 + - action: utter_no_products_found + - action: utter_ask_rephrase + - intent: search_product + entities: + - product_type: "laptop" + - action: action_search_product + + # ============ MULTI-TURN CONVERSATIONS ============ + + - story: detailed product inquiry + steps: + - intent: search_product + entities: + - product_type: "máy chủ" + - action: action_search_product + - intent: ask_specifications + - action: action_show_specifications + - intent: ask_price + - action: action_show_price + - intent: ask_warranty + - action: action_show_warranty + - intent: ask_promotion + - action: action_show_promotions + - intent: ask_stock + - action: action_check_stock + - intent: affirm + - action: action_add_to_cart + + - story: from recommendation to purchase + steps: + - intent: recommend_product + entities: + - use_case: "doanh nghiệp" + - product_type: "máy chủ" + - action: action_recommend_product + - intent: compare_products + - action: action_compare_products + - intent: ask_price + - action: action_show_price + - intent: add_to_cart + entities: + - product_name: "Dell R740" + - quantity: "2" + - action: action_add_to_cart + - intent: checkout + - action: checkout_form + + # ============ EDGE CASES ============ + + - story: change mind during checkout + steps: + - intent: checkout + - action: checkout_form + - active_loop: checkout_form + - intent: deny + - action: action_deactivate + - active_loop: null + - action: utter_checkout_cancelled + + - story: ask delivery during search + steps: + - intent: search_product + - action: action_search_product + - intent: ask_delivery + - action: action_show_delivery_info + - intent: add_to_cart + - action: action_add_to_cart + + # ============ GOODBYE ============ + + - story: thank and goodbye + steps: + - intent: thank + - action: utter_thank + - intent: goodbye + - action: utter_goodbye + + - story: goodbye after purchase + steps: + - action: action_process_checkout + - action: utter_order_confirmation + - intent: thank + - action: utter_thank + - intent: goodbye + - action: utter_goodbye