/**
* V.AI STUDIO — Chat Fix v14
*
* v14 CHANGES:
* - hookAI chạy NGAY đầu file (trước mọi code khác)
* - SP click trong AI search & chat cards → mở showDetail() trên trang hiện tại (ko popup)
* - Fix: nếu chatbox gọi fetch trước hook → vẫn OK vì hook chạy trước DOMContentLoaded
* - Thêm fallback: nếu showDetail không tồn tại → navigate to slug page
*/
// === HOOK AI NGAY LẬP TỨC — TRƯỚC MỌI THỨ ===
(function(){
var _origFetch = window.fetch;
var _hookInstalled = false;
var _D = function(){ return (typeof D !== 'undefined' && D && D.length) ? D : []; };
function norm(s){return(s||'').normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/[Đđ]/g,'d').toLowerCase();}
function fmt(n){if(!n||isNaN(n))return'LH';return Number(n).toLocaleString('vi-VN')+'đ';}
var PRIORITY_BRANDS=['malloca','grob','canzy','eurogold','garis','demax'];
var STOPWORDS='tìm tim giup giúp cho toi tôi anh chi chị em xin muon muốn cần can co có nao nào loai loại mua kiểu kieu nên nen duoc được mấy may cai cái xem hay hoac hoặc va và với voi the thế nay này kia đó do ấy ay bao lam làm sao gi gì vay vậy hỏi hoi ơi la là một mot nha nhé nhe ạ a ơ ừ uk ok vâng dạ da rồi roi duoc không khong ko sp san pham sản phẩm cua của'.split(' ');
var CATEGORY_MAP={
'bep tu':['bep tu','bep dien tu','bep cam ung','induction','bep tu doi','bep tu 2','bep tu 3','bep tu don','bep tu ba'],
'bep gas':['bep gas','bep ga','gas am','gas doi'],
'bep hong ngoai':['bep hong ngoai','hong ngoai','infrared'],
'bep ket hop':['bep gas ket hop','gas ket hop dien','bep ket hop','ket hop tu gas'],
'may hut mui':['may hut mui','hut mui','hood','hut khoi','khu mui','may hut khoi'],
'may rua bat':['may rua bat','rua bat','rua chen','may rua chen','dishwasher'],
'lo nuong':['lo nuong','oven','lo am tu','lo nuong am','lo nuong dien'],
'lo vi song':['lo vi song','vi song','microwave'],
'chau rua':['chau rua','bon rua','sink','chau rua chen','chau da','chau inox'],
'voi rua':['voi rua','faucet','voi rua chen','voi nong lanh','voi chen'],
'tu lanh':['tu lanh','tu ruou','wine','wine cooler'],
'may say chen':['may say chen','say chen','say bat','may say bat'],
'phu kien tu bep':['phu kien tu bep','phu kien bep','ke bat','gia bat','gia dia','tu do kho','ke gia vi','gia gia vi','thung rac','ke xoong','mam xoay','phu kien'],
'gia bat':['gia bat','gia dia','ke bat','gia nang ha'],
'tu do kho':['tu do kho','tu kho','he kho'],
'ray':['ray am','ray bi','ray giam chan','ray hop'],
'thung rac':['thung rac','thung gao'],
'khoa cua':['khoa cua','khoa van tay','khoa thong minh','khoa dien tu','smart lock'],
'tay nam':['tay nam','num tu','tay cam'],
'may giat':['may giat','may say','washing'],
'may loc nuoc':['may loc nuoc','loc nuoc','water filter'],
'tivi':['tivi','tv','television'],
'dieu hoa':['dieu hoa','may lanh','air conditioner'],
'noi chien':['noi chien khong dau','air fryer','chien khong dau'],
'may hut am':['may hut am','hut am','dehumidifier']
};
function detectCategory(text){
var n=norm(text);var bestCat='',bestLen=0;
for(var cat in CATEGORY_MAP){var kws=CATEGORY_MAP[cat];for(var i=0;ibestLen){bestCat=cat;bestLen=kws[i].length;}}}
return bestCat;
}
function detectBrand(text){
var n=norm(text);
var allBrands=['malloca','grob','canzy','eurogold','garis','demax','boss','hafele','teka','bosch','panasonic','electrolux','samsung','lg','toshiba','sharp'];
for(var i=0;i|tu|toi thieu|lon hon)\s*([\d.,]+)\s*(trieu|tr|t|m)?/);if(m2){min=parsePrice(m2[2],m2[3]);}
var m3=n.match(/(tu|from)\s*([\d.,]+)\s*(trieu|tr|t|m)?\s*(den|toi|to|-)\s*([\d.,]+)\s*(trieu|tr|t|m)?/);if(m3){min=parsePrice(m3[2],m3[3]||m3[6]);max=parsePrice(m3[5],m3[6]);}
var m4=n.match(/(tam|khoang|around|gang)\s*([\d.,]+)\s*(trieu|tr|t|m)?/);if(m4&&max===Infinity){var mid=parsePrice(m4[2],m4[3]);min=mid*0.7;max=mid*1.3;}
if(max===Infinity&&min===0){var m5=n.match(/([\d.,]+)\s*(trieu|tr)\b/);if(m5){if(n.includes('duoi')||n.includes('thap')||n.includes('re'))max=parsePrice(m5[1],m5[2]);}}
return{min:min,max:max};
}
function parsePrice(numStr,unit){
var v=parseFloat((numStr||'').replace(/\./g,'').replace(',','.'));if(isNaN(v))return 0;
unit=(unit||'').toLowerCase();
if(unit==='trieu'||unit==='tr'||unit==='t'||unit==='m')return v*1000000;
if(v>1000)return v;if(v>0&&v<200)return v*1000000;return v;
}
function extractKeywords(query){
var n=norm(query);var words=n.split(/[\s,;.!?]+/).filter(function(w){return w.length>=2;});
var filtered=words.filter(function(w){return STOPWORDS.indexOf(w)===-1;});
return filtered.length>0?filtered:words.filter(function(w){return w.length>=2;});
}
function searchProductsByContext(text,limit){
limit=limit||24;var data=_D();if(!data.length)return[];
var cat=detectCategory(text);var brand=detectBrand(text);var priceRange=detectPriceRange(text);var keywords=extractKeywords(text);
if(cat&&CATEGORY_MAP[cat]){var catW=[];CATEGORY_MAP[cat].forEach(function(kw){kw.split(' ').forEach(function(w){if(w.length>=2)catW.push(w);});});keywords=keywords.filter(function(w){return catW.indexOf(w)===-1;});}
if(brand)keywords=keywords.filter(function(w){return w!==brand;});
keywords=keywords.filter(function(w){return!w.match(/^\d+$/);});
keywords=keywords.filter(function(w){return['trieu','tr','duoi','tren','den','tam','khoang','gia','tot','nhat','re','dep','chat','luong'].indexOf(w)===-1;});
var results=[];
for(var i=0;i0){if(pricepriceRange.max)continue;score+=10;}else if(priceRange.max=2)score+=kwMatched*5;
if(score>0&&img){results.push({p:p,score:score,price:price});}
}
results.sort(function(a,b){return b.score-a.score||(a.price-b.price);});
return results.slice(0,limit);
}
// Export cho bên ngoài
window._vaiSearchContext=searchProductsByContext;
window._vaiDetectCategory=detectCategory;
window._vaiDetectBrand=detectBrand;
window._vaiDetectPrice=detectPriceRange;
// === NAVIGATE TO PRODUCT (trên trang hiện tại, không popup) ===
window._vaiGoProduct=function(slug){
if(!slug)return;
// Nếu showDetail tồn tại (defined in index.html inline) → dùng nó
if(typeof showDetail==='function'){
showDetail(slug);
// Scroll lên top
window.scrollTo({top:0,behavior:'smooth'});
return;
}
// Fallback: navigate
window.location.href='/san-pham/'+slug+'/index.html';
};
// === HOOK FETCH NGAY LẬP TỨC ===
var _lastProduct=null;
var _conversationHistory=[];
var VISION_MODEL='meta-llama/Llama-4-Scout-17B-16E-Instruct';
window.fetch=function(url,options){
if(url&&typeof url==='string'&&url.includes('router.huggingface.co')&&options&&options.body){
try{
var body=JSON.parse(options.body);
if(body.messages&&Array.isArray(body.messages)){
var userMsg=body.messages.filter(function(m){return m.role==='user';}).pop();
if(!userMsg)return _origFetch.apply(this,arguments);
var userText=typeof userMsg.content==='string'?userMsg.content:(userMsg.content&&userMsg.content[0]?userMsg.content[0].text:'');
var data=_D();var product=null;
if(data.length){
var q=norm(userText).replace(/[.\-_ ]/g,'');
for(var i=0;i3&&q.includes(sku)){product=p;break;}}
if(!product){var qn=norm(userText);for(var j=0;j8&&qn.includes(nameN)){product=p2;break;}}}
}
if(product){_lastProduct=product;}else if(_lastProduct){product=_lastProduct;}
var contextProducts=[];
var cat=detectCategory(userText);var brand=detectBrand(userText);var priceRange=detectPriceRange(userText);
var isContextQuery=cat||(brand&&!product)||(priceRange.max0);
if(isContextQuery||!product){contextProducts=searchProductsByContext(userText,8);}
// Vision model for design questions
if(product&&/thiết kế|kiểu dáng|màu sắc|design|phong cách|chất liệu/i.test(userText)){
var imgV=product.image||product.img||product.i||'';
if(imgV){body.model=VISION_MODEL;var lu=body.messages[body.messages.length-1];if(lu&&lu.role==='user'&&typeof lu.content==='string')lu.content=[{type:'text',text:lu.content},{type:'image_url',image_url:{url:imgV}}];}
}
var strict='\n\n[QUY TẮC TUYỆT ĐỐI]:\n1. CHỈ trả lời dựa trên [DỮ LIỆU] bên dưới. KHÔNG bịa thông số/giá.\n2. Nếu không có data → "Em chưa có thông tin SP này, anh/chị liên hệ Zalo 0981873395".\n3. LUÔN đề cập TÊN SẢN PHẨM + GIÁ cụ thể.\n4. Gạch đầu dòng, ngắn gọn.\n5. Khi có nhiều SP: so sánh ưu/nhược.\n6. Cuối câu: gợi ý SP phù hợp nhất.';
if(product&&!isContextQuery){
var specs=product.specs||{};var ss='';if(typeof specs==='object')for(var sk2 in specs)ss+=sk2+':'+specs[sk2]+'; ';
var feats=(product.feats||[]).slice(0,10).join('; ');
strict+='\n\n[DỮ LIỆU SP]:\nTên: '+(product.name||product.n)+'\nGiá: '+(product.price||product.p||'LH')+'\nBrand: '+(product.brand||'')+'\nMã: '+(product.sku||product.mod||'');
if(ss)strict+='\nThông số: '+ss;if(feats)strict+='\nTính năng: '+feats;
if(product.summary||product.sum)strict+='\nMô tả: '+(product.summary||product.sum||'').substring(0,500);
}
if(contextProducts.length>0){
strict+='\n\n[DANH SÁCH SP PHÙ HỢP';
if(cat)strict+=' | Loại:'+cat;if(brand)strict+=' | Brand:'+brand;
if(priceRange.max=2)return contextResults.map(function(r){var p=r.p;return{name:p.name||p.n||'',slug:p.slug||'',price:p.price||p.p||'',image:p.image||p.img||p.i||'',model:p.model||p.mod||p.sku||'',brand:p.brand||''};});
var data=_D();if(data.length){
var n=norm(botText);var found=[];var seen={};
for(var i=0;i3&&n.includes(sku)){seen[p.slug]=true;found.push({name:p.name||p.n||'',slug:p.slug,price:p.price||p.p||'',image:p.image||p.img||p.i||'',model:p.model||p.mod||'',brand:p.brand||''});}}
if(found.length)return found;
var botResults=searchProductsByContext(botText,limit);
if(botResults.length>=1)return botResults.map(function(r){var p=r.p;return{name:p.name||p.n||'',slug:p.slug||'',price:p.price||p.p||'',image:p.image||p.img||p.i||'',model:p.model||p.mod||p.sku||'',brand:p.brand||''};});
if(_conversationHistory.length){var histResults=searchProductsByContext(_conversationHistory.slice(-3).join(' '),limit);if(histResults.length>=1)return histResults.map(function(r){var p=r.p;return{name:p.name||p.n||'',slug:p.slug||'',price:p.price||p.p||'',image:p.image||p.img||p.i||'',model:p.model||p.mod||p.sku||'',brand:p.brand||''};});}
}
return[];
}
function createCardsHTML(products){
if(!products||!products.length)return'';
var h='
';
products.forEach(function(p){
h+='
';
h+='
';
if(p.image)h+='';
h+='
'+(p.name||'').substring(0,35)+'
';
if(p.model)h+='
'+(p.model||'').substring(0,20)+'
';
h+='
'+(p.price||'LH')+'
';
h+='';
h+='
';
});
h+='
';return h;
}
function injectLoop(){
var chatBody=document.querySelector('.chat-body');if(!chatBody)return;
var lastUserMsg='';var userMsgs=chatBody.querySelectorAll('.chat-msg.user');
if(userMsgs.length)lastUserMsg=userMsgs[userMsgs.length-1].textContent||'';
var botMsgs=chatBody.querySelectorAll('.chat-msg.bot');
for(var i=0;i10)_conversationHistory.shift();}
var cards=getCards(text,lastUserMsg,6);
if(cards.length){var div=document.createElement('div');div.innerHTML=createCardsHTML(cards);msg.appendChild(div.firstChild);}
}
chatBody.querySelectorAll('.vai-card-add:not([data-b])').forEach(function(btn){
btn.setAttribute('data-b','1');
btn.addEventListener('click',function(e){e.preventDefault();e.stopPropagation();var slug=this.getAttribute('data-slug');if(!slug)return;var self=this;var data=_D();for(var i=0;iĐang tải dữ liệu...
';resultsDiv.style.display='block';return;}
var results=searchProductsByContext(query,24);
if(!results.length){resultsDiv.innerHTML='
Không tìm thấy SP phù hợp. VD: "bếp từ Grob dưới 10 triệu", "máy hút mùi Malloca"
';resultsDiv.style.display='block';return;}
var cat=detectCategory(query);var brand=detectBrand(query);var priceRange=detectPriceRange(query);
var parts=[];if(cat)parts.push('📂 '+cat);if(brand)parts.push('🏷 '+brand);if(priceRange.max0)parts.push('💰 >'+fmt(priceRange.min));parts.push('🔍 '+results.length+' SP');
var html='