|
|
@@ -1,11 +1,16 @@
|
|
|
jQuery.noConflict(); // Release $ to other libraries
|
|
|
-console.log(typeof jQuery);
|
|
|
+// console.log(typeof jQuery);
|
|
|
// $ = jQuery;
|
|
|
|
|
|
// --- Config ---
|
|
|
const UPLOAD_API_URL = '/attr/products/upload-excel/'; // TODO: set to your upload endpoint
|
|
|
const ACCEPT_TYPES = '*'; // e.g., 'image/*,.csv,.xlsx'
|
|
|
|
|
|
+
|
|
|
+const thresholdInput = document.getElementById('thresholdRange');
|
|
|
+const thresholdValueDisplay = document.getElementById('thresholdValue');
|
|
|
+
|
|
|
+
|
|
|
var PRODUCT_BASE = [
|
|
|
// { id: 1, item_id: 'SKU001', product_name: "Levi's Jeans", product_long_description: 'Classic blue denim jeans with straight fit.', product_short_description: 'Blue denim jeans.', product_type: 'Clothing', image_path: 'media/products/jeans.jpg', image: 'http://127.0.0.1:8000/media/products/jeans.png' },
|
|
|
// { id: 2, item_id: 'SKU002', product_name: 'Adidas Running Shoes', product_long_description: 'Lightweight running shoes with breathable mesh and cushioned sole.', product_short_description: "Men's running shoes.", product_type: 'Footwear', image_path: 'media/products/shoes.png', image: 'http://127.0.0.1:8000/media/products/shoes.png' },
|
|
|
@@ -26,15 +31,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
- console.log("data",data);
|
|
|
+ // console.log("data",data);
|
|
|
// --- Wire up ---
|
|
|
PRODUCT_BASE = data;
|
|
|
PRODUCT_BASE = PRODUCT_BASE.map((d)=>{return {...d,mandatoryAttributes:["color","size"]}});
|
|
|
- console.log("PRODUCT_BASE",PRODUCT_BASE);
|
|
|
+ // console.log("PRODUCT_BASE",PRODUCT_BASE);
|
|
|
if(PRODUCT_BASE.length > 0){
|
|
|
$('#paginationBar').style.display = 'block';
|
|
|
}
|
|
|
renderProducts();
|
|
|
+ getAtributeList();
|
|
|
document.getElementById('btnSubmit').addEventListener('click', submitAttributes);
|
|
|
document.getElementById('btnReset').addEventListener('click', resetAll);
|
|
|
// document.getElementById('btnSelectAll').addEventListener('click', () => {
|
|
|
@@ -118,7 +124,8 @@ function renderChips(container, obj, memoryMap) {
|
|
|
Object.entries(obj || {}).forEach(([k, v]) => {
|
|
|
const chip = el('span', 'chip');
|
|
|
const kEl = el('span', 'k'); kEl.textContent = k + ':';
|
|
|
- const vEl = el('span', 'v'); vEl.textContent = ' ' + String(v);
|
|
|
+ // console.log("v",v);
|
|
|
+ const vEl = el('span', 'v'); vEl.textContent = ' ' + String(v[0].value) +' (' +String(v[0].source) + ')';
|
|
|
chip.appendChild(kEl); chip.appendChild(vEl);
|
|
|
const was = memoryMap.get(k);
|
|
|
if (was === undefined || was !== v) chip.classList.add('new');
|
|
|
@@ -141,7 +148,7 @@ function createProductCard(p) {
|
|
|
const left = el('div', 'thumb');
|
|
|
const img = new Image(); img.src = mediaUrl+p.image_path || p.image || '';
|
|
|
img.alt = `${p.product_name} image`;
|
|
|
- console.log("img",img);
|
|
|
+ // console.log("img",img);
|
|
|
// img.onerror = () => { img.remove(); const fb = el('div', 'fallback'); fb.textContent = (p.product_name || 'Product').split(' ').map(w => w[0]).slice(0,2).join('').toUpperCase(); left.appendChild(fb); };
|
|
|
img.onerror = () => { img.src = mediaUrl+"media/images/no-product.png" };
|
|
|
left.appendChild(img);
|
|
|
@@ -308,7 +315,7 @@ function renderProductsCards(items = getCurrentSlice()) {
|
|
|
function createMiniThumb(p) {
|
|
|
const mt = el('div', 'mini-thumb');
|
|
|
const img = new Image(); img.src = mediaUrl+p.image_path || p.image || ''; img.alt = `${p.product_name} image`;
|
|
|
- console.log("img",img);
|
|
|
+ // console.log("img",img);
|
|
|
img.onerror = () => { img.src = mediaUrl+"media/images/no-product.png" };
|
|
|
// img.onerror = () => { img.remove(); const fb = el('div', 'fallback'); fb.textContent = (p.product_name || 'Product').split(' ').map(w => w[0]).slice(0,2).join('').toUpperCase(); mt.appendChild(fb); };
|
|
|
mt.appendChild(img);
|
|
|
@@ -503,7 +510,7 @@ function renderProductsTable(items = getCurrentSlice()) {
|
|
|
const wrap = document.getElementById('tableContainer');
|
|
|
wrap.innerHTML = '';
|
|
|
const table = document.createElement('table');
|
|
|
- table.classList.add('table', 'table-striped', 'table-bordered');
|
|
|
+ table.classList.add('table', 'table-striped', 'table-bordered','table-responsive');
|
|
|
|
|
|
const thead = document.createElement('thead');
|
|
|
const trh = document.createElement('tr');
|
|
|
@@ -720,6 +727,7 @@ function renderInlineForTable() {
|
|
|
$('#statTotal').textContent = api.total_products ?? 0;
|
|
|
$('#statOk').textContent = api.successful ?? 0;
|
|
|
$('#statKo').textContent = api.failed ?? 0;
|
|
|
+ $('#api-summary').style.display = 'block';
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -732,7 +740,7 @@ function renderProducts() {
|
|
|
if (layoutMode === 'cards') {
|
|
|
$('#cardsContainer').style.display = '';
|
|
|
$('#tableContainer').style.display = 'none';
|
|
|
- console.log("PRODUCT_BASE",PRODUCT_BASE);
|
|
|
+ // console.log("PRODUCT_BASE",PRODUCT_BASE);
|
|
|
renderProductsCards();
|
|
|
} else {
|
|
|
$('#cardsContainer').style.display = 'none';
|
|
|
@@ -754,13 +762,23 @@ function submitAttributes() {
|
|
|
return;
|
|
|
}
|
|
|
// if (selectedIds.size === 0) { alert('Please select at least one product.'); return; }
|
|
|
- console.log("selectedIds",selectedIds);
|
|
|
+ // console.log("selectedIds",selectedIds);
|
|
|
jQuery('#full-page-loader').show();
|
|
|
// let inputArray = {
|
|
|
// "product_ids" : [...selectedIds]
|
|
|
// }
|
|
|
const extractAdditional = document.getElementById('extract_additional').checked;
|
|
|
const processImage = document.getElementById('process_image').checked;
|
|
|
+ // const selectedMultiples = document.getElementById('#mandatory-attributes');
|
|
|
+ // const selectedValues = Array.from(selectedMultiples.selectedOptions).map(option => option.value);
|
|
|
+ const selectElement = document.getElementById('mandatory-attributes');
|
|
|
+
|
|
|
+ const selectedValues = Array.from(selectElement.selectedOptions).map(option => option.value);
|
|
|
+
|
|
|
+ // console.log(selectedValues); // Logs an array of selected values
|
|
|
+ // console.log("thresholdValueDisplay",thresholdValueDisplay.value);
|
|
|
+ const threshold = parseFloat(document.getElementById('thresholdRange').value);
|
|
|
+
|
|
|
|
|
|
// Transform the new state array into the required API format
|
|
|
const itemIds = selectedProductsWithAttributes.map(p => p.item_id);
|
|
|
@@ -785,10 +803,14 @@ function submitAttributes() {
|
|
|
|
|
|
let inputArray = {
|
|
|
"products": payloadForQ1,
|
|
|
-
|
|
|
"model": "llama-3.1-8b-instant",
|
|
|
"extract_additional": extractAdditional,
|
|
|
- "process_image": processImage
|
|
|
+ "process_image": processImage,
|
|
|
+ "multiple": selectedValues,
|
|
|
+ "threshold_abs": threshold, // Lower threshold to be more permissive
|
|
|
+ // "margin": 0.3, // Larger margin to include more candidates
|
|
|
+ // "use_adaptive_margin": true,
|
|
|
+ // "use_semantic_clustering": true
|
|
|
}
|
|
|
let raw = JSON.stringify(inputArray);
|
|
|
fetch('/attr/batch-extract/', {
|
|
|
@@ -801,7 +823,7 @@ function submitAttributes() {
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
- console.log("response data",data);
|
|
|
+ // console.log("response data",data);
|
|
|
FAKE_API_RESPONSE = data;
|
|
|
renderInlineAttributes();
|
|
|
jQuery('#full-page-loader').hide();
|
|
|
@@ -818,6 +840,18 @@ function resetAll() {
|
|
|
document.getElementById('statOk').textContent = '0';
|
|
|
document.getElementById('statKo').textContent = '0';
|
|
|
$('#api-summary').style.display = 'none';
|
|
|
+
|
|
|
+ // ✅ Clear Select2 selections
|
|
|
+ jQuery('#mandatory-attributes').val(null).trigger('change');
|
|
|
+
|
|
|
+ // ✅ Reset threshold input (and display)
|
|
|
+ const thresholdInput = document.getElementById('thresholdRange');
|
|
|
+ const thresholdDisplay = document.getElementById('thresholdValue');
|
|
|
+
|
|
|
+ thresholdInput.value = '0.2'; // or any default value you prefer
|
|
|
+ if (thresholdDisplay) {
|
|
|
+ thresholdDisplay.textContent = '0.2';
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function setLayout(mode) {
|
|
|
@@ -1039,6 +1073,72 @@ function isAttributeValueSelected(itemId, attrName, value) {
|
|
|
|
|
|
|
|
|
|
|
|
-$('.attribute-select').select2({
|
|
|
- placeholder: 'Select product attributes'
|
|
|
-});
|
|
|
+// $('.attribute-select').select2({
|
|
|
+// placeholder: 'Select product attributes'
|
|
|
+// });
|
|
|
+
|
|
|
+function getAtributeList(){
|
|
|
+ jQuery('#full-page-loader').show();
|
|
|
+ try{
|
|
|
+ fetch('/attr/products/attributes', {
|
|
|
+ method: 'GET', // or 'POST' if your API expects POST
|
|
|
+ headers: {
|
|
|
+ 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]')?.value || ''
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(response => response.json())
|
|
|
+ .then(data => {
|
|
|
+ // console.log("data",data);
|
|
|
+ let attributesData = data;
|
|
|
+ // Step 1: Extract unique mandatory attribute names
|
|
|
+ const mandatoryAttributes = [...new Set(
|
|
|
+ attributesData
|
|
|
+ .filter(attr => attr.is_mandatory === "Yes")
|
|
|
+ .map(attr => attr.attribute_name)
|
|
|
+ )];
|
|
|
+
|
|
|
+ // Step 2: Populate the select element
|
|
|
+ const $select = jQuery('#mandatory-attributes');
|
|
|
+ $select.append(new Option("Select All", "select_all")); // Add "Select All" option first
|
|
|
+
|
|
|
+ mandatoryAttributes.forEach(attr => {
|
|
|
+ $select.append(new Option(attr, attr));
|
|
|
+ });
|
|
|
+
|
|
|
+ // Step 3: Initialize Select2 with placeholder
|
|
|
+ // $select.select2({
|
|
|
+ // placeholder: "Select mandatory attributes",
|
|
|
+ // allowClear: true
|
|
|
+ // });
|
|
|
+
|
|
|
+ // Step 4: Handle 'Select All' logic
|
|
|
+ $select.on('select2:select', function (e) {
|
|
|
+ if (e.params.data.id === "select_all") {
|
|
|
+ // Select all real options except "Select All"
|
|
|
+ const allOptions = mandatoryAttributes;
|
|
|
+ $select.val(allOptions).trigger('change');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ jQuery('#full-page-loader').hide();
|
|
|
+ });
|
|
|
+ }catch(err){
|
|
|
+ console.log("err",err);
|
|
|
+ jQuery('#full-page-loader').hide();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+document.addEventListener("DOMContentLoaded", function () {
|
|
|
+ // Update span when range changes
|
|
|
+ thresholdInput.addEventListener('input', function () {
|
|
|
+ // console.log("this.value",this.value);
|
|
|
+ thresholdValueDisplay.textContent = this.value;
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+// Get threshold value when needed
|
|
|
+function getThreshold() {
|
|
|
+ // console.log("parseFloat(thresholdInput.value)",parseFloat(thresholdInput.value));
|
|
|
+ return parseFloat(thresholdInput.value);
|
|
|
+}
|