Spaces:
Running
Running
Download src/semantic-terms.js from bep40/VSEARCH: direct link, hf CLI and curl.
- Browser
- Download file 7.7 kB
-
https://huggingface.co/spaces/bep40/VSEARCH/resolve/main/src/semantic-terms.js
- Command line
-
hf download hf://spaces/bep40/VSEARCH/src/semantic-terms.js
-
curl -L -o semantic-terms.js https://huggingface.co/spaces/bep40/VSEARCH/resolve/main/src/semantic-terms.js
7.7 kB
| /** | |
| * Từ khóa ngữ nghĩa chung — tách "câu hỏi về ảnh" khỏi "lookup sản phẩm". | |
| * ========================================================================= | |
| * | |
| * Trường ảnh này trộn hai thứ: ảnh interiors (xếp bằng CLIP cosine) và sản phẩm | |
| * catalogue (xếp lexical). merge.js ghép chúng, và có rule "crowd-out": khi | |
| * truy vấn rõ ràng là câu hỏi về SẢN PHẨM, mọi ảnh interiors bị gỡ khỏi trường. | |
| * | |
| * Rule đó từng nuốt luôn truy vấn ngữ nghĩa. "Bàn", "ghế", "nội thất", "nhà | |
| * phố", "biệt thự" khớp vào tên và specs của nhiều sản phẩm, nên rule crowd-out | |
| * kích hoạt và trường chỉ còn thẻ sản phẩm — mất khả năng tìm ảnh theo ngữ | |
| * nghĩa. Tập này là danh sách token (đã gấp dấu: NFD + bỏ dấu + đ→d + | |
| * lowercase, đúng normalizeText của catalogue.js) mà một truy vấn chứa vào là | |
| * đang hỏi về CẢNH / KHÔNG GIAN / ĐỒ ĐẸP, không phải sản phẩm cụ thể. merge.js | |
| * dùng nó để: | |
| * * đếm token "giống sản phẩm" (productLikeTerms) -- chỉ khi query có >= 2 | |
| * token product-like và tất cả cùng nằm trong tên một sản phẩm thì crowd-out | |
| * mới được phép gỡ interiors; | |
| * * giữ 100% hành vi lookup: trúng SKU/mã model/tên chính xác (score >= 700, | |
| * relevance.js EXACT_SCORE_FLOOR) vẫn luôn crowd-out. | |
| * * quyết định neon ring: products never ring on semantic queries. | |
| * | |
| * Nguyên tắc chọn từ: token chỉ được vào đây khi nó KHÔNG thể là danh từ chỉ một | |
| * dòng sản phẩm chủ lực. "ban"/"ghe" có mặt (tìm "bàn","ghế" là tìm ảnh). | |
| * "ke","tu","may","bep","kinh" KHÔNG có mặt (vừa là từ khóa ảnh vừa là dòng SP | |
| * chủ lực "kệ xoong","bếp từ","máy hút mùi","kính cường lực"); giữ nguyên | |
| * product-like, với rule >= 2 token, một token duy nhất ("bếp","tủ") không | |
| * kích hoạt crowd-out nên ảnh vẫn hiện. | |
| */ | |
| export const SEMANTIC_TERMS = new Set([ | |
| // ── nhà ở / bất động sản ── | |
| 'nha', 'pho', 'ong', 'lien', 'chung', 'cu', 'biet', 'thu', | |
| 'villa', 'vien', 'penthouse', 'dat', 'khu', | |
| // ── nội thất / trang trí ── | |
| 'noi', 'that', 'trang', 'tri', 'decor', | |
| // ── phòng ── | |
| 'phong', 'khach', 'ngu', 'an', 'tam', | |
| // ── kết cấu / hạng nhà (không bao giờ nằm trong tên dòng SP chủ lực) ── | |
| 'cap', 'tang', 'lau', 'mai', 'tre', 'ham', | |
| // ── đồ gỗ / vật liệu trang trí ── | |
| 'ban', 'ghe', 'tham', 'den', 'rem', 'goi', 'nem', 'go', 'tre', | |
| 'nua', 'gom', 'su', 'dong', 'vai', 'nen', 'nghe', | |
| // ── cảnh quan / kiến trúc ── | |
| 'hoa', 'cay', 'xanh', 'san', 'vuon', 'tuong', 'tran', 'gach', | |
| 'cua', 'so', 'mau', 'sac', | |
| // ── tính từ chung / meta ── | |
| 'xinh', 'dep', 'nhieu', 'lon', 'nho', 'sang', 'vang', 'bac', | |
| 'anh', 'hinh', | |
| ]); | |
| /** | |
| * Từ khóa của truy vấn LOẠI HÌNH NHÀ Ở / KIẾN TRÚC / NỘI THẤT. | |
| * | |
| * Những từ này định nghĩa "tôi đang tìm ẢNH một không gian", và chúng trái | |
| * nghĩa hoàn toàn với intent mua sắm: một câu hỏi "biệt thự", "nhà phố", | |
| * "phòng ngủ", "nhà cấp 4" không bao giờ là tên dòng sản phẩm. merge.js dùng | |
| * tập này để KHÓA các kết quả sản phẩm rác (khóa cửa "dùng cho cửa phòng ngủ", | |
| * tay nắm "phòng tắm") ra khỏi field khi intent là không gian -- những SP đó | |
| * chỉ khớp vài từ rải rác trong tên/spec dài, không phải là câu trả lời cho | |
| * "phòng khách". | |
| * | |
| * Giữ HẸP có chủ đích: "san" là sân (cảnh quan) nhưng cũng là "sàn" (vật liệu | |
| * sàn -- một mặt hàng), "tuong" là tường nhưng "tủ ống" không liên quan; nên | |
| * chỉ các từ mang NGHĨA LOẠI HÌNH NHÀ ở đây. Các đôi như "mai" (mái) vẫn nằm | |
| * ngoài vì "mái hiên" có thể là phụ kiện. | |
| */ | |
| export const SPACE_QUERY_TERMS = new Set([ | |
| 'nha', 'pho', 'ong', 'lien', 'chung', 'cu', 'biet', 'thu', | |
| 'villa', 'vien', 'penthouse', 'cap', 'tang', 'lau', 'mai', | |
| 'can', 'ho', 'khach', 'ngu', 'tam', 'an', 'bep', 'phong', | |
| ]); | |
| /** | |
| * Đồng nghĩa ngữ nghĩa, dùng để MỞ RỘNG truy vấn lexical (avatar interiors | |
| * không có embedding, chỉ match caption). | |
| * | |
| * "nhà phố" cũng nên bắt được caption "nhà ống"; "biệt thự" bắt được "villa"; | |
| * "nội thất" bắt được "trang trí". Danh sách giữ HẸP: "nha" → "vien" bắt cả | |
| * "gạch viên", "viên đá" -- false positive. Chỉ giữ cặp đồng nghĩa thực sự. | |
| */ | |
| export const SEMANTIC_SYNONYMS = { | |
| nha: ['ong', 'biet', 'thu', 'lien'], | |
| pho: ['nha', 'ong', 'lien'], | |
| ong: ['nha', 'pho', 'lien'], | |
| lien: ['nha', 'pho', 'ong'], | |
| biet: ['thu', 'villa', 'vuon'], | |
| thu: ['biet', 'villa', 'vuon'], | |
| villa: ['biet', 'thu'], | |
| vuon: ['biet', 'thu'], | |
| noi: ['that'], | |
| that: ['noi'], | |
| trang: ['tri'], | |
| tri: ['trang'], | |
| phong: ['khach', 'ngu', 'tam'], | |
| khach: ['phong'], | |
| ngu: ['phong'], | |
| tam: ['phong'], | |
| ban: ['ghe'], | |
| ghe: ['ban'], | |
| }; | |
| /** True khi một token (đã gấp dấu) là từ khóa ngữ nghĩa chung. */ | |
| export function isSemanticTerm(token) { | |
| return SEMANTIC_TERMS.has(String(token || '').trim().toLowerCase()); | |
| } | |
| /** | |
| * True khi truy vấn đang hỏi về MỘT KHÔNG GIAN / LOẠI HÌNH NHÀ Ở, không phải | |
| * về một sản phẩm. | |
| * | |
| * "phòng khách", "phòng ngủ", "nhà phố", "biệt thự", "nhà cấp 4" đều dẫn tới | |
| * đây. Ý nghĩa: một token keyword-space và MỘT token semantic khác ("phong" | |
| * + "khach") diễn đạt KHÔNG GIAN; nhiều token đều là keyword-space (nhà + cấp | |
| * 4, biệt thự + vườn) cũng vậy. merge.js đóng vai trò này để KHÔNG trả sản | |
| * phẩm rác (khóa cửa "dùng cho phòng ngủ") lấn ảnh nội thất. | |
| */ | |
| export function isSpaceQuery(query) { | |
| // Gấp dấu y hệt normalizeText (catalogue.js) — query thô có dấu "phòng | |
| // khách", nhưng SPACE_QUERY_TERMS lưu dạng đã gấp "phong"/"khach". | |
| const folded = String(query || '').trim() | |
| .normalize('NFD').replace(/[\u0300-\u036f]/g, '') | |
| .replace(/đ/g, 'd').replace(/Đ/g, 'D') | |
| .toLowerCase(); | |
| const tokens = folded.split(/[^a-z0-9]+/).filter(token => token.length > 1); | |
| if (!tokens.length) return false; | |
| const keywordSpace = tokens.filter(token => SPACE_QUERY_TERMS.has(token)); | |
| const semantic = tokens.filter(token => SEMANTIC_TERMS.has(token)); | |
| // Keyword-space duy nhất + ít nhất một semantic ("nhà vệ sinh", "khách | |
| // sạn", "phòng") vẫn là không gian; nhiều keyword-space ("nhà cấp 4") cũng | |
| // vậy. "bếp từ" (bep + tu, đều không semantic) không qua được. | |
| return keywordSpace.length > 0 && (semantic.length >= 1 || keywordSpace.length >= 2); | |
| } | |
| /** | |
| * Lọc tập token xuống còn phần THỰC SỰ nêu tên sản phẩm. | |
| * | |
| * "ban ghe" -> [] (cả hai đều là từ khóa ảnh); | |
| * "ke xoong" -> ["ke", "xoong"]; | |
| * "bep tu" -> ["bep", "tu"]. | |
| */ | |
| export function productLikeTerms(tokens) { | |
| return tokens.filter(token => !isSemanticTerm(token)); | |
| } | |
| /** | |
| * Mở rộng một tập token bằng đồng nghĩa ngữ nghĩa, giữ thứ tự và không trùng. | |
| * Dùng cho searchAvatarInteriors (match caption lexical). | |
| */ | |
| export function expandQueryTerms(terms) { | |
| const expanded = new Set(terms); | |
| for (const term of terms) { | |
| for (const alias of SEMANTIC_SYNONYMS[term] ?? []) expanded.add(alias); | |
| } | |
| return [...expanded]; | |
| } | |