Commit dd1a212f authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

fix: accessory filter mapping - use actual DB product_line_vn values for...

fix: accessory filter mapping - use actual DB product_line_vn values for accessories (Khan, Mu, Tat, Tui xach, Chan ca nhan etc.) + remove 8-product truncation limit + add accessory guidance in prompts
parent e5e5e142
...@@ -702,6 +702,7 @@ Anh có muốn em tìm thêm phụ kiện phối với váy này không? 😊" ...@@ -702,6 +702,7 @@ Anh có muốn em tìm thêm phụ kiện phối với váy này không? 😊"
- Tư vấn phong cách: "Mặc gì đi cưới?", "Đồ công sở?", "Áo cho đàn ông đi chơi" - Tư vấn phong cách: "Mặc gì đi cưới?", "Đồ công sở?", "Áo cho đàn ông đi chơi"
- So sánh sản phẩm: "So sánh áo thun vs áo len", "Giữa X và Y nên chọn cái nào" - So sánh sản phẩm: "So sánh áo thun vs áo len", "Giữa X và Y nên chọn cái nào"
- Mua cho nhiều người: "Tư vấn 2tr cho gia đình 5 người" - Mua cho nhiều người: "Tư vấn 2tr cho gia đình 5 người"
- **Khách hỏi phụ kiện phối đồ:** "Phối với phụ kiện gì?", "Kết hợp gì cho đẹp?", "Có phụ kiện nào đi kèm?" → **BẮT BUỘC** gọi tool với `product_name: "Khăn/ Mũ/ Túi xách/ Tất"`. **TUYỆT ĐỐI KHÔNG** gợi ý phụ kiện từ trí nhớ - PHẢI gọi tool để lấy data thật!
**LƯU Ý:** Ngay cả khi khách nói kèm size (VD: "Tìm áo size M"), vẫn dùng `data_retrieval_tool` để tìm sản phẩm trước. Chỉ dùng `canifa_knowledge_search` khi khách hỏi "cách chọn size" hoặc "bảng size". **LƯU Ý:** Ngay cả khi khách nói kèm size (VD: "Tìm áo size M"), vẫn dùng `data_retrieval_tool` để tìm sản phẩm trước. Chỉ dùng `canifa_knowledge_search` khi khách hỏi "cách chọn size" hoặc "bảng size".
...@@ -754,41 +755,57 @@ form_sleeve: [Dài tay/Ngắn tay/...] ...@@ -754,41 +755,57 @@ form_sleeve: [Dài tay/Ngắn tay/...]
Khi sinh query, nếu câu hỏi hiện tại thiếu thông tin, bạn **BẮT BUỘC** phải lấy thông tin từ `[GOAL]` và `[CONSTRAINS]` trong `user_insight` để điền vào các trường metadata (gender, product_name, form_sleeve, age...). Khi sinh query, nếu câu hỏi hiện tại thiếu thông tin, bạn **BẮT BUỘC** phải lấy thông tin từ `[GOAL]` và `[CONSTRAINS]` trong `user_insight` để điền vào các trường metadata (gender, product_name, form_sleeve, age...).
- Khách không nói lại "dài tay" không có nghĩa là họ đã đổi ý. Trừ khi khách nói "cho xem cộc tay", còn lại phải giữ nguyên các constraint đã biết. - Khách không nói lại "dài tay" không có nghĩa là họ đã đổi ý. Trừ khi khách nói "cho xem cộc tay", còn lại phải giữ nguyên các constraint đã biết.
**TUYỆT ĐỐI KHÔNG đưa giá tiền vào `query`** - Giá phải vào tham số `price_min`, `price_max` **TUYỆT ĐỐI KHÔNG đưa giá tiền vào `description`** - Giá phải vào tham số `price_min`, `price_max`
#### ⚠️⚠️⚠️ QUY TẮC `description` vs `product_name` (CỰC QUAN TRỌNG) ⚠️⚠️⚠️
Trong DB, cột `description_text` BẮT ĐẦU bằng tên sản phẩm:
"Áo polo nam basic dáng regular với bảng màu đa dạng..."
↑ TÊN SẢN PHẨM nằm ở đầu description_text
**→ Khi khách hỏi THẲNG tên sản phẩm:** `description` = `product_name` (GIỐNG NHAU!)
- "quần jeans" → `description: "Quần jean"`, `product_name: "Quần jean"`
- "áo polo" → `description: "Áo Polo"`, `product_name: "Áo Polo"`
- "váy jeans" → `description: "Váy jeans"`, `product_name: "Váy jeans"`
→ Vì semantic search sẽ match trực tiếp với đầu description_text trong DB!
**→ Khi khách hỏi MÔ TẢ / NHU CẦU (HYDE):** `description` ≠ `product_name`
- "đi dự tiệc" → `description: "Váy dự tiệc sang trọng nữ tính"`, `product_name: "Váy liền"`
- "đồ đi biển" → `description: "Áo phông nam đi biển thoáng mát"`, `product_name: "Áo phông"`
→ Vì cần HYDE để tạo mô tả giống description_text trong DB
#### VÍ DỤ ĐÚNG: #### VÍ DỤ ĐÚNG:
```python ```python
# Input: "Áo thun nam đi chơi dưới 300k" # CASE 1: Hỏi THẲNG tên SP → description = product_name
query = """ # Input: "Tìm quần jeans nam"
product_name: Áo thun description = "Quần jean nam"
gender_by_product: men product_name = "Quần jean"
age_by_product: adult gender_by_product = "men"
style: casual age_by_product = "adult"
"""
# CASE 2: Hỏi THẲNG tên SP + filter
# Input: "Áo polo nữ màu hồng dưới 300k"
description = "Áo Polo nữ"
product_name = "Áo Polo"
gender_by_product = "women"
master_color = "hồng"
price_max = 300000 price_max = 300000
# Input: "Áo len nữ mùa đông" # CASE 3: Hỏi MÔ TẢ / NHU CẦU → description = HYDE
query = """ # Input: "Tìm đồ đi dự tiệc cho vợ"
product_name: Áo len description = "Váy dự tiệc sang trọng nữ tính thanh lịch"
gender_by_product: women product_name = "Váy liền"
season: winter gender_by_product = "women"
material_group: Yarn - Sợi age_by_product = "adult"
"""
# Input: "Quần áo bé trai 8 tuổi"
query = """
product_name: Quần áo
gender_by_product: boy
age_by_product: kid
"""
``` ```
#### VÍ DỤ SAI (CẤM): #### VÍ DỤ SAI (CẤM):
```python ```python
query = "áo thun nam casual thoải mái" # ← SAI - không theo format description = "product_name: Áo thun. master_color: Trắng" # ← SAI - KHÔNG chèn field names vào description
query = "áo len giá dưới 500k" # ← SAI - có giá trong query description = "áo len giá dưới 500k" # ← SAI - có giá trong description
description = "Váy liền thân/ Chân váy" # ← SAI khi hỏi "váy jeans" - phải ghi "Váy jeans"
``` ```
--- ---
......
...@@ -43,13 +43,43 @@ QUY TẮC SINH SEARCH QUERIES: ...@@ -43,13 +43,43 @@ QUY TẮC SINH SEARCH QUERIES:
- "quần khaki" → `product_name: Quần Khaki/ Quần jean` - "quần khaki" → `product_name: Quần Khaki/ Quần jean`
- "áo khoác" → `product_name: Áo khoác gió/ Áo nỉ có mũ` - "áo khoác" → `product_name: Áo khoác gió/ Áo nỉ có mũ`
**⚡ PHỤ KIỆN ĐI KÈM - Khi khách hỏi "phụ kiện", "đồ đi kèm", "accessories":**
Sinh thêm Query tìm phụ kiện:
- `product_name: Khăn/ Khăn mặt/ Khăn tắm/ Mũ/ Túi xách/ Chăn cá nhân/ Tất`
- VD: "Tìm phụ kiện đi kèm" → product_name: Khăn/ Mũ/ Túi xách
- VD: "Có khăn quàng cổ không?" → product_name: Khăn
- VD: "Có khăn mặt không?" → product_name: Khăn mặt
**⚠️⚠️⚠️ QUY TẮC QUAN TRỌNG VỀ `description` vs `product_name` ⚠️⚠️⚠️**
Trong DB, cột `description_text` BẮT ĐẦU bằng tên sản phẩm:
"Áo polo nam basic dáng regular với bảng màu đa dạng..."
↑ TÊN SẢN PHẨM nằm ở đầu description_text
**→ Khi khách hỏi THẲNG tên sản phẩm:** `description` = `product_name` (GIỐNG NHAU!)
- "quần jeans" → `description: Quần jean`, `product_name: Quần jean`
- "áo khaki" → `description: Áo Khaki`, `product_name: Áo Khaki`
- "áo polo" → `description: Áo Polo`, `product_name: Áo Polo`
- "váy liền" → `description: Váy liền`, `product_name: Váy liền`
- "chân váy" → `description: Chân váy`, `product_name: Chân váy`
- "áo len" → `description: Áo len`, `product_name: Áo len`
- "váy jeans" → `description: Váy jeans`, `product_name: Váy jeans`
**→ Khi khách hỏi MÔ TẢ / NHU CẦU (HYDE):** `description` ≠ `product_name`
- "đi dự tiệc" → `description: Váy dự tiệc sang trọng nữ tính`, `product_name: Váy liền`
- "đồ đi biển" → `description: Áo phông nam đi biển thoáng mát`, `product_name: Áo phông`
- "outfit công sở" → `description: Áo sơ mi nữ thanh lịch công sở`, `product_name: Áo Sơ mi`
----- VÍ DỤ CHI TIẾT ----- ----- VÍ DỤ CHI TIẾT -----
CASE 1: TÌM 1 MÓN CỤ THỂ CASE 1: TÌM 1 MÓN CỤ THỂ (TÊN SẢN PHẨM RÕ RÀNG)
User: "Tìm áo phông nam màu trắng" User: "Tìm áo phông nam màu trắng"
-> Sinh 1 Query: -> description = product_name (vì hỏi thẳng tên SP)
- query: "product_name: Áo phông nam/ Áo T-shirt. master_color: Trắng/ White. gender_by_product: male. product_line_vn: Áo." - description: "Áo phông nam"
- product_name: "Áo phông"
- master_color: "trắng"
- gender_by_product: "men"
CASE 2: TÌM ĐỒ CHO NHIỀU ĐỐI TƯỢNG (VỢ + CHỒNG + CON) CASE 2: TÌM ĐỒ CHO NHIỀU ĐỐI TƯỢNG (VỢ + CHỒNG + CON)
User: "Tìm áo gia đình đi biển" User: "Tìm áo gia đình đi biển"
......
...@@ -29,7 +29,7 @@ class SearchItem(BaseModel): ...@@ -29,7 +29,7 @@ class SearchItem(BaseModel):
model_config = {"extra": "forbid"} # STRICT MODE model_config = {"extra": "forbid"} # STRICT MODE
description: str = Field( description: str = Field(
description="Mô tả sản phẩm cần tìm (semantic search trong description_text). VD: 'váy tiểu thư', 'áo thun basic', 'đầm dự tiệc sang chảnh'" description="Mô tả sản phẩm cho semantic search. QUY TẮC: Nếu khách hỏi THẲNG TÊN SP (quần jeans, áo polo) → description = product_name (VD: 'Quần jean', 'Áo Polo'). Nếu khách hỏi MÔ TẢ/NHU CẦU (đi dự tiệc, đồ đi biển) → description = HYDE mô tả (VD: 'Váy dự tiệc sang trọng nữ tính')"
) )
product_name: str | None = Field( product_name: str | None = Field(
description="CHỈ tên loại sản phẩm cơ bản: Áo, Váy, Quần, Chân váy, Áo khoác... KHÔNG bao gồm style/mô tả." description="CHỈ tên loại sản phẩm cơ bản: Áo, Váy, Quần, Chân váy, Áo khoác... KHÔNG bao gồm style/mô tả."
...@@ -177,13 +177,7 @@ async def data_retrieval_tool(searches: list[SearchItem]) -> str: ...@@ -177,13 +177,7 @@ async def data_retrieval_tool(searches: list[SearchItem]) -> str:
if filter_info: if filter_info:
all_filter_infos.append(filter_info) all_filter_infos.append(filter_info)
# ============================================================
# OPTIMIZATION: Limit to top 8 products
# ============================================================
MAX_PRODUCTS = 8
if len(combined_results) > MAX_PRODUCTS:
logger.info(f"⚡ Truncating results {len(combined_results)} -> {MAX_PRODUCTS}")
combined_results = combined_results[:MAX_PRODUCTS]
# Aggregate filter info from first result for simplicity in response # Aggregate filter info from first result for simplicity in response
final_info = all_filter_infos[0] if all_filter_infos else {} final_info = all_filter_infos[0] if all_filter_infos else {}
......
...@@ -372,6 +372,38 @@ PRODUCT_TYPE_MAPPING = { ...@@ -372,6 +372,38 @@ PRODUCT_TYPE_MAPPING = {
"quan short": "Quần soóc", "quan short": "Quần soóc",
"quần soóc": "Quần soóc", "quần soóc": "Quần soóc",
"quần đùi": "Quần soóc", "quần đùi": "Quần soóc",
# Phụ kiện / Accessories (DB values verified 2026-02-07)
"tất": "Tất",
"vớ": "Tất",
"tat": "Tất",
"khăn quàng cổ": "Khăn", # DB: "Khăn" (15 products)
"khăn quàng": "Khăn",
"khăn choàng": "Khăn",
"khan quang co": "Khăn",
"khăn": "Khăn",
"khan": "Khăn",
"khăn mặt": "Khăn mặt", # DB: "Khăn mặt" (16 products)
"khan mat": "Khăn mặt",
"khăn tắm": "Khăn tắm", # DB: "Khăn tắm" (17 products)
"khan tam": "Khăn tắm",
"khăn lau đầu": "Khăn lau đầu", # DB: "Khăn lau đầu" (5 products)
"khan lau dau": "Khăn lau đầu",
"mũ": "Mũ", # DB: "Mũ" (16 products)
"nón": "Mũ",
"mu": "Mũ",
"non": "Mũ",
"túi xách": "Túi xách", # DB: "Túi xách" (6 products)
"tui xach": "Túi xách",
"túi": "Túi xách",
"tui": "Túi xách",
"chăn": "Chăn cá nhân", # DB: "Chăn cá nhân" (6 products)
"chan": "Chăn cá nhân",
"chăn cá nhân": "Chăn cá nhân",
"găng tay": "Găng tay chống nắng", # DB: "Găng tay chống nắng" (5 products)
"gang tay": "Găng tay chống nắng",
"găng tay chống nắng": "Găng tay chống nắng",
"phụ kiện": "Tất",
"phu kien": "Tất",
} }
...@@ -392,6 +424,16 @@ PRODUCT_TYPE_ALTERNATIVES = { ...@@ -392,6 +424,16 @@ PRODUCT_TYPE_ALTERNATIVES = {
"Quần jean": ["Quần dài", "Quần Khaki"], "Quần jean": ["Quần dài", "Quần Khaki"],
"Quần Khaki": ["Quần dài", "Quần jean"], "Quần Khaki": ["Quần dài", "Quần jean"],
"Quần soóc": ["Quần dài"], "Quần soóc": ["Quần dài"],
# Phụ kiện alternatives (DB values verified 2026-02-07)
"Tất": ["Khăn mặt"],
"Khăn": ["Khăn mặt", "Mũ"],
"Khăn mặt": ["Khăn tắm", "Khăn"],
"Khăn tắm": ["Khăn mặt", "Khăn lau đầu"],
"Khăn lau đầu": ["Khăn tắm", "Khăn mặt"],
"Mũ": ["Khăn", "Găng tay chống nắng"],
"Túi xách": ["Mũ"],
"Chăn cá nhân": ["Khăn tắm"],
"Găng tay chống nắng": ["Mũ"],
} }
......
"""
Check actual product_line_vn values in StarRocks DB.
Verifies what accessory categories exist.
"""
import os
import sys
# Fix encoding for Windows console
os.environ["PYTHONIOENCODING"] = "utf-8"
sys.stdout.reconfigure(encoding="utf-8")
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from common.starrocks_connection import get_db_connection
def main():
db = get_db_connection()
results = db.execute_query(
"SELECT DISTINCT product_line_vn, COUNT(*) as cnt "
"FROM shared_source.magento_product_dimension_with_text_embedding "
"GROUP BY product_line_vn ORDER BY cnt DESC"
)
print("=" * 55)
print(f"{'product_line_vn':40s} | count")
print("=" * 55)
for r in results:
val = str(r.get("product_line_vn") or "NULL")
print(f"{val:40s} | {r['cnt']}")
if __name__ == "__main__":
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment