File size: 5,144 Bytes
a6957c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// ── RAG: query_catalog — in-memory search, shows results in panel + returns data to AI ──
// Hàm find product theo tên/sku — dùng cho show_product tool
function findProductByName(query) {
  if (!vaistudioAllProducts.length) return null;
  const qs = _sd(query), terms = qs.split(/\s+/).filter(t=>t.length>1);
  let best = null, bestScore = 0;
  for (const p of vaistudioAllProducts) {
    let sc = 0;
    const nm = _sd(p.title_clean||p.name), sk = _sd(p.sku||p.model), br = _sd(p.brand);
    if (nm===qs||sk===qs) return p;
    if (nm.includes(qs)||sk.includes(qs)||br.includes(qs)) sc+=20;
    for (const t of terms) { if (nm.includes(t)) sc+=5; if (sk.includes(t)) sc+=4; if (br.includes(t)) sc+=3; }
    if (sc>bestScore) { bestScore=sc; best=p; }
  }
  return best;
}

// Update UI panel with search results
function updatePanelResults(products) {
  const panel = document.getElementById("vaistudio-panel");
  const toggle = document.getElementById("vaistudio-toggle");
  const loadingEl = document.getElementById("vaistudio-loading");
  const prodsEl = document.getElementById("vaistudio-products");
  const countEl = document.getElementById("vaistudio-count");
  if (!prodsEl) return;

  if (panel && !panel.classList.contains("open")) { panel.classList.add("open"); panel.style.display="flex"; }
  if (toggle) toggle.classList.add("active");
  if (loadingEl) loadingEl.hidden = true;

  prodsEl.innerHTML = "";
  prodsEl.style.display = "block";

  for (let i=0; i<products.length; i++) {
    const p = products[i];
    const card = document.createElement("div"); card.className = "product-card";
    if (p.image) {
      const ie = document.createElement("img"); ie.className="product-card-img"; ie.src=p.image; ie.alt=""; ie.loading="lazy";
      ie.onerror = function(){this.style.display="none"}; card.appendChild(ie);
    } else {
      const pl = document.createElement("div"); pl.className="product-card-img";
      pl.style.cssText = "flex-shrink:0;background:#e2e8f0;display:flex;align-items:center;justify-content:center;font-size:1.5rem";
      pl.textContent="📦"; card.appendChild(pl);
    }
    const info = document.createElement("div"); info.className="product-card-info";
    const t = document.createElement("p"); t.className="product-card-title"; t.textContent=p.title_clean||p.name;
    const b = document.createElement("p"); b.className="product-card-brand"; b.textContent=p.brand||"";
    const pr = document.createElement("p"); pr.className="product-card-price"; pr.textContent=_fmt(p.priceNum);
    info.append(t,b,pr);
    if (p.category) { const ct = document.createElement("span"); ct.className="product-card-cat"; ct.textContent=p.category; info.appendChild(ct); }
    card.appendChild(info);
    card.addEventListener("click", function(e){ e.stopPropagation(); showProductDetail(p); });
    prodsEl.appendChild(card);
  }
  if (countEl) countEl.textContent = products.length+" kết quả";
}

/** Search products in memory, update UI panel, and return structured text. */
function queryProducts(query) {
  if (!vaistudioAllProducts.length) return "Catalog still loading, please wait.";
  const q = query.trim();
  if (!q) return "What product are you looking for?";

  const qNorm = _sd(q), terms = qNorm.split(/\s+/).filter(t=>t.length>1);
  const scored = [];

  for (let i=0; i<vaistudioAllProducts.length; i++) {
    const p = vaistudioAllProducts[i];
    let score = 0;
    const nm = _sd(p.title_clean||p.name), sk = _sd(p.sku||p.model), br = _sd(p.brand);
    const all = [nm, br, _sd(p.category), _sd(p.description||""), _sd((p.features||[]).join(" ")), _sd(p.summary||"")].join(" ");

    if (nm.includes(qNorm)) score += 50;
    else if (all.includes(qNorm)) score += 30;

    for (const t of terms) {
      if (nm.includes(t)) score += 8;
      else if (sk.includes(t)) score += 6;
      else if (br.includes(t)) score += 5;
      else if (all.includes(t)) score += 1;
    }
    if (score > 0) scored.push({ product:p, score });
  }

  scored.sort((a,b)=>b.score-a.score);
  const top = scored.slice(0, 5).map(s=>s.product);

  // Update UI panel with results
  updatePanelResults(top.length ? top : vaistudioAllProducts.slice(0,20));

  if (!top.length) return `No products matching "${q}". Try a different term.`;

  let result = `Found ${top.length} product(s) matching "${q}":\n\n`;
  for (let i=0; i<top.length; i++) {
    const p = top[i];
    result += `【${i+1}${p.title_clean||p.name}\n  Brand: ${p.brand||"N/A"} | Price: ${_fmt(p.priceNum)}\n`;
    if (p.model||p.sku) result += `  Model: ${p.model||p.sku}\n`;
    if (p.summary) result += `  ${p.summary.slice(0,200)}\n`;
    if (p.features?.length) result += `  Features: ${p.features.slice(0,5).join(", ")}${p.features.length>5?"...":""}\n`;
    if (p.specs&&Object.keys(p.specs).length) {
      const entries = Object.entries(p.specs).filter(([_,v])=>v&&v!=="None").slice(0,4);
      for (const [k,v] of entries) result += `  ${k}: ${String(v).slice(0,80)}\n`;
    }
    result += `\n`;
  }
  result += `Best: ${top[0].title_clean||top[0].name} (${_fmt(top[0].priceNum)}). Panel updated!`;
  return result;
}