Pārlūkot izejas kodu

changes for the category in content card

VISHAL BHANUSHALI 3 mēneši atpakaļ
vecāks
revīzija
fafb4860e6

+ 451 - 0
content_quality_tool_public/templates/get-data.html

@@ -252,10 +252,373 @@
      <script>
         const mediaUrl = "./../media/";
         console.log("mediaUrl",mediaUrl);
+        let apiresults_without_filter;
+        // 2. Function to filter the products based on localStorage 'productType'
+function filterProductsByCategory() {
+    // A. Retrieve the target category from localStorage
+    // Use a key like 'productType' as requested, or adjust if your localStorage key is different.
+    const targetCategory = localStorage.getItem('selectedproductType');
+
+    // Handle case where localStorage value is missing or empty
+    if (!targetCategory) {
+        console.warn("localStorage item 'productType' not found or is empty. Returning all products.");
+        return productData;
+    }
+
+    // B. Filter the product array
+    // We assume that the category is available at the top level of each product object.
+    const filteredData = apiresults_without_filter.filter(product => {
+        // Ensure both values are compared consistently (case-insensitive trim)
+        const productCategory = product.category ? product.category.trim().toLowerCase() : '';
+        const filterValue = targetCategory.trim().toLowerCase();
+        
+        return productCategory === filterValue;
+    });
+
+    return filteredData;
+}
         document.addEventListener('DOMContentLoaded', function () {
             // const responseDiv = document.getElementById('batchScoreMessage');
             // Show loader
             $('#full-page-loader').show();
+            // console.log("localStorage.getItem('analyticsdata')",localStorage.getItem('analyticsdata'));
+            if (localStorage.getItem('analyticsdata') !== null) {
+                // console.log('Data key exists in localStorage');
+                apiresults_stringify = localStorage.getItem('analyticsdata');
+                apiresults_without_filter = JSON.parse(apiresults_stringify);
+
+                apiresults = filterProductsByCategory();
+                // 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));
+                     apiresults.forEach(element => {
+                        // console.log(element.final_score);
+                        var initial_score = '';
+                        var after_score = ''
+                        var base_keys = { 'Title': 'title_quality', 'Description': 'description_quality', 'Image': 'image_score', 'Attributes': 'attributes' }
+
+
+
+                        Object.entries(base_keys).forEach(([key, value]) => {
+                            let name = key;
+                            
+                            key = key.toLowerCase();
+                            console.log("key",key);
+                            console.log(element.breakdown[value], value);
+                            var per = 0
+                            if (element.breakdown[value]) {
+                                per = element.breakdown[value];
+                            }
+                            var intial_desc = '';
+                            if (element.categorized_feedback[key]) {
+                                // console.log(element.categorized_feedback[key].issues);
+                                intial_desc = element.categorized_feedback[key].issues.join(', ');
+                            }
+                            if(key == "image"){
+                                // Build the breakdown progress HTML
+                                let breakdownHtml = '';
+
+                                for (const [key, value] of Object.entries(element.image_breakdown)) {
+                                    breakdownHtml += `
+                                        <div style="margin-bottom: 10px;">
+                                            <strong>${key.charAt(0).toUpperCase() + key.slice(1)}</strong>
+                                            <div class="progress progress-sm mt-1">
+                                                <div class="progress-bar bg-success" role="progressbar"
+                                                    aria-valuenow="${value}" aria-valuemin="0" aria-valuemax="100"
+                                                    style="width: ${value}%">
+                                                </div>
+                                            </div>
+                                            <small>${value}%</small>
+                                        </div>
+                                    `;
+                                }
+                                initial_score += `<tr>
+                                                        <td class="wow bounceInLeft">
+                                                            <a>
+                                                                `+ name + `
+                                                            </a>
+                                                        </td>
+
+                                                        <td class="project_progress wow bounceInRight">
+                                                            <div class="progress progress-sm">
+                                                                <div class="progress-bar bg-green" role="progressbar"
+                                                                    aria-valuenow="`+ per + `" aria-valuemin="0" aria-valuemax="100"
+                                                                    style="width: `+ per + `%">
+                                                                </div>
+                                                            </div>
+                                                            <small>
+                                                                `+ per + `%
+                                                            </small>
+                                                        </td>
+
+                                                    </tr>
+                                                    <tr>
+                                                    <td class="wow bounceInLeft" colspan='2' data-wow-delay="0.2s">
+                                                        <div style='max-height:100px;overflow-y:auto;'>  
+                                                            `+ breakdownHtml + `
+                                                        </div>
+                                                        </td>
+                                                    </tr>`;
+                            
+                            }else{
+                                initial_score += `<tr>
+                                                        <td class="wow bounceInLeft">
+                                                            <a>
+                                                                `+ name + `
+                                                            </a>
+                                                        </td>
+
+                                                        <td class="project_progress wow bounceInRight">
+                                                            <div class="progress progress-sm">
+                                                                <div class="progress-bar bg-green" role="progressbar"
+                                                                    aria-valuenow="`+ per + `" aria-valuemin="0" aria-valuemax="100"
+                                                                    style="width: `+ per + `%">
+                                                                </div>
+                                                            </div>
+                                                            <small>
+                                                                `+ per + `%
+                                                            </small>
+                                                        </td>
+
+                                                    </tr>
+                                                    <tr>
+                                                    <td class="wow bounceInLeft" colspan='2' data-wow-delay="0.2s">
+                                                        <div style='max-height:100px;overflow-y:auto;'>  
+                                                        <small>
+                                                            `+ intial_desc + `
+                                                        </small>
+                                                        </div>
+                                                        </td>
+                                                    </tr>`;
+                            }                        
+                        });
+                        
+
+                        Object.keys(base_keys).forEach(k => {
+                            let name = k;
+                            k = k.toLowerCase();
+                            var ik = 'improved_' + k
+                            console.log("ik",ik);
+                            var after_desc = '';
+                            if (element.ai_suggestions.content[ik]) {
+                                console.log(element.ai_suggestions.content);
+                                after_desc = element.ai_suggestions.content[ik];
+                            }
+
+                            let missing_attributes = '';
+                            if(k == "attributes"){
+                                if(element?.ai_suggestions?.content?.missing_attributes){
+                                    Object.entries(element?.ai_suggestions?.content?.missing_attributes).forEach(([key, value]) => {     
+                                        missing_attributes += `<li><span class="attribute-label">${key}:</span> ${value}</li>`         
+                                    });
+                                }
+                            }
+
+
+                            if(k == "image"){
+                                after_score += `<tr>
+                                        <td class="wow bounceInLeft">
+                                            <a>
+                                                `+ name + ` Note
+                                            </a>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                    <td class="wow bounceInLeft" colspan='2'  data-wow-delay="0.2s">
+                                        <div style='max-height:100px;overflow-y:auto;'>  
+                                        <small>
+                                              ${element?.ai_suggestions?.image?.note ? element.ai_suggestions.image.note : 'No notes available'}
+                                        </small>
+                                        </div>
+                                        </td>
+                                    </tr>`;
+                            }else if(k == "attributes"){
+                                after_score += `<tr>
+                                    <td class="wow bounceInLeft">
+                                        <a>
+                                           Missing `+ name + `
+                                        </a>
+                                    </td>
+                                </tr>
+                                <tr>
+                                <td class="wow bounceInLeft" colspan='2'  data-wow-delay="0.2s">
+                                    <div style='max-height:100px;overflow-y:auto;'>  
+                                    <small> <ul>
+                                        `+ missing_attributes + `
+                                    </ul></small>
+                                    </div>
+                                    </td>
+                                </tr>`;
+                            }else{
+                                after_score += `<tr>
+                                    <td class="wow bounceInLeft">
+                                        <a>
+                                            `+ name + `
+                                        </a>
+                                    </td>
+                                </tr>
+                                <tr>
+                                <td class="wow bounceInLeft" colspan='2'  data-wow-delay="0.2s">
+                                    <div style='max-height:100px;overflow-y:auto;'>  
+                                    <small>
+                                        `+ after_desc + `
+                                    </small>
+                                    </div>
+                                    </td>
+                                </tr>`;
+                            }                    
+                        })
+
+
+                        html += `<div class="row mb-4" >
+                                <div class="col-md-4">
+                                    <div class="card">
+                                        <img class="card-img-top wow pulse" data-wow-iteration="2"
+                                            src="`+mediaUrl+element.image_path+`">
+                                        
+                                        <div class="card-block">
+                                            <h4 class="card-title wow bounceInLeft d-block w-100" data-wow-delay="0.1s">` 
+                                                + element.title + 
+                                                `&nbsp; 
+                                                <a href="` + element?.product_link + `" target="_blank" class="text-decoration-none text-dark">
+                                                    <i class="bi bi-box-arrow-up-right ms-2" title="Open Product"></i>
+                                                </a>
+                                            </h4>
+                                            <p class="card-text wow bounceInLeft d-block w-100" data-wow-delay="0.2s">` + element.description + `</p>
+                                        </div>
+
+                                        <div class="card-footer wow bounceInLeft" data-wow-delay="0.3s">
+                                            <small>`+element.created_at+`</small>
+                                        </div>
+                                    </div>
+                                </div>
+
+                                <div class="col-md-4">
+                                    <div class="card">
+                                        <div class="card-header py-2">
+                                            <div class="text-sm mb-0">Initial Score</div>
+                                        </div>
+                                        <div class="card-body text-center wow bounceInDown" data-wow-iteration="0.5">
+                                            <input type="text" class="dial" value="`+ element.final_score + `" data-width="120" data-height="120"
+                                                data-readOnly='true' data-fgColor="#3c8dbc" data-bgColor="#e8e8e8"
+                                                data-thickness=".2">
+                                            <div class="mt-2">Overall Score</div>
+                                        </div>
+                                        <table class="table table-striped projects mb-0 table-sm">
+                                            <tbody>
+                                                `+ initial_score + `
+                                            </tbody>
+                                        </table>
+                                    </div>
+
+                                </div>
+                                <div class="col-md-4 after_score d-none">
+                                    <div class="card">
+                                        <div class="card-header py-2">
+                                            <div class="text-sm mb-0">Forecasted Score</div>
+                                        </div>
+                                        <div class="card-body text-center wow bounceInDown" data-wow-iteration="0.5">
+                                            <input type="text" class="dial" value="`+ element.ai_suggestions.content.quality_score_prediction + `" data-width="120" data-height="120"
+                                                data-readOnly='true' data-fgColor="#198754" data-bgColor="#e8e8e8"
+                                                data-thickness=".2">
+                                            <div class="mt-2">Overall Score</div>
+                                        </div>
+                                        <table class="table table-striped projects mb-0 table-sm">
+                                            <tbody>
+                                                `+ after_score + `
+                                            </tbody>
+                                        </table>
+                                    </div>
+                                    
+                                </div>
+                            </div > `;
+                        // console.log('werrrrrrrrrrrrrrrrrrr', html);
+
+                    });
+
+                    $('#html').html(html);
+                    $('.dial').knob();
+                    
+                    document.querySelector('.ai-fix-issues-button').style.display = 'block';
+                    console.log('Generated Metrics:', output);
+                    $('#full-page-loader').hide();
+             } else {
+                console.log('Data key not found');
             fetch('/core/api/batch-score/', {
                 method: 'GET', // or 'POST' if your API expects POST
                 headers: {
@@ -266,6 +629,7 @@
             .then(data => {
                 if (data.success) {
                     var html = '';
+                    localStorage.setItem('analyticsdata',JSON.stringify(data.results));
                     data.results.forEach(element => {
                         // console.log(element.final_score);
                         var initial_score = '';
@@ -519,6 +883,89 @@
                     // });
                     new WOW().init();
 
+
+                    
+                    // 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));
+
+                    console.log('Generated Metrics:', output);
+
+
                     // responseDiv.innerHTML = `<div class="alert alert-success">✅ ${data.message}</div>`;
                 } else {
                     $('#full-page-loader').hide();
@@ -537,6 +984,10 @@
                 //     responseDiv.innerHTML = '';
                 // }, 5000);
             });
+                       
+            
+            }
+
         });
         </script>
     

+ 420 - 10
content_quality_tool_public/templates/product-performance-analysis.html

@@ -225,25 +225,25 @@ border-left: 5px solid #e20303; /* Green */
                     <div class="row g-4 text-center">
                         <div class="col-md-3">
                             <div class="score-card excellent">
-                                <h2>3</h2>
+                                <h2 id="excellence_performance">3</h2>
                                 <p>Excellent Performers</p>
                             </div>
                         </div>
                         <div class="col-md-3">
                             <div class="score-card good">
-                                <h2>4</h2>
+                                <h2  id="good_performance">4</h2>
                                 <p>Good Performers</p>
                             </div>
                         </div>
                         <div class="col-md-3">
                             <div class="score-card fair">
-                                <h2>2</h2>
+                                <h2  id="fair_performance">2</h2>
                                 <p>Fair Performers</p>
                             </div>
                         </div>
                         <div class="col-md-3">
                             <div class="score-card poor">
-                                <h2>1</h2>
+                                <h2  id="poor_performance">1</h2>
                                 <p>Poor Performers</p>
                             </div>
                         </div>
@@ -272,7 +272,7 @@ border-left: 5px solid #e20303; /* Green */
 
                     <!-- Table -->
                     <div class="table-responsive mt-4">
-                        <table class="table table-bordered align-middle">
+                        <table class="table table-bordered align-middle" >
                             <thead>
                                 <tr>
                                     <th>Product Type</th>
@@ -291,7 +291,7 @@ border-left: 5px solid #e20303; /* Green */
                                     <th>Actions</th>
                                 </tr>
                             </thead>
-                            <tbody>
+                            <tbody id="productTableBody">
                                 <tr>
                                     <td>CeraVe</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"
         integrity="sha256-+vh8GkaU7C9/wbSLIcwq82tQ2wTf44aOHA8HlBMwRI8=" crossorigin="anonymous"></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 () {
-            $('#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
                 headers: {
                     'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]')?.value || ''
@@ -378,12 +694,106 @@ border-left: 5px solid #e20303; /* Green */
             })
             .then(response => response.json())
             .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 => {
                 $('#full-page-loader').hide();
             });
-        });
+                       
+            
+            }
     </script>
 
 </body><!--end::Body-->

+ 4 - 57
core/views.py

@@ -732,7 +732,8 @@ class BatchScoreViewV2(View):
                 'categorized_feedback': categorized,
                 'issues': all_issues,
                 'suggestions': all_suggestions,
-                'processing_time': total_time
+                'processing_time': total_time,
+                'product_type': category
             }
 
 
@@ -774,6 +775,7 @@ class BatchScoreViewV2(View):
                 return JsonResponse({'error': 'No products found in database'}, status=404)
 
             results, errors, elapsed = self._run_batch(products)
+
             return JsonResponse({
                 'success': True,
                 'processed': len(results),
@@ -988,61 +990,7 @@ from rest_framework import status
 from django.db.models import Avg, Count
 from .models import Product, AttributeScore  # adjust the import path as needed
 
-from rest_framework.views import APIView
-from rest_framework.response import Response
-from rest_framework import status
-from django.db.models import Avg, Count
-
 class ProductTypeQualityMetricsView(APIView):
-    """
-    API endpoint to fetch product type quality metrics.
-    Returns metrics for all products, ignoring query parameters.
-    """
-
-    def get(self, request):
-        print("****************** get called")
-        # Fetch all products, no filtering
-        queryset = Product.objects.all()
-        print("queryset", queryset)
-
-        scored = (
-            AttributeScore.objects.filter(product__in=queryset)
-            .annotate(
-                title_quality=Avg('details__title_quality'),
-                description_quality=Avg('details__description_quality'),
-                image_quality=Avg('details__image_score'),
-                attributes_quality=Avg('details__attributes'),
-            )
-            .values('product__product_type')
-            .annotate(
-                product_count=Count('product', distinct=True),
-                scored_product_count=Count('id'),
-                avg_overall_score=Avg('score'),
-                avg_title_quality=Avg('details__title_quality'),
-                avg_description_quality=Avg('details__description_quality'),
-                avg_image_quality=Avg('details__image_score'),
-                avg_attributes_quality=Avg('details__attributes'),
-            )
-        )
-
-        results = [
-            {
-                "product_type": item['product__product_type'],
-                "product_count": item['product_count'],
-                "scored_product_count": item['scored_product_count'],
-                "avg_overall_score": round(item['avg_overall_score'] or 0, 2),
-                "avg_title_quality_percent": round(item['avg_title_quality'] or 0, 2),
-                "avg_description_quality_percent": round(item['avg_description_quality'] or 0, 2),
-                "avg_image_quality_percent": round(item['avg_image_quality'] or 0, 2),
-                "avg_attributes_quality_percent": round(item['avg_attributes_quality'] or 0, 2),
-            }
-            for item in scored
-        ]
-
-        return Response(results, status=status.HTTP_200_OK)
-
-
-# class ProductTypeQualityMetricsView(APIView):
     """
     API endpoint to fetch product type quality metrics.
     Supports optional ?product_type=<type> query param.
@@ -1051,7 +999,6 @@ class ProductTypeQualityMetricsView(APIView):
     def get(self, request):
         product_type_filter = request.query_params.get('product_type', None)
         queryset = Product.objects.all()
-        print("queryset",queryset)
 
         if product_type_filter:
             queryset = queryset.filter(product_type=product_type_filter)
@@ -1064,7 +1011,7 @@ class ProductTypeQualityMetricsView(APIView):
                 image_quality=Avg('details__image_score'),
                 attributes_quality=Avg('details__attributes'),
             )
-            .values('product__category')
+            .values('product__product_type')
             .annotate(
                 product_count=Count('product', distinct=True),
                 scored_product_count=Count('id'),