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

refactor: unified SKU search (exact match, no subsequence) + store search...

refactor: unified SKU search (exact match, no subsequence) + store search upgrade (token AND + reverse LIKE fallback)
parent 40f5a569
......@@ -130,6 +130,8 @@ def format_product_results(products: list[dict]) -> list[dict]:
continue
seen_skus.add(dedup_key)
description_value = p.get("description_text_full") or p.get("description_text") or ""
product_entry = {
"sku": sku,
"sku_color": sku_color,
......@@ -139,7 +141,7 @@ def format_product_results(products: list[dict]) -> list[dict]:
"sale_price": int(sale_price) if sale_price else int(original_price),
"url": web_url,
"thumbnail_image_url": thumb_url,
"description": _neutralize_generic_print(p.get("description_text") or ""),
"description": _neutralize_generic_print(description_value),
}
size_scale = p.get("size_scale")
if size_scale:
......
......@@ -3,7 +3,6 @@ import logging
from langchain_core.tools import tool
from pydantic import BaseModel, Field
from agent.prompt_utils import read_tool_prompt
from common.starrocks_connection import get_db_connection
logger = logging.getLogger(__name__)
......@@ -33,23 +32,55 @@ async def canifa_store_search(location: str) -> str:
clean = clean.replace(prefix, "")
clean = clean.strip()
if not clean:
# Tách thành tokens, deduplicate (giữ thứ tự)
# VD: "hà đông, hà nội" → ["hà", "đông", "nội"]
tokens = list(dict.fromkeys(
t for t in clean.replace(',', ' ').split() if t.strip()
))
if not tokens:
return "Vui lòng cho em biết khu vực bạn muốn tìm cửa hàng CANIFA (ví dụ: Hoàng Mai, Cầu Giấy, Đà Nẵng...)."
# Search trên các cột structured: city, state, address, store_name
sql = f"""
SELECT store_name, address, city, state, phone_number,
schedule_name, time_open_today, time_close_today
FROM {STORE_TABLE}
WHERE LOWER(city) LIKE '%{clean}%'
OR LOWER(state) LIKE '%{clean}%'
OR LOWER(address) LIKE '%{clean}%'
OR LOWER(store_name) LIKE '%{clean}%'
ORDER BY state, city, store_name
LIMIT 20
"""
results = await sr.execute_query_async(sql)
# Search trên concat tất cả cột địa chỉ
text_col = "LOWER(concat_ws(' ', store_name, address, city, state))"
def _build_sql(where_clause: str) -> str:
return f"""
SELECT store_name, address, city, state, phone_number,
schedule_name, time_open_today, time_close_today
FROM {STORE_TABLE}
WHERE {where_clause}
ORDER BY state, city, store_name
LIMIT 20
"""
# ═══════════════════════════════════════════════
# Step 1: AND tất cả tokens (strict match)
# "hà đông hà nội" → tokens ["hà","đông","nội"] → AND → 5 stores ✓
# ═══════════════════════════════════════════════
and_conds = [f"{text_col} LIKE '%{tk}%'" for tk in tokens]
results = await sr.execute_query_async(_build_sql(' AND '.join(and_conds)))
# ═══════════════════════════════════════════════
# Step 2: Fallback — Reverse LIKE
# Dùng chính DB làm từ điển địa danh:
# Kiểm tra tên quận/huyện/tỉnh nào trong DB XUẤT HIỆN trong input user
# "hà đông cầu giấy" chứa "hà đông" (city) + "cầu giấy" (city) → lấy CẢ 2
# ═══════════════════════════════════════════════
if not results and len(tokens) >= 2:
# Strip prefix khỏi city: "Quận Hà Đông" → "hà đông"
city_stripped = """LOWER(TRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
city, 'Quận ', ''), 'Huyện ', ''), 'Thành phố ', ''), 'Thị xã ', ''), 'TP. ', '')))"""
state_lower = "LOWER(TRIM(state))"
fallback_where = f"""
(LOCATE({city_stripped}, '{clean}') > 0 AND LENGTH({city_stripped}) > 1)
OR
(LOCATE({state_lower}, '{clean}') > 0 AND LENGTH({state_lower}) > 1)
"""
results = await sr.execute_query_async(_build_sql(fallback_where))
logger.info(f"📊 Store search: reverse-LIKE fallback for '{clean}'")
logger.info(f"📊 Store search: {len(results)} stores found for '{location}'")
if not results:
......@@ -86,4 +117,3 @@ async def canifa_store_search(location: str) -> str:
return "Tôi đang gặp khó khăn khi tìm kiếm cửa hàng. Bạn có thể liên hệ hotline 1800 6061 để được hỗ trợ."
canifa_store_search.__doc__ = read_tool_prompt("store_search_tool") or canifa_store_search.__doc__
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