|
@@ -225,25 +225,25 @@ border-left: 5px solid #e20303; /* Green */
|
|
|
<div class="row g-4 text-center">
|
|
<div class="row g-4 text-center">
|
|
|
<div class="col-md-3">
|
|
<div class="col-md-3">
|
|
|
<div class="score-card excellent">
|
|
<div class="score-card excellent">
|
|
|
- <h2>3</h2>
|
|
|
|
|
|
|
+ <h2 id="excellence_performance">3</h2>
|
|
|
<p>Excellent Performers</p>
|
|
<p>Excellent Performers</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="col-md-3">
|
|
<div class="col-md-3">
|
|
|
<div class="score-card good">
|
|
<div class="score-card good">
|
|
|
- <h2>4</h2>
|
|
|
|
|
|
|
+ <h2 id="good_performance">4</h2>
|
|
|
<p>Good Performers</p>
|
|
<p>Good Performers</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="col-md-3">
|
|
<div class="col-md-3">
|
|
|
<div class="score-card fair">
|
|
<div class="score-card fair">
|
|
|
- <h2>2</h2>
|
|
|
|
|
|
|
+ <h2 id="fair_performance">2</h2>
|
|
|
<p>Fair Performers</p>
|
|
<p>Fair Performers</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="col-md-3">
|
|
<div class="col-md-3">
|
|
|
<div class="score-card poor">
|
|
<div class="score-card poor">
|
|
|
- <h2>1</h2>
|
|
|
|
|
|
|
+ <h2 id="poor_performance">1</h2>
|
|
|
<p>Poor Performers</p>
|
|
<p>Poor Performers</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -272,7 +272,7 @@ border-left: 5px solid #e20303; /* Green */
|
|
|
|
|
|
|
|
<!-- Table -->
|
|
<!-- Table -->
|
|
|
<div class="table-responsive mt-4">
|
|
<div class="table-responsive mt-4">
|
|
|
- <table class="table table-bordered align-middle">
|
|
|
|
|
|
|
+ <table class="table table-bordered align-middle" >
|
|
|
<thead>
|
|
<thead>
|
|
|
<tr>
|
|
<tr>
|
|
|
<th>Product Type</th>
|
|
<th>Product Type</th>
|
|
@@ -291,7 +291,7 @@ border-left: 5px solid #e20303; /* Green */
|
|
|
<th>Actions</th>
|
|
<th>Actions</th>
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
|
- <tbody>
|
|
|
|
|
|
|
+ <tbody id="productTableBody">
|
|
|
<tr>
|
|
<tr>
|
|
|
<td>CeraVe</td>
|
|
<td>CeraVe</td>
|
|
|
<td>3</td>
|
|
<td>3</td>
|
|
@@ -368,9 +368,325 @@ border-left: 5px solid #e20303; /* Green */
|
|
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.37.1/dist/apexcharts.min.js"
|
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.37.1/dist/apexcharts.min.js"
|
|
|
integrity="sha256-+vh8GkaU7C9/wbSLIcwq82tQ2wTf44aOHA8HlBMwRI8=" crossorigin="anonymous"></script>
|
|
integrity="sha256-+vh8GkaU7C9/wbSLIcwq82tQ2wTf44aOHA8HlBMwRI8=" crossorigin="anonymous"></script>
|
|
|
<script>
|
|
<script>
|
|
|
|
|
+ function renderProductMetrics(data) {
|
|
|
|
|
+ // Get the tbody element by ID (assuming your table has an ID of 'productTable')
|
|
|
|
|
+ const tableBody = document.getElementById('productTableBody');
|
|
|
|
|
+
|
|
|
|
|
+ // Clear any existing rows (like the placeholder CeraVe row)
|
|
|
|
|
+ tableBody.innerHTML = '';
|
|
|
|
|
+
|
|
|
|
|
+ // Loop through the product_metrics array in the data
|
|
|
|
|
+ data.product_metrics.forEach(metric => {
|
|
|
|
|
+ // Create a new table row element
|
|
|
|
|
+ const row = document.createElement('tr');
|
|
|
|
|
+
|
|
|
|
|
+ // Define the data points to display in order (matching the table columns)
|
|
|
|
|
+ const cellData = [
|
|
|
|
|
+ metric.product_type,
|
|
|
|
|
+ metric.products,
|
|
|
|
|
+ metric.avg_score,
|
|
|
|
|
+ metric.excellent_percent,
|
|
|
|
|
+ metric.good_percent,
|
|
|
|
|
+ metric.fair_percent,
|
|
|
|
|
+ metric.poor_percent,
|
|
|
|
|
+ metric.avg_title_quality,
|
|
|
|
|
+ metric.avg_description_quality,
|
|
|
|
|
+ metric.avg_image_quality
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // Create and append the standard data cells (td)
|
|
|
|
|
+ cellData.forEach(cellValue => {
|
|
|
|
|
+ const cell = document.createElement('td');
|
|
|
|
|
+ cell.textContent = cellValue;
|
|
|
|
|
+ row.appendChild(cell);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Add the 'Actions' cell with the View button
|
|
|
|
|
+ const actionsCell = document.createElement('td');
|
|
|
|
|
+ actionsCell.innerHTML = '<button class="btn btn-view btn-sm" onclick="viewProductInfo(`'+metric.product_type+'`)">View</button>';
|
|
|
|
|
+ row.appendChild(actionsCell);
|
|
|
|
|
+
|
|
|
|
|
+ // Append the completed row to the table body
|
|
|
|
|
+ tableBody.appendChild(row);
|
|
|
|
|
+ console.log("row",row);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function updateScoreCards(summaryData) {
|
|
|
|
|
+ // Get the performance summary object
|
|
|
|
|
+ const performance = summaryData.performance_summary;
|
|
|
|
|
+
|
|
|
|
|
+ // 1. Update Excellent Performers
|
|
|
|
|
+ const excellentElement = document.getElementById('excellence_performance');
|
|
|
|
|
+ if (excellentElement) {
|
|
|
|
|
+ // Set the text content to the 'excellent' count
|
|
|
|
|
+ excellentElement.textContent = performance.excellent;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. Update Good Performers
|
|
|
|
|
+ const goodElement = document.getElementById('good_performance');
|
|
|
|
|
+ if (goodElement) {
|
|
|
|
|
+ goodElement.textContent = performance.good;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. Update Fair Performers
|
|
|
|
|
+ const fairElement = document.getElementById('fair_performance');
|
|
|
|
|
+ if (fairElement) {
|
|
|
|
|
+ fairElement.textContent = performance.fair;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. Update Poor Performers
|
|
|
|
|
+ const poorElement = document.getElementById('poor_performance');
|
|
|
|
|
+ if (poorElement) {
|
|
|
|
|
+ poorElement.textContent = performance.poor;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ function viewProductInfo(productType){
|
|
|
|
|
+ console.log("productType",productType);
|
|
|
|
|
+ localStorage.setItem("selectedproductType",productType);
|
|
|
|
|
+ window.location.href = "/content-scorecard";
|
|
|
|
|
+ }
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
- $('#full-page-loader').show();
|
|
|
|
|
- fetch('/core/api/quality-metrics/', {
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // $('#full-page-loader').show();
|
|
|
|
|
+ // apiresults = [];
|
|
|
|
|
+
|
|
|
|
|
+ // // Define performance buckets
|
|
|
|
|
+ // const bucketRanges = {
|
|
|
|
|
+ // excellent: [85, 100],
|
|
|
|
|
+ // good: [70, 84.99],
|
|
|
|
|
+ // fair: [50, 69.99],
|
|
|
|
|
+ // poor: [0, 49.99]
|
|
|
|
|
+ // };
|
|
|
|
|
+
|
|
|
|
|
+ // // Helper function to classify score
|
|
|
|
|
+ // function classify(score) {
|
|
|
|
|
+ // for (const [bucket, [low, high]] of Object.entries(bucketRanges)) {
|
|
|
|
|
+ // if (score >= low && score <= high) return bucket;
|
|
|
|
|
+ // }
|
|
|
|
|
+ // return 'unknown';
|
|
|
|
|
+ // }
|
|
|
|
|
+
|
|
|
|
|
+ // // Group products by product type
|
|
|
|
|
+ // const grouped = {};
|
|
|
|
|
+
|
|
|
|
|
+ // apiresults.forEach(item => {
|
|
|
|
|
+ // const valuesUsed = item?.ai_suggestions?.title_construction?.values_used || [];
|
|
|
|
|
+ // const productType = valuesUsed[1] || 'Unknown';
|
|
|
|
|
+ // const score = item.final_score || 0;
|
|
|
|
|
+ // const breakdown = item.breakdown || {};
|
|
|
|
|
+ // const titleQuality = breakdown.title_quality || 0;
|
|
|
|
|
+ // const descriptionQuality = breakdown.description_quality || 0;
|
|
|
|
|
+ // const imageScore = breakdown.image_score || item.image_score || 0;
|
|
|
|
|
+
|
|
|
|
|
+ // if (!grouped[productType]) grouped[productType] = [];
|
|
|
|
|
+ // grouped[productType].push({
|
|
|
|
|
+ // score,
|
|
|
|
|
+ // titleQuality,
|
|
|
|
|
+ // descriptionQuality,
|
|
|
|
|
+ // imageScore,
|
|
|
|
|
+ // bucket: classify(score)
|
|
|
|
|
+ // });
|
|
|
|
|
+ // });
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // // Prepare final JSON structure
|
|
|
|
|
+ // const output = {
|
|
|
|
|
+ // performance_summary: { excellent: 0, good: 0, fair: 0, poor: 0 },
|
|
|
|
|
+ // product_metrics: []
|
|
|
|
|
+ // };
|
|
|
|
|
+
|
|
|
|
|
+ // for (const [ptype, items] of Object.entries(grouped)) {
|
|
|
|
|
+ // const total = items.length;
|
|
|
|
|
+ // const bucketCounts = { excellent: 0, good: 0, fair: 0, poor: 0 };
|
|
|
|
|
+ // let scoreSum = 0, titleSum = 0, descSum = 0, imageSum = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // items.forEach(item => {
|
|
|
|
|
+ // bucketCounts[item.bucket]++;
|
|
|
|
|
+ // scoreSum += item.score;
|
|
|
|
|
+ // titleSum += item.titleQuality;
|
|
|
|
|
+ // descSum += item.descriptionQuality;
|
|
|
|
|
+ // imageSum += item.imageScore;
|
|
|
|
|
+ // });
|
|
|
|
|
+
|
|
|
|
|
+ // output.performance_summary.excellent += bucketCounts.excellent;
|
|
|
|
|
+ // output.performance_summary.good += bucketCounts.good;
|
|
|
|
|
+ // output.performance_summary.fair += bucketCounts.fair;
|
|
|
|
|
+ // output.performance_summary.poor += bucketCounts.poor;
|
|
|
|
|
+
|
|
|
|
|
+ // output.product_metrics.push({
|
|
|
|
|
+ // product_type: ptype,
|
|
|
|
|
+ // products: total,
|
|
|
|
|
+ // avg_score: (scoreSum / total).toFixed(2),
|
|
|
|
|
+ // excellent_percent: `${Math.round((bucketCounts.excellent / total) * 100)}%`,
|
|
|
|
|
+ // good_percent: `${Math.round((bucketCounts.good / total) * 100)}%`,
|
|
|
|
|
+ // fair_percent: `${Math.round((bucketCounts.fair / total) * 100)}%`,
|
|
|
|
|
+ // poor_percent: `${Math.round((bucketCounts.poor / total) * 100)}%`,
|
|
|
|
|
+ // avg_title_quality: (titleSum / total).toFixed(2),
|
|
|
|
|
+ // avg_description_quality: (descSum / total).toFixed(2),
|
|
|
|
|
+ // avg_image_quality: (imageSum / total).toFixed(2)
|
|
|
|
|
+ // });
|
|
|
|
|
+ // }
|
|
|
|
|
+
|
|
|
|
|
+ // const total = Object.values(output.performance_summary).reduce((a, b) => a + b, 0);
|
|
|
|
|
+
|
|
|
|
|
+ // const percentages = Object.fromEntries(
|
|
|
|
|
+ // Object.entries(output.performance_summary).map(([key, value]) => [
|
|
|
|
|
+ // key,
|
|
|
|
|
+ // ((value / total) * 100).toFixed(2) + '%'
|
|
|
|
|
+ // ])
|
|
|
|
|
+ // );
|
|
|
|
|
+
|
|
|
|
|
+ // console.log(percentages);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // console.log('Generated Metrics:', output);
|
|
|
|
|
+ // data = output;
|
|
|
|
|
+ // 1. The JSON data you provided
|
|
|
|
|
+ // const data = {
|
|
|
|
|
+ // "performance_summary": {
|
|
|
|
|
+ // "excellent": 2,
|
|
|
|
|
+ // "good": 8,
|
|
|
|
|
+ // "fair": 0,
|
|
|
|
|
+ // "poor": 0
|
|
|
|
|
+ // },
|
|
|
|
|
+ // "product_metrics": [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // "product_type": "Unknown",
|
|
|
|
|
+ // "products": 10,
|
|
|
|
|
+ // "avg_score": "82.40",
|
|
|
|
|
+ // "excellent_percent": "20%",
|
|
|
|
|
+ // "good_percent": "80%",
|
|
|
|
|
+ // "fair_percent": "0%",
|
|
|
|
|
+ // "poor_percent": "0%",
|
|
|
|
|
+ // "avg_title_quality": "78.52",
|
|
|
|
|
+ // "avg_description_quality": "67.14",
|
|
|
|
|
+ // "avg_image_quality": "32.05"
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ]
|
|
|
|
|
+ // };
|
|
|
|
|
+
|
|
|
|
|
+ // 2. Function to render the table
|
|
|
|
|
+
|
|
|
|
|
+ // 3. Call the function to render the data when the page loads
|
|
|
|
|
+ // document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
+ // renderProductMetrics(data);
|
|
|
|
|
+ // updateScoreCards(data);
|
|
|
|
|
+// });
|
|
|
|
|
+ // $('#full-page-loader').hide();
|
|
|
|
|
+ // fetch('/core/api/', {
|
|
|
|
|
+ // 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);
|
|
|
|
|
+ // })
|
|
|
|
|
+ // .catch(error => {
|
|
|
|
|
+ // $('#full-page-loader').hide();
|
|
|
|
|
+
|
|
|
|
|
+ // The JSON data you provided (re-using the performance_summary)
|
|
|
|
|
+
|
|
|
|
|
+// Function to update the score cards
|
|
|
|
|
+
|
|
|
|
|
+ // });
|
|
|
|
|
+ });
|
|
|
|
|
+ </script>
|
|
|
|
|
+ <script>
|
|
|
|
|
+ if (localStorage.getItem('analyticsdata') !== null) {
|
|
|
|
|
+ console.log('Data key exists in localStorage');
|
|
|
|
|
+ apiresults_stringify = localStorage.getItem('analyticsdata');
|
|
|
|
|
+ apiresults = JSON.parse(apiresults_stringify);
|
|
|
|
|
+ // apiresults = [];
|
|
|
|
|
+
|
|
|
|
|
+ // Define performance buckets
|
|
|
|
|
+ const bucketRanges = {
|
|
|
|
|
+ excellent: [85, 100],
|
|
|
|
|
+ good: [70, 84.99],
|
|
|
|
|
+ fair: [50, 69.99],
|
|
|
|
|
+ poor: [0, 49.99]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Helper function to classify score
|
|
|
|
|
+ function classify(score) {
|
|
|
|
|
+ for (const [bucket, [low, high]] of Object.entries(bucketRanges)) {
|
|
|
|
|
+ if (score >= low && score <= high) return bucket;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 'unknown';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Group products by product type
|
|
|
|
|
+ const grouped = {};
|
|
|
|
|
+
|
|
|
|
|
+ apiresults.forEach(item => {
|
|
|
|
|
+ const valuesUsed = item?.ai_suggestions?.title_construction?.values_used || [];
|
|
|
|
|
+ const productType = item?.category || 'Unknown';
|
|
|
|
|
+ const score = item.final_score || 0;
|
|
|
|
|
+ const breakdown = item.breakdown || {};
|
|
|
|
|
+ const titleQuality = breakdown.title_quality || 0;
|
|
|
|
|
+ const descriptionQuality = breakdown.description_quality || 0;
|
|
|
|
|
+ const imageScore = breakdown.image_score || item.image_score || 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!grouped[productType]) grouped[productType] = [];
|
|
|
|
|
+ grouped[productType].push({
|
|
|
|
|
+ score,
|
|
|
|
|
+ titleQuality,
|
|
|
|
|
+ descriptionQuality,
|
|
|
|
|
+ imageScore,
|
|
|
|
|
+ bucket: classify(score)
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Prepare final JSON structure
|
|
|
|
|
+ const output = {
|
|
|
|
|
+ performance_summary: { excellent: 0, good: 0, fair: 0, poor: 0 },
|
|
|
|
|
+ product_metrics: []
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ for (const [ptype, items] of Object.entries(grouped)) {
|
|
|
|
|
+ const total = items.length;
|
|
|
|
|
+ const bucketCounts = { excellent: 0, good: 0, fair: 0, poor: 0 };
|
|
|
|
|
+ let scoreSum = 0, titleSum = 0, descSum = 0, imageSum = 0;
|
|
|
|
|
+
|
|
|
|
|
+ items.forEach(item => {
|
|
|
|
|
+ bucketCounts[item.bucket]++;
|
|
|
|
|
+ scoreSum += item.score;
|
|
|
|
|
+ titleSum += item.titleQuality;
|
|
|
|
|
+ descSum += item.descriptionQuality;
|
|
|
|
|
+ imageSum += item.imageScore;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ output.performance_summary.excellent += bucketCounts.excellent;
|
|
|
|
|
+ output.performance_summary.good += bucketCounts.good;
|
|
|
|
|
+ output.performance_summary.fair += bucketCounts.fair;
|
|
|
|
|
+ output.performance_summary.poor += bucketCounts.poor;
|
|
|
|
|
+
|
|
|
|
|
+ output.product_metrics.push({
|
|
|
|
|
+ product_type: ptype,
|
|
|
|
|
+ products: total,
|
|
|
|
|
+ avg_score: (scoreSum / total).toFixed(2),
|
|
|
|
|
+ excellent_percent: `${Math.round((bucketCounts.excellent / total) * 100)}%`,
|
|
|
|
|
+ good_percent: `${Math.round((bucketCounts.good / total) * 100)}%`,
|
|
|
|
|
+ fair_percent: `${Math.round((bucketCounts.fair / total) * 100)}%`,
|
|
|
|
|
+ poor_percent: `${Math.round((bucketCounts.poor / total) * 100)}%`,
|
|
|
|
|
+ avg_title_quality: (titleSum / total).toFixed(2),
|
|
|
|
|
+ avg_description_quality: (descSum / total).toFixed(2),
|
|
|
|
|
+ avg_image_quality: (imageSum / total).toFixed(2)
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ localStorage.setItem('performanceAnalysis',JSON.stringify(output));
|
|
|
|
|
+ renderProductMetrics(output);
|
|
|
|
|
+ updateScoreCards(output);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Generated Metrics:', output);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log('Data key not found');
|
|
|
|
|
+ $('#full-page-loader').show();
|
|
|
|
|
+ fetch('/core/api/batch-score/', {
|
|
|
method: 'GET', // or 'POST' if your API expects POST
|
|
method: 'GET', // or 'POST' if your API expects POST
|
|
|
headers: {
|
|
headers: {
|
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]')?.value || ''
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]')?.value || ''
|
|
@@ -378,12 +694,106 @@ border-left: 5px solid #e20303; /* Green */
|
|
|
})
|
|
})
|
|
|
.then(response => response.json())
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
.then(data => {
|
|
|
- console.log("data",data);
|
|
|
|
|
|
|
+ if (data.success) {
|
|
|
|
|
+ var html = '';
|
|
|
|
|
+ localStorage.setItem('analyticsdata',JSON.stringify(data.results));
|
|
|
|
|
+
|
|
|
|
|
+ // Define performance buckets
|
|
|
|
|
+ const bucketRanges = {
|
|
|
|
|
+ excellent: [85, 100],
|
|
|
|
|
+ good: [70, 84.99],
|
|
|
|
|
+ fair: [50, 69.99],
|
|
|
|
|
+ poor: [0, 49.99]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Helper function to classify score
|
|
|
|
|
+ function classify(score) {
|
|
|
|
|
+ for (const [bucket, [low, high]] of Object.entries(bucketRanges)) {
|
|
|
|
|
+ if (score >= low && score <= high) return bucket;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 'unknown';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Group products by product type
|
|
|
|
|
+ const grouped = {};
|
|
|
|
|
+
|
|
|
|
|
+ data.results.forEach(item => {
|
|
|
|
|
+ const valuesUsed = item?.ai_suggestions?.title_construction?.values_used || [];
|
|
|
|
|
+ const productType = item?.category || 'Unknown';
|
|
|
|
|
+ const score = item.final_score || 0;
|
|
|
|
|
+ const breakdown = item.breakdown || {};
|
|
|
|
|
+ const titleQuality = breakdown.title_quality || 0;
|
|
|
|
|
+ const descriptionQuality = breakdown.description_quality || 0;
|
|
|
|
|
+ const imageScore = breakdown.image_score || item.image_score || 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!grouped[productType]) grouped[productType] = [];
|
|
|
|
|
+ grouped[productType].push({
|
|
|
|
|
+ score,
|
|
|
|
|
+ titleQuality,
|
|
|
|
|
+ descriptionQuality,
|
|
|
|
|
+ imageScore,
|
|
|
|
|
+ bucket: classify(score)
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Prepare final JSON structure
|
|
|
|
|
+ const output = {
|
|
|
|
|
+ performance_summary: { excellent: 0, good: 0, fair: 0, poor: 0 },
|
|
|
|
|
+ product_metrics: []
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ for (const [ptype, items] of Object.entries(grouped)) {
|
|
|
|
|
+ const total = items.length;
|
|
|
|
|
+ const bucketCounts = { excellent: 0, good: 0, fair: 0, poor: 0 };
|
|
|
|
|
+ let scoreSum = 0, titleSum = 0, descSum = 0, imageSum = 0;
|
|
|
|
|
+
|
|
|
|
|
+ items.forEach(item => {
|
|
|
|
|
+ bucketCounts[item.bucket]++;
|
|
|
|
|
+ scoreSum += item.score;
|
|
|
|
|
+ titleSum += item.titleQuality;
|
|
|
|
|
+ descSum += item.descriptionQuality;
|
|
|
|
|
+ imageSum += item.imageScore;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ output.performance_summary.excellent += bucketCounts.excellent;
|
|
|
|
|
+ output.performance_summary.good += bucketCounts.good;
|
|
|
|
|
+ output.performance_summary.fair += bucketCounts.fair;
|
|
|
|
|
+ output.performance_summary.poor += bucketCounts.poor;
|
|
|
|
|
+
|
|
|
|
|
+ output.product_metrics.push({
|
|
|
|
|
+ product_type: ptype,
|
|
|
|
|
+ products: total,
|
|
|
|
|
+ avg_score: (scoreSum / total).toFixed(2),
|
|
|
|
|
+ excellent_percent: `${Math.round((bucketCounts.excellent / total) * 100)}%`,
|
|
|
|
|
+ good_percent: `${Math.round((bucketCounts.good / total) * 100)}%`,
|
|
|
|
|
+ fair_percent: `${Math.round((bucketCounts.fair / total) * 100)}%`,
|
|
|
|
|
+ poor_percent: `${Math.round((bucketCounts.poor / total) * 100)}%`,
|
|
|
|
|
+ avg_title_quality: (titleSum / total).toFixed(2),
|
|
|
|
|
+ avg_description_quality: (descSum / total).toFixed(2),
|
|
|
|
|
+ avg_image_quality: (imageSum / total).toFixed(2)
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ localStorage.setItem('performanceAnalysis',JSON.stringify(output));
|
|
|
|
|
+ // data = output;
|
|
|
|
|
+ renderProductMetrics(output);
|
|
|
|
|
+ updateScoreCards(output);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Generated Metrics:', output);
|
|
|
|
|
+ $('#full-page-loader').show();
|
|
|
|
|
+
|
|
|
|
|
+ // responseDiv.innerHTML = `<div class="alert alert-success">✅ ${data.message}</div>`;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $('#full-page-loader').hide();
|
|
|
|
|
+ // responseDiv.innerHTML = `<div class="alert alert-danger">❌ ${data.error}</div>`;
|
|
|
|
|
+ }
|
|
|
})
|
|
})
|
|
|
.catch(error => {
|
|
.catch(error => {
|
|
|
$('#full-page-loader').hide();
|
|
$('#full-page-loader').hide();
|
|
|
});
|
|
});
|
|
|
- });
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
</body><!--end::Body-->
|
|
</body><!--end::Body-->
|