# Tài Liệu Kỹ Thuật: Cơ Chế Lọc Bảng TKB Profile-Based trong Text2SQL

Cơ chế lọc bảng **TKB Profile-Based** là giải pháp tối ưu hóa deterministic (quy tắc cứng) được thiết kế riêng cho cơ sở dữ liệu Thời khóa biểu (TKB) chứa 56 bảng. Thay vì sử dụng LLM để đọc và lọc schema (vừa chậm, tốn chi phí, vừa dễ thiếu các bảng liên kết/cầu nối), hệ thống sẽ phân tích trực tiếp câu hỏi tiếng Việt của người dùng để rút ra tập bảng tối ưu.

Toàn bộ logic xử lý của cơ chế này nằm trong lớp [SchemaSelectionService](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L87-L458) thuộc file [schemaSelectionService.js](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js).

---

## 1. Sơ Đồ Luồng Xử Lý (Workflow Diagram)

```mermaid
graph TD
    A[Nhận câu hỏi từ người dùng] --> B[Chuẩn hóa văn bản <br>normalizeText]
    B --> C[Phân tích cờ từ khóa <br>Boolean Flags]
    C --> D[Nhận diện chủ đề câu hỏi <br>_detectTkbProfile]
    
    D --> E[Lấy danh sách bảng cơ sở <br>TKB_PROFILES]
    
    E --> F{Kiểm tra điều kiện động <br>Conditional Rules}
    F -->|Có từ khóa phòng ốc| G[Bổ sung tbPhongHoc, tbLoaiPhong, tbTKBChiTiet]
    F -->|Có từ khóa lớp/giảng dạy| H[Bổ sung tbLopHoc, tbPhanNam]
    F -->|Có chương trình khung| I[Bổ sung tbCTKhung]
    F -->|Có kiểu xếp TKB| J[Bổ sung tbKieuXepTKB]
    
    G & H & I & J & E --> K[Hợp nhất danh sách bảng]
    K --> L[Lọc bỏ bảng không tồn tại trong DB]
    L --> M[Kết quả: Tập bảng rút gọn bàn giao cho AI sinh SQL]
```

---

## 2. Các Bước Thực Thi Chi Tiết

### Bước 1: Chuẩn Hóa Văn Bản (Text Normalization)

Hàm [normalizeText(value)](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L57-L68) thực hiện các thao tác tiền xử lý câu hỏi:
1. Tách các cụm CamelCase (ví dụ: `tbCanBo` thành `tb Can Bo`).
2. Thay thế dấu gạch dưới `_` bằng khoảng trắng.
3. Chuyển đổi ký tự Unicode có dấu thành không dấu (NFD normalization) để xử lý tiếng Việt không dấu.
4. Chuyển đổi chữ đ, Đ thành d, D.
5. Chuyển toàn bộ chuỗi về chữ thường (lowercase).
6. Loại bỏ toàn bộ các ký tự không phải chữ cái và chữ số (thay bằng khoảng trắng).

> **Ví dụ:** 
> * Gốc: *"Giảng viên Nguyễn Văn A dạy phòng máy nào vào ngày 06/06?"*
> * Sau chuẩn hóa: `"giang vien nguyen van a day phong may nao vao ngay 06 06"`

---

### Bước 2: Nhận Diện Cờ Từ Khóa (Boolean Flags)

Dựa trên câu hỏi đã được chuẩn hóa, hệ thống quét qua các từ khóa đặc trưng thông qua hàm so khớp [matchesPattern](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L76-L81) để xác lập các cờ trạng thái:

* **`hasClass`**: Câu hỏi chứa cụm từ `'lop'` hoặc `'lop hoc'`.
* **`hasTeacher`**: Câu hỏi chứa các từ chỉ giảng viên (`'giang vien'`, `'giao vien'`, `'thay'`, `'co giao'`, `'day'`, `'giang day'`, `'len lop'`).
* **`hasSubject`**: Câu hỏi chứa các từ chỉ môn học (`'mon hoc'`, `'hoc phan'`, `'tin chi'`, `'so tiet'`, `'csdl'`, `'qtkd'`, `'nhom mon'`, `'mon chu tri'`).
* **`hasDateOrSchedule`**: Câu hỏi hỏi về thời gian/lịch trình (`'ngay'`, `'tu ngay'`, `'den ngay'`, `'thu may'`, `'trong tuan'`, `'lich hoc'`, `'lich day'`, `'lich thi'`, `'tkb'`, `'ca hoc'`, `'khung gio'`, `'khi nao'`...).
* **`hasLesson`**: Câu hỏi chứa từ khóa bài học (`'bai hoc'`, `'bai giang'`, `'noi dung bai'`, `'noi dung chuong'`).
* **`hasRoomTerm`**: Câu hỏi chứa từ khóa phòng ốc (`'phong hoc'`, `'loai phong'`, `'phong may'`, `'suc chua'`, `'toa nha'`, `'giang duong'`, `'so luong sinh vien'`...).
* **`hasUnitWord`**: Câu hỏi chứa từ chỉ khoa hoặc bộ môn (`'khoa'`, `'don vi'`, `'bo mon'`).
* **`hasAssignmentVerb`**: Câu hỏi chứa hành động phân công giảng dạy (`'phan cong'`, `'giang day'`, `'day'`, `'len lop'`, `'phu trach'`).

---

### Bước 3: Phân Loại Profile Nghiệp Vụ (`_detectTkbProfile`)

Hàm [_detectTkbProfile(question)](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L322-L355) áp dụng cây quyết định theo thứ tự ưu tiên giảm dần:

| Thứ tự | Điều kiện kiểm tra | Cụm nghiệp vụ trả về (Profile) |
| :---: | :--- | :--- |
| 1 | Chứa cụm từ `'phong ban'`, `'truong pho phong'` | `people_unit` |
| 2 | Chứa cụm từ `'kieu xep'`, `'kieu thiet lap'`, `'xep tkb'` | `subject_program` |
| 3 | Chứa cụm từ `'khoa hoc'`, `'khoa dao tao'`, `'nien khoa'` | `class_training` |
| 4 | Chứa cụm từ `'chuong trinh dao tao khung'` | `subject_program` |
| 5 | Chứa cụm từ `'bo mon'` **VÀ** có từ chỉ đơn vị (`hasUnitWord`) | `subject_program` |
| 6 | Có cờ bài học (`hasLesson`):<br>- Nếu có cờ thời gian (`hasDateOrSchedule`) <br>- Nếu không có cờ thời gian | <br>- `schedule_room`<br>- `lesson` |
| 7 | Có cờ phòng học (`hasRoomTerm`) **VÀ** có cờ thời gian/lớp/môn/giáo viên | `schedule_room` |
| 8 | Có cờ thời gian/lịch trình (`hasDateOrSchedule`) | `schedule_room` |
| 9 | Hỏi kết hợp giữa: (Lớp **VÀ** Môn) hoặc (Giáo viên **VÀ** Môn) | `assignment` |
| 10 | Hỏi về danh sách môn học của lớp | `assignment` |
| 11 | Hỏi về đơn vị/khoa (`hasUnitWord`) kết hợp môn học/phân công:<br>- Nếu có nhắc tới giáo viên (`hasTeacher`) <br>- Nếu không nhắc tới giáo viên | <br>- `assignment`<br>- `subject_program` |
| 12 | Có từ chỉ đơn vị (`hasUnitWord`) **VÀ** có cờ lớp học (`hasClass`) | `class_training` |
| 13 | Chỉ có từ chỉ đơn vị (`hasUnitWord`) | `people_unit` |
| 14 | Quét qua bộ quy tắc tĩnh bổ trợ [TKB_PROFILE_RULES](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L47-L55) | Nhóm tương ứng |
| 15 | Không khớp bất kỳ điều kiện nào (Mặc định) | `core` |

---

### Bước 4: Lấy Danh Sách Bảng Cơ Sở (`TKB_PROFILES`)

Sau khi xác định được Profile, hệ thống sẽ ánh xạ sang danh sách các bảng vật lý được định nghĩa tại [TKB_PROFILES](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L36-L45):

```javascript
const TKB_PROFILES = {
    // Chỉ lấy bảng cán bộ và đơn vị
    people_unit: ['tbCanBo', 'tbDonVi'],
    
    // Các bảng phục vụ quản lý lớp học, chương trình học, chuyên ngành
    class_training: ['tbLopHoc', 'tbKhoaHoc', 'tbHeDaoTao', 'tbCanBo', 'tbDonVi', 'tbCTKhung', 'tbKieuLop', 'tbNganhHoc', 'tbChuyenNganh', 'tbPhanNam', 'tbMonHoc', 'tbNamHoc'],
    
    // Các bảng phục vụ chương trình học, khối kiến thức môn học
    subject_program: ['tbMonHoc', 'tbCTKhung', 'tbDonVi', 'tbLoaiMonHoc', 'tbNhomMon', 'tbBaiHoc', 'tbLoaiKienThucTrongCTK', 'tbKieuXepTKB', 'tbLopHoc', 'tbPhanNam'],
    
    // Các bảng phục vụ phân công giảng dạy (bảng cầu nối tbPhanNam đóng vai trò chủ đạo)
    assignment: ['tbPhanNam', 'tbMonHoc', 'tbLopHoc', 'tbCanBo', 'tbDonVi', 'tbNamHoc', 'tbKhoaHoc', 'tbHeDaoTao', 'tbKieuXepTKB', 'tbTKBChiTiet', 'tbCTKhung', 'tbNhomMon'],
    
    // Các bảng phục vụ thời khóa biểu chi tiết, lịch học, lịch dạy, phòng học
    schedule_room: ['tbTKBChiTiet', 'tbThoiKhoaBieu', 'tbPhanNam', 'tbMonHoc', 'tbLopHoc', 'tbCanBo', 'tbDonVi', 'tbPhongHoc', 'tbLoaiPhong', 'tbToaNha', 'tbNamHoc', 'tbBaiHoc', 'tbKhoaHoc'],
    
    // Các bảng phục vụ thông tin phòng học, loại phòng, sức chứa, thiết bị
    room: ['tbPhongHoc', 'tbLoaiPhong', 'tbToaNha', 'tbTKBChiTiet', 'tbLopHoc', 'tbMonHoc', 'tbBaiHoc', 'tbCanBo', 'tbDonVi'],
    
    // Các bảng phục vụ bài học, bài giảng chi tiết
    lesson: ['tbBaiHoc', 'tbMonHoc', 'tbCanBo', 'tbDonVi', 'tbLoaiGio', 'tbTKBChiTiet'],
    
    // Nhóm bảng cốt lõi cơ bản nhất
    core: ['tbLopHoc', 'tbMonHoc', 'tbCanBo', 'tbDonVi', 'tbPhanNam', 'tbTKBChiTiet', 'tbNamHoc', 'tbThoiKhoaBieu']
};
```

---

### Bước 5: Luật Bổ Sung Bảng Động (Conditional Rules)

Để tránh trường hợp câu hỏi có tính chất lai (hỏi chủ đề này nhưng muốn lọc/điều kiện theo trường của bảng chủ đề khác), hệ thống áp dụng các quy tắc bổ sung động cuối hàm [_selectTkbProfileTables](file:///root/repo/AI_CODE/app/server/src/services/schemaSelectionService.js#L251-L320):

* **Bổ sung về Phòng ốc:**
  Nếu câu hỏi chứa từ khóa phòng (`hasRoomTerm` = true) $\rightarrow$ Thêm `tbPhongHoc`, `tbLoaiPhong`. Nếu không thuộc profile `lesson` $\rightarrow$ Thêm `tbTKBChiTiet`.
* **Bổ sung về Bài học & Phân công:**
  Nếu profile là `lesson` nhưng câu hỏi nhắc tới lớp, giáo viên, phân công hoặc hỏi *"khi nào"* $\rightarrow$ Thêm `tbLopHoc`, `tbPhanNam` (bảng liên kết).
* **Bổ sung Phân công cho Phòng học:**
  Nếu profile là `room` (hoặc câu hỏi có chứa từ khóa phòng) và đi kèm từ khóa phân công (`hasAssignmentTerm` = true) $\rightarrow$ Thêm `tbPhanNam`.
* **Bổ sung Giảng viên cho Môn học:**
  Nếu profile là `subject_program` nhưng câu hỏi chứa từ khóa giáo viên/cán bộ $\rightarrow$ Thêm `tbCanBo`.
* **Bổ sung Kiểu xếp:**
  Nếu profile thuộc `schedule_room` hoặc `lesson` và câu hỏi nhắc tới cách sắp xếp phòng/kiểu xếp $\rightarrow$ Thêm `tbKieuXepTKB`.
* **Bổ sung Chương trình khung:**
  Nếu profile là `schedule_room` hoặc `assignment` và câu hỏi nhắc tới chương trình khung/bắt buộc $\rightarrow$ Thêm `tbCTKhung`.
* **Bổ sung Mốc học kỳ:**
  Nếu câu hỏi liên quan đến lịch học/phân công và chứa các mốc thời gian của học kỳ (bắt đầu/kết thúc) $\rightarrow$ Thêm `tbThoiKhoaBieu` (chứa ngày hiệu lực của học kỳ).

---

## 3. Các Điểm Khác Biệt và Ưu Điểm của Cơ Chế Này

> [!IMPORTANT]
> 1. **Hoàn toàn Deterministic:** Cơ chế này không sử dụng LLM tại bước lọc bảng. Do đó, thời gian xử lý bước này gần như bằng 0ms và không tốn chi phí API.
> 2. **Giải quyết triệt để lỗi thiếu bảng liên kết (Bridge Tables):** Đối với các CSDL lớn như TKB, LLM rất hay quên đưa các bảng trung gian như `tbPhanNam` hay `tbTKBChiTiet` vào prompt sinh SQL. Cơ chế này tự động bổ sung các bảng trung gian dựa trên các luật nghiệp vụ cứng, đảm bảo câu SQL sinh ra luôn thực hiện `JOIN` được.
> 3. **Tự động phục hồi:** Nếu tập bảng sau khi lọc bị rỗng (do lỗi phân loại từ khóa lạ), hệ thống sẽ tự động fallback về tập bảng của profile **`core`** để đảm bảo quá trình dịch Text-to-SQL vẫn diễn ra bình thường.
