{"id":48892,"date":"2026-03-15T10:25:59","date_gmt":"2026-03-15T02:25:59","guid":{"rendered":"https:\/\/www.geobok.com\/geo-toolkit\/ai-citation-rate-report\/"},"modified":"2026-04-03T10:52:48","modified_gmt":"2026-04-03T02:52:48","slug":"ai-citation-rate-report","status":"publish","type":"page","link":"https:\/\/www.geobok.com\/en\/geo-toolkit\/ai-citation-rate-report\/","title":{"rendered":"AI Citation Rate Report"},"content":{"rendered":"\n<style>\n\/* ===== A1 \u62a5\u544a\u6837\u5f0f ===== *\/\n.cr-overview { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-bottom: 24px; }\n.cr-big-card { text-align: center; padding: 28px 16px; border-radius: var(--geo-radius-lg); border: 1px solid var(--geo-border); background: #fff; }\n.cr-big-num { font-size: 40px; font-weight: 800; letter-spacing: -1px; line-height: 1.1; }\n.cr-big-label { font-size: 12px; color: var(--geo-text-faint); font-weight: 600; text-transform: uppercase; letter-spacing: 1px; margin-top: 8px; }\n.cr-big-card--primary { background: linear-gradient(135deg, #f0fdfa, #ccfbf1); border-color: #99f6e4; }\n.cr-big-card--primary .cr-big-num { color: var(--geo-primary); }\n\n.cr-grade-bar { display: flex; height: 16px; border-radius: 8px; overflow: hidden; margin-bottom: 8px; }\n.cr-grade-bar__seg { height: 100%; transition: width 0.6s var(--geo-ease); }\n.cr-grade-bar__seg--A { background: var(--geo-success); }\n.cr-grade-bar__seg--B { background: #3b82f6; }\n.cr-grade-bar__seg--C { background: var(--geo-warn); }\n.cr-grade-bar__seg--D { background: var(--geo-danger); }\n.cr-grade-legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px; color: var(--geo-text-muted); }\n.cr-grade-legend__item { display: flex; align-items: center; gap: 5px; }\n.cr-grade-legend__dot { width: 10px; height: 10px; border-radius: 2px; }\n\n.cr-providers { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin-bottom: 24px; }\n.cr-prov-card { padding: 20px; border-radius: var(--geo-radius-md); border: 1px solid var(--geo-border); background: #fff; }\n.cr-prov-name { font-size: 14px; font-weight: 700; color: var(--geo-text-primary); margin-bottom: 8px; }\n.cr-prov-acc { font-size: 28px; font-weight: 800; color: var(--geo-primary); }\n.cr-prov-detail { font-size: 12px; color: var(--geo-text-faint); margin-top: 6px; }\n\n.cr-uncited { padding: 16px 20px; background: var(--geo-danger-bg); border: 1px solid var(--geo-danger-border); border-radius: var(--geo-radius-md); margin-bottom: 24px; }\n.cr-uncited__title { font-size: 14px; font-weight: 700; color: #991b1b; margin-bottom: 10px; }\n.cr-uncited__item { font-size: 14px; color: #991b1b; padding: 4px 0; display: flex; align-items: baseline; gap: 8px; }\n.cr-uncited__item::before { content: \"\u2717\"; font-weight: 700; flex-shrink: 0; }\n\n.cr-reason-text { font-size: 11px; color: var(--geo-text-faint); margin-top: 2px; }\n\n\/* ===== A3 \u8d8b\u52bf\u6837\u5f0f ===== *\/\n.td-divider { height: 2px; background: linear-gradient(90deg, transparent, var(--geo-border), transparent); margin: 40px 0 30px; }\n.td-hero { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 14px; margin-bottom: 24px; }\n.td-stat { padding: 16px; border-radius: var(--geo-radius-lg); border: 1px solid var(--geo-border); background: #fff; text-align: center; }\n.td-stat__val { font-size: 24px; font-weight: 800; color: var(--geo-text-primary); }\n.td-stat__label { font-size: 11px; color: var(--geo-text-faint); font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 4px; }\n.td-stat--primary { background: linear-gradient(135deg, #f0fdfa, #ccfbf1); border-color: #99f6e4; }\n.td-stat--primary .td-stat__val { color: var(--geo-primary); }\n.td-stat--up .td-stat__val { color: var(--geo-success); }\n.td-stat--down .td-stat__val { color: var(--geo-danger); }\n\n.td-chart-wrap { background: #fff; border: 1px solid var(--geo-border); border-radius: var(--geo-radius-lg); padding: 24px; margin-bottom: 20px; }\n.td-chart-inner { position: relative; width: 100%; height: 280px; }\n.td-chart-title { font-size: 15px; font-weight: 700; color: var(--geo-text-primary); margin-bottom: 16px; }\n\n.td-change { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 700; padding: 4px 12px; border-radius: var(--geo-radius-pill); margin: 2px 4px 2px 0; }\n.td-change--improved { background: var(--geo-success-bg); color: #166534; }\n.td-change--declined { background: var(--geo-danger-bg); color: #991b1b; }\n\n.td-history-item { display: flex; align-items: center; gap: 16px; padding: 12px 16px; border-radius: var(--geo-radius-md); border: 1px solid var(--geo-border); margin-bottom: 6px; background: #fff; font-size: 13px; }\n.td-history-item__date { color: var(--geo-text-faint); min-width: 110px; font-family: var(--geo-font-mono); }\n.td-history-item__brand { font-weight: 600; color: var(--geo-text-primary); flex: 1; }\n.td-history-item__acc { font-size: 18px; font-weight: 800; min-width: 60px; text-align: right; }\n.td-history-item__meta { font-size: 11px; color: var(--geo-text-faint); }\n\n@media (max-width: 768px) {\n    .cr-overview { grid-template-columns: 1fr; }\n    .cr-providers { grid-template-columns: 1fr; }\n    .td-hero { grid-template-columns: 1fr 1fr; }\n    .td-history-item { flex-wrap: wrap; }\n}\n<\/style>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/Chart.js\/4.4.1\/chart.umd.min.js\"><\/script>\n\n<div class=\"geo-card\">\n    <div class=\"geo-hero\">\n        <h2 class=\"geo-hero__title\">\ud83d\udcca AI Citation Report<\/h2>\n        <p class=\"geo-hero__desc\">Enter brand name + question bank to test citation rates across AI platforms. Results auto-saved for trend tracking.<\/p>\n    \n<div class=\"geo-about\">\n    <details class=\"geo-about__section\">\n        <summary>\ud83d\udcd6 What can this tool do?<\/summary>\n        <div class=\"geo-about__body\">\n            <p>The Citation Report runs the full matrix: your brand, a bank of test questions, and multiple AI platforms, all at once. You get citation rates, grade distributions, and auto-saved results for trend tracking \u2014 the execution backbone of Chapter 8's monitoring loop.<\/p>\n            <p class=\"geo-about__ref\">See <em>Make AI Speak for You: The Definitive Guide to GEO<\/em>, Ch. 8<\/p>\n        <\/div>\n    <\/details>\n    <details class=\"geo-about__section\">\n        <summary>\u2753 FAQ: GEO Impact<\/summary>\n        <div class=\"geo-about__body\">\n            <div class=\"geo-faq-item\"><h4>How should I build my question bank?<\/h4><p>The book recommends 30 questions across three tiers: brand awareness, product comparison, and industry-generic. Use the Question Map to mine real queries first.<\/p><\/div>\n            <div class=\"geo-faq-item\"><h4>How often should I run it?<\/h4><p>Monthly. Pick a fixed day, run the full battery, produce a short report. RAG-channel improvements typically show within weeks.<\/p><\/div>\n            <div class=\"geo-faq-item\"><h4>How long does D-to-A take?<\/h4><p>RAG-channel gains can appear in weeks. Parametric memory (AI internalizing your brand) is measured in months and years.<\/p><\/div>\n        <\/div>\n    <\/details>\n<\/div>\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How should I build my question bank?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The book recommends 30 questions across three tiers: brand awareness, product comparison, and industry-generic. Use the Question Map to mine real queries first.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How often should I run it?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Monthly. Pick a fixed day, run the full battery, produce a short report. RAG-channel improvements typically show within weeks.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How long does D-to-A take?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"RAG-channel gains can appear in weeks. Parametric memory (AI internalizing your brand) is measured in months and years.\"\n      }\n    }\n  ]\n}\n<\/script>\n\n<\/div>\n\n    <div class=\"geo-action\">\n        <div class=\"geo-form-grid\">\n            <div class=\"geo-field\">\n                <label class=\"geo-label\">\u76ee\u6807\u54c1\u724c\/\u516c\u53f8\u540d<\/label>\n                <input type=\"text\" id=\"cr-target\" class=\"geo-input\" placeholder=\"e.g. Nike\">\n            <\/div>\n            <div class=\"geo-field\">\n                <label class=\"geo-label\">\u9009\u62e9 AI \u5e73\u53f0<\/label>\n                <div class=\"geo-check-group\" id=\"cr-providers\">\n                                        <label class=\"geo-check-item geo-check-item--active\" data-val=\"openai\"><input type=\"checkbox\" checked> OpenAI GPT<\/label>\n                    <label class=\"geo-check-item geo-check-item--active\" data-val=\"claude\"><input type=\"checkbox\" checked> Claude<\/label>\n                    <label class=\"geo-check-item\" data-val=\"gemini\"><input type=\"checkbox\"> Gemini<\/label>\n                                    <\/div>\n            <\/div>\n            <div class=\"geo-field\">\n                <label class=\"geo-label\">\u95ee\u9898\u5e93 <span class=\"geo-label--hint\">\u6bcf\u884c\u4e00\u4e2a\u95ee\u9898\uff0c\u6700\u591a 50 \u4e2a<\/span><\/label>\n                <textarea id=\"cr-questions\" class=\"geo-input\" style=\"min-height:180px;\" placeholder=\"\u5bb6\u7528\u6295\u5f71\u4eea\u600e\u4e48\u9009&#10;\u6295\u5f71\u4eea\u548c\u7535\u89c6\u54ea\u4e2a\u597d&#10;3000\u5143\u4ee5\u5185\u6295\u5f71\u4eea\u63a8\u8350&#10;\u6295\u5f71\u4eea\u4ec0\u4e48\u724c\u5b50\u597d\"><\/textarea>\n            <\/div>\n            <button id=\"cr-btn\" class=\"geo-btn geo-btn--block\">Generate citation report<\/button>\n        <\/div>\n    <\/div>\n\n    <div class=\"geo-progress\" id=\"cr-progress\">\n        <div class=\"geo-progress__track\"><div id=\"cr-pbar\" class=\"geo-progress__bar\"><\/div><\/div>\n        <div id=\"cr-ptext\" class=\"geo-progress__text\"><\/div>\n    <\/div>\n\n    <!-- \u62a5\u544a\u7ed3\u679c\u533a -->\n    <div id=\"cr-apikey-area\"><\/div>\n<script>document.addEventListener('DOMContentLoaded',function(){var el=document.getElementById('cr-apikey-area');if(el)el.innerHTML=GeoAPI.renderApiKeyInput();});<\/script>\n    <div id=\"cr-result\" class=\"geo-result\" style=\"padding: 0 var(--geo-space-xl) var(--geo-space-xl);\"><\/div>\n\n    <!-- \u8d8b\u52bf\u533a\uff08\u59cb\u7ec8\u5b58\u5728\uff0c\u9875\u9762\u52a0\u8f7d\u65f6\u81ea\u52a8\u586b\u5145\uff09 -->\n    <div id=\"td-section\" style=\"padding: 0 var(--geo-space-xl) var(--geo-space-xl);\"><\/div>\n<\/div>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', function(){\n\n    \/* ---- \u591a\u9009\u4ea4\u4e92 ---- *\/\n    document.querySelectorAll('#cr-providers .geo-check-item').forEach(function(item){\n        item.addEventListener('click', function(){\n            var cb = this.querySelector('input');\n            cb.checked = !cb.checked;\n            this.classList.toggle('geo-check-item--active', cb.checked);\n        });\n    });\n\n    var btn = document.getElementById('cr-btn');\n    var result = document.getElementById('cr-result');\n    var tdSection = document.getElementById('td-section');\n    var progress = GeoAPI.initProgress(document.getElementById('cr-pbar'), document.getElementById('cr-ptext'));\n    var PROV_NAMES = {}; GeoAPI.getProviders().forEach(function(p){PROV_NAMES[p.value]=p.label;});\n    var mainChart = null, providerChart = null;\n\n    function getHeaders() {\n        var h = {};\n        if (GeoAPI._auth && GeoAPI._auth.token) h['X-GeoAuth-Token'] = GeoAPI._auth.token;\n        return h;\n    }\n    function accColor(v) { return v >= 50 ? 'var(--geo-success)' : v >= 20 ? 'var(--geo-primary)' : 'var(--geo-danger)'; }\n\t\/* =========================================================================\n * \u524d\u7aef\u8865\u4e01\uff1a\u5728\u73b0\u6709 geo_citation_report Snippet \u7684 JS \u4e2d\u6dfb\u52a0\n * \u627e\u5230 DOMContentLoaded \u56de\u8c03\u7684\u5f00\u5934\uff08\u591a\u9009\u4ea4\u4e92\u90a3\u6bb5\u4e4b\u540e\uff09\uff0c\u63d2\u5165\u4ee5\u4e0b\u4ee3\u7801\n * ========================================================================= *\/\n\n    \/* ==================== \u52a0\u8f7d\u4e0a\u6b21\u6d4b\u8bd5\u914d\u7f6e ==================== *\/\n    var loadBar = document.createElement('div');\n    loadBar.style.cssText = 'display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:16px;';\n    loadBar.innerHTML = '<button type=\"button\" id=\"cr-load-last\" class=\"geo-btn geo-btn--ghost\" style=\"font-size:13px;padding:8px 16px;\">\ud83d\udccb \u52a0\u8f7d\u4e0a\u6b21\u6d4b\u8bd5<\/button>'\n        + '<span id=\"cr-load-info\" style=\"font-size:13px;color:var(--geo-text-faint);\"><\/span>';\n\n    \/* \u63d2\u5165\u5230\u6309\u94ae\u4e0a\u65b9 *\/\n    var formBtn = document.getElementById('cr-btn');\n    if (formBtn) formBtn.parentNode.insertBefore(loadBar, formBtn);\n\n    \/* \u9875\u9762\u52a0\u8f7d\u65f6\u68c0\u67e5\u662f\u5426\u6709\u5386\u53f2\u6570\u636e *\/\n    if (GeoAPI._auth && GeoAPI._auth.loggedIn) {\n        axios.get(GeoAPI.BASE_URL + '\/geo\/last-test-config', { headers: getHeaders(), timeout: 8000 })\n        .then(function(res) {\n            var cfg = res.data;\n            if (cfg.has_data) {\n                document.getElementById('cr-load-info').textContent = \n                    '\u4e0a\u6b21\u6d4b\u8bd5\uff1a' + cfg.target_company + '\uff08' + cfg.question_count + ' \u9898 \u00b7 ' + cfg.last_test_date + '\uff09';\n            } else {\n                loadBar.style.display = 'none';\n            }\n        }).catch(function() {\n            loadBar.style.display = 'none';\n        });\n    } else {\n        loadBar.style.display = 'none';\n    }\n\n    \/* \u70b9\u51fb\u52a0\u8f7d *\/\n    document.getElementById('cr-load-last').addEventListener('click', function() {\n        var loadBtn = this;\n        loadBtn.disabled = true;\n        loadBtn.textContent = '\u52a0\u8f7d\u4e2d...';\n\n        axios.get(GeoAPI.BASE_URL + '\/geo\/last-test-config', { headers: getHeaders(), timeout: 8000 })\n        .then(function(res) {\n            var cfg = res.data;\n            if (!cfg.has_data) { alert('\u6ca1\u6709\u5386\u53f2\u6d4b\u8bd5\u6570\u636e'); return; }\n\n            \/* \u56de\u586b\u54c1\u724c\u540d *\/\n            document.getElementById('cr-target').value = cfg.target_company;\n\n            \/* \u56de\u586b\u95ee\u9898\u5e93 *\/\n            document.getElementById('cr-questions').value = cfg.questions.join('\\n');\n\n            \/* \u56de\u586b\u5e73\u53f0\u9009\u62e9 *\/\n            document.querySelectorAll('#cr-providers .geo-check-item').forEach(function(item) {\n                var val = item.getAttribute('data-val');\n                var cb = item.querySelector('input');\n                var shouldCheck = cfg.providers.indexOf(val) >= 0;\n                cb.checked = shouldCheck;\n                item.classList.toggle('geo-check-item--active', shouldCheck);\n            });\n\n            loadBtn.textContent = '\u2713 \u5df2\u52a0\u8f7d';\n            setTimeout(function() { loadBtn.textContent = '\ud83d\udccb \u52a0\u8f7d\u4e0a\u6b21\u6d4b\u8bd5'; loadBtn.disabled = false; }, 1500);\n        }).catch(function(err) {\n            alert('\u52a0\u8f7d\u5931\u8d25: ' + err.message);\n            loadBtn.textContent = '\ud83d\udccb \u52a0\u8f7d\u4e0a\u6b21\u6d4b\u8bd5';\n            loadBtn.disabled = false;\n        });\n    });\n\n    \/* ==================== \u9875\u9762\u52a0\u8f7d\u65f6\uff1a\u81ea\u52a8\u52a0\u8f7d\u8d8b\u52bf ==================== *\/\n    loadTrend();\n\n    \/* ==================== \u62a5\u544a\u751f\u6210 ==================== *\/\n    btn.addEventListener('click', async function(){\n        var target = document.getElementById('cr-target').value.trim();\n        if(!target){ GeoAPI.showError(result, '\u8bf7\u8f93\u5165\u76ee\u6807\u54c1\u724c\u540d'); return; }\n\n        var questions = document.getElementById('cr-questions').value\n            .split('\\n').map(function(q){return q.trim();}).filter(function(q){return q.length > 0;});\n        if(questions.length === 0){ GeoAPI.showError(result, '\u8bf7\u8f93\u5165\u81f3\u5c11\u4e00\u4e2a\u95ee\u9898'); return; }\n        if(questions.length > 50){ GeoAPI.showError(result, '\u5355\u6b21\u6700\u591a 50 \u4e2a\u95ee\u9898\uff0c\u5f53\u524d ' + questions.length + ' \u4e2a'); return; }\n\n        var providers = [];\n        document.querySelectorAll('#cr-providers .geo-check-item input:checked').forEach(function(cb){\n            providers.push(cb.closest('.geo-check-item').getAttribute('data-val'));\n        });\n        if(providers.length === 0){ GeoAPI.showError(result, '\u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u4e2a AI \u5e73\u53f0'); return; }\n\n        var totalCalls = questions.length * providers.length;\n        var estMin = Math.ceil(totalCalls * 2 \/ 60);\n\n        GeoAPI.disableBtn(btn, GeoAPI.t('btn.generating'));\n        result.style.display = 'none';\n        result.classList.remove('geo-result--visible');\n        progress.show();\n        progress.update(5, GeoAPI.LANG==='en' ? 'Sending '+totalCalls+' test queries to AI models (~'+estMin+' min)...' : '\u6b63\u5728\u5411 '+totalCalls+' \u4e2a AI \u5927\u6a21\u578b\u53d1\u9001\u6d4b\u8bd5\u95ee\u9898\uff0c\u9884\u8ba1\u9700\u8981 '+estMin+' \u5206\u949f...');\n\n        var pct = 5;\n        var timer = setInterval(function(){\n            pct = Math.min(pct + 0.3, 92);\n            var phase = pct < 30 ? (GeoAPI.LANG==='en'?'Querying AI models...':'\u6b63\u5728\u5411 AI \u5927\u6a21\u578b\u53d1\u9001\u95ee\u9898...') : pct < 70 ? (GeoAPI.LANG==='en'?'Analyzing responses...':'\u6b63\u5728\u5206\u6790\u56de\u7b54\u5e76\u8bc4\u4f30\u5f15\u7528\u7b49\u7ea7...') : (GeoAPI.LANG==='en'?'Compiling report...':'\u6b63\u5728\u6c47\u603b GEO \u5f15\u7528\u7387\u62a5\u544a...');\n            progress.update(pct, phase + '\uff08' + Math.round(pct) + '%\uff09');\n        }, 1000);\n\n        try {\n            var data = await GeoAPI.post('\/geo\/citation-report', {\n                target_company: target,\n                questions: questions,\n                providers: providers,\n                api_keys: (function(){ var keys={}; providers.forEach(function(p){ var k=GeoAPI.getApiKey(p); if(k) keys[p]=k; }); return keys; })(),\n                lang: GeoAPI.LANG\n            }, { timeout: 600000 });\n\n            clearInterval(timer);\n            progress.update(100, '\u62a5\u544a\u751f\u6210\u5b8c\u6210');\n            setTimeout(function(){ progress.hide(); }, 500);\n\n            renderReport(data, providers);\n\n            \/* \u62a5\u544a\u8dd1\u5b8c\u540e\u81ea\u52a8\u5237\u65b0\u8d8b\u52bf *\/\n            setTimeout(function(){ loadTrend(); }, 500);\n\n        } catch(e) {\n            clearInterval(timer);\n            progress.hide();\n            if(!e._geoAuthHandled) GeoAPI.showError(result, '\u62a5\u544a\u751f\u6210\u5931\u8d25: ' + e.message);\n        } finally {\n            GeoAPI.enableBtn(btn);\n        }\n    });\n\n\n    \/* ==================== \u6e32\u67d3\u62a5\u544a\uff08A1\uff09 ==================== *\/\n    function renderReport(data, providers) {\n        var html = '';\n        var gd = data.overall_grade_distribution || {};\n        var totalGraded = (gd.A||0) + (gd.B||0) + (gd.C||0) + (gd.D||0);\n\n        html += '<div class=\"geo-section\"><h3 class=\"geo-section__title\">\ud83d\udcc8 \u672c\u6b21\u6d4b\u8bd5\u7ed3\u679c<\/h3>'\n              + '<span class=\"geo-section__desc\">\u54c1\u724c\uff1a' + GeoAPI.escapeHtml(data.target_company)\n              + ' \u00b7 ' + data.question_count + ' \u4e2a\u95ee\u9898 \u00d7 ' + providers.length + ' \u4e2a\u5e73\u53f0 = ' + data.total_checks + ' \u6b21\u68c0\u6d4b<\/span><\/div>';\n\n        html += '<div class=\"cr-overview\">'\n              + '<div class=\"cr-big-card cr-big-card--primary\"><div class=\"cr-big-num\">' + data.overall_acc + '%<\/div><div class=\"cr-big-label\">\u603b\u5f15\u7528\u8986\u76d6\u7387<\/div><\/div>'\n              + '<div class=\"cr-big-card\"><div class=\"cr-big-num\">' + data.total_cited + '\/' + data.total_checks + '<\/div><div class=\"cr-big-label\">\u88ab\u5f15\u7528\u6b21\u6570<\/div><\/div>'\n              + '<div class=\"cr-big-card\"><div class=\"cr-big-num\" style=\"color:var(--geo-danger);\">' + data.not_cited_count + '<\/div><div class=\"cr-big-label\">\u96f6\u5f15\u7528\u95ee\u9898\u6570<\/div><\/div>'\n              + '<\/div>';\n\n        if(totalGraded > 0) {\n            html += '<div class=\"cr-grade-bar\">';\n            ['A','B','C','D'].forEach(function(g){\n                var pct = ((gd[g]||0) \/ totalGraded * 100);\n                if(pct > 0) html += '<div class=\"cr-grade-bar__seg cr-grade-bar__seg--' + g + '\" style=\"width:' + pct + '%\" title=\"' + g + '\u7ea7: ' + (gd[g]||0) + '\u6b21\"><\/div>';\n            });\n            html += '<\/div>';\n            html += '<div class=\"cr-grade-legend\">';\n            ['A','B','C','D'].forEach(function(g){\n                var colors = {A:'var(--geo-success)',B:'#3b82f6',C:'var(--geo-warn)',D:'var(--geo-danger)'};\n                html += '<span class=\"cr-grade-legend__item\"><span class=\"cr-grade-legend__dot\" style=\"background:' + colors[g] + '\"><\/span>' + g + ' \u7ea7: ' + (gd[g]||0) + '<\/span>';\n            });\n            html += '<\/div>';\n        }\n\n        html += '<div class=\"geo-section\" style=\"margin-top:24px;\"><h3 class=\"geo-section__title\">\ud83c\udff7\ufe0f \u5206\u5e73\u53f0\u5bf9\u6bd4<\/h3><\/div>';\n        html += '<div class=\"cr-providers\">';\n        providers.forEach(function(p){\n            var pd = data.by_provider[p] || {};\n            var pgd = pd.grade_distribution || {};\n            html += '<div class=\"cr-prov-card\">'\n                  + '<div class=\"cr-prov-name\">' + GeoAPI.escapeHtml(PROV_NAMES[p]||p) + '<\/div>'\n                  + '<div class=\"cr-prov-acc\">' + (pd.acc||0) + '%<\/div>'\n                  + '<div class=\"cr-prov-detail\">\u5f15\u7528 ' + (pd.cited_count||0) + '\/' + (pd.total||0)\n                  + ' \u00b7 A:' + (pgd.A||0) + ' B:' + (pgd.B||0) + ' C:' + (pgd.C||0) + ' D:' + (pgd.D||0) + '<\/div>'\n                  + '<\/div>';\n        });\n        html += '<\/div>';\n\n        if(data.not_cited_questions && data.not_cited_questions.length > 0) {\n            html += '<div class=\"cr-uncited\"><div class=\"cr-uncited__title\">\u26a0 \u4ee5\u4e0b\u95ee\u9898\u5728\u6240\u6709\u5e73\u53f0\u5747\u672a\u88ab\u5f15\u7528\uff08\u5171 ' + data.not_cited_questions.length + ' \u4e2a\uff09<\/div>';\n            data.not_cited_questions.forEach(function(q){\n                html += '<div class=\"cr-uncited__item\">' + GeoAPI.escapeHtml(q) + '<\/div>';\n            });\n            html += '<\/div>';\n        }\n\n        html += '<div class=\"geo-section\"><h3 class=\"geo-section__title\">\ud83d\udccb \u9010\u9898\u660e\u7ec6<\/h3><\/div>';\n        html += '<div class=\"geo-table-wrap\"><table class=\"geo-table\"><thead><tr>'\n              + '<th style=\"min-width:40px;\">#<\/th><th style=\"min-width:200px;\">\u95ee\u9898<\/th>';\n        providers.forEach(function(p){\n            html += '<th style=\"min-width:120px;\">' + GeoAPI.escapeHtml(PROV_NAMES[p]||p) + '<\/th>';\n        });\n        html += '<\/tr><\/thead><tbody>';\n\n        data.question_details.forEach(function(qd, idx){\n            html += '<tr><td>' + (idx+1) + '<\/td>';\n            html += '<td style=\"white-space:normal;max-width:300px;\">' + GeoAPI.escapeHtml(qd.question) + '<\/td>';\n            providers.forEach(function(p){\n                var r = qd.results[p];\n                if(!r) { html += '<td>-<\/td>'; return; }\n                var g = r.grade || '-';\n                if(r.error) {\n                    html += '<td><span class=\"geo-badge geo-badge--neutral\" style=\"font-size:11px;padding:2px 8px;\">\u9519\u8bef<\/span><\/td>';\n                } else {\n                    html += '<td><span class=\"geo-grade geo-grade--' + g + '\" style=\"width:28px;height:28px;font-size:13px;\">' + g + '<\/span>';\n                    if(r.grade_reason) html += '<div class=\"cr-reason-text\">' + GeoAPI.escapeHtml(r.grade_reason.substring(0, 60)) + '<\/div>';\n                    html += '<\/td>';\n                }\n            });\n            html += '<\/tr>';\n        });\n        html += '<\/tbody><\/table><\/div>';\n\n        GeoAPI.showResult(result, html);\n    }\n\n\n    \/* ==================== \u8d8b\u52bf\u52a0\u8f7d\uff08A3\uff09 ==================== *\/\n    function loadTrend() {\n        if (!GeoAPI._auth || !GeoAPI._auth.loggedIn) {\n            tdSection.innerHTML = '';\n            return;\n        }\n\n        axios.get(GeoAPI.BASE_URL + '\/geo\/trend-compare', { headers: getHeaders(), timeout: 15000 })\n        .then(function(res) {\n            var data = res.data;\n            if (!data.has_data) {\n                tdSection.innerHTML = '<div class=\"td-divider\"><\/div>'\n                    + '<div style=\"text-align:center;padding:30px 20px;color:var(--geo-text-muted);font-size:14px;\">'\n                    + '\ud83d\udcca \u5b8c\u6210\u7b2c\u4e00\u6b21\u62a5\u544a\u540e\uff0c\u8d8b\u52bf\u56fe\u5c06\u5728\u8fd9\u91cc\u663e\u793a<\/div>';\n                tdSection.style.display = 'block';\n                return;\n            }\n\n            return axios.get(GeoAPI.BASE_URL + '\/geo\/trend-list', { headers: getHeaders(), timeout: 15000 })\n            .then(function(res2) {\n                renderTrend(data, res2.data);\n            });\n        }).catch(function(err) {\n            \/* \u8d8b\u52bf\u52a0\u8f7d\u5931\u8d25\u4e0d\u5f71\u54cd\u4e3b\u529f\u80fd\uff0c\u9759\u9ed8\u5904\u7406 *\/\n            console.log('\u8d8b\u52bf\u52a0\u8f7d:', err.message);\n        });\n    }\n\n\n\/* =========================================================================\n * \u66ff\u6362 geo_citation_report Snippet \u4e2d\u7684 renderTrend \u51fd\u6570\n * \u627e\u5230 \"function renderTrend(trendData, listData)\" \u6574\u4e2a\u51fd\u6570\u4f53\uff0c\u66ff\u6362\u4e3a\u4ee5\u4e0b\n * ========================================================================= *\/\n\n    function renderTrend(trendData, listData) {\n        var html = '';\n        var trend = trendData.trend || [];\n        var changes = trendData.grade_changes || [];\n        var uncited = trendData.still_uncited || [];\n        var reports = listData.reports || [];\n\n        var PROV_SHORT = {}; GeoAPI.getProviders().forEach(function(p){PROV_SHORT[p.value]=p.label;});\n\n        var latest = trend.length > 0 ? trend[trend.length - 1] : null;\n        var previous = trend.length > 1 ? trend[trend.length - 2] : null;\n        var first = trend.length > 0 ? trend[0] : null;\n        var delta = latest && previous ? (latest.acc - previous.acc).toFixed(1) : 0;\n        var totalDelta = latest && first && trend.length > 1 ? (latest.acc - first.acc).toFixed(1) : 0;\n\n        function shortDate(d) {\n            if (!d) return '';\n            \/* \"2026-03-15 14:39\" \u2192 \"03-15 14:39\" *\/\n            return d.length > 5 ? d.substring(5) : d;\n        }\n\n        html += '<div class=\"td-divider\"><\/div>';\n        html += '<div class=\"geo-section\"><h3 class=\"geo-section__title\">\ud83d\udcc8 \u5f15\u7528\u7387\u8d8b\u52bf \u00b7 ' + GeoAPI.escapeHtml(trendData.target_company) + '<\/h3>'\n              + '<span class=\"geo-section__desc\">\u5171 ' + trendData.report_count + ' \u6b21\u6d4b\u8bd5 \u00b7 ' + shortDate(trendData.first_report_date) + ' \u81f3 ' + shortDate(trendData.last_report_date) + '<\/span><\/div>';\n\n        html += '<div class=\"td-hero\">';\n        html += '<div class=\"td-stat td-stat--primary\"><div class=\"td-stat__val\">' + (latest ? latest.acc : 0) + '%<\/div><div class=\"td-stat__label\">\u6700\u65b0\u5f15\u7528\u7387<\/div><\/div>';\n        html += '<div class=\"td-stat ' + (delta > 0 ? 'td-stat--up' : delta < 0 ? 'td-stat--down' : '') + '\"><div class=\"td-stat__val\">' + (delta > 0 ? '+' : '') + delta + '%<\/div><div class=\"td-stat__label\">\u73af\u6bd4\u53d8\u5316<\/div><\/div>';\n        html += '<div class=\"td-stat ' + (totalDelta > 0 ? 'td-stat--up' : totalDelta < 0 ? 'td-stat--down' : '') + '\"><div class=\"td-stat__val\">' + (totalDelta > 0 ? '+' : '') + totalDelta + '%<\/div><div class=\"td-stat__label\">\u7d2f\u8ba1\u53d8\u5316<\/div><\/div>';\n        html += '<div class=\"td-stat\"><div class=\"td-stat__val\">' + trendData.report_count + '<\/div><div class=\"td-stat__label\">\u6d4b\u8bd5\u6b21\u6570<\/div><\/div>';\n        html += '<\/div>';\n\n        \/* \u56fe\u8868 - \u7528\u7b80\u5316\u65e5\u671f *\/\n        html += '<div class=\"td-chart-wrap\"><div class=\"td-chart-title\">\u603b\u5f15\u7528\u7387\u8d8b\u52bf<\/div><div class=\"td-chart-inner\"><canvas id=\"td-main-chart\"><\/canvas><\/div><\/div>';\n\n        if (Object.keys(trendData.provider_trend || {}).length > 0) {\n            html += '<div class=\"td-chart-wrap\"><div class=\"td-chart-title\">\u5206\u5e73\u53f0\u5f15\u7528\u7387\u8d8b\u52bf<\/div><div class=\"td-chart-inner\"><canvas id=\"td-provider-chart\"><\/canvas><\/div><\/div>';\n        }\n\n        \/* \u8bc4\u7ea7\u53d8\u5316 *\/\n        var improved = changes.filter(function(c){ return c.direction === 'improved'; });\n        var declined = changes.filter(function(c){ return c.direction === 'declined'; });\n        var hasChanges = improved.length > 0 || declined.length > 0 || uncited.length > 0;\n\n        if (hasChanges) {\n            html += '<div class=\"geo-section\"><h3 class=\"geo-section__title\">\ud83d\udd04 \u8bc4\u7ea7\u53d8\u5316\u8ffd\u8e2a<\/h3><span class=\"geo-section__desc\">\u9996\u6b21\u6d4b\u8bd5 vs \u6700\u8fd1\u4e00\u6b21\u6d4b\u8bd5<\/span><\/div>';\n\n            if (improved.length > 0) {\n                html += '<div style=\"margin-bottom:16px;\"><strong style=\"color:var(--geo-success);font-size:14px;\">\u2191 \u63d0\u5347 ' + improved.length + ' \u9879<\/strong><div style=\"margin-top:8px;display:flex;flex-wrap:wrap;gap:6px;\">';\n                improved.forEach(function(c) {\n                    html += '<span class=\"td-change td-change--improved\">' \n                          + GeoAPI.escapeHtml(c.question.substring(0,25)) \n                          + ' <span style=\"opacity:0.7;font-size:11px;\">' + (PROV_SHORT[c.provider]||c.provider) + '<\/span> '\n                          + c.old_grade + ' \u2192 ' + c.new_grade + '<\/span>';\n                });\n                html += '<\/div><\/div>';\n            }\n\n            if (declined.length > 0) {\n                html += '<div style=\"margin-bottom:16px;\"><strong style=\"color:var(--geo-danger);font-size:14px;\">\u2193 \u4e0b\u964d ' + declined.length + ' \u9879<\/strong><div style=\"margin-top:8px;display:flex;flex-wrap:wrap;gap:6px;\">';\n                declined.forEach(function(c) {\n                    html += '<span class=\"td-change td-change--declined\">'\n                          + GeoAPI.escapeHtml(c.question.substring(0,25))\n                          + ' <span style=\"opacity:0.7;font-size:11px;\">' + (PROV_SHORT[c.provider]||c.provider) + '<\/span> '\n                          + c.old_grade + ' \u2192 ' + c.new_grade + '<\/span>';\n                });\n                html += '<\/div><\/div>';\n            }\n\n            if (uncited.length > 0) {\n                \/* \u53bb\u91cd\uff1a\u540c\u4e00\u4e2a\u95ee\u9898\u53ef\u80fd\u5728\u591a\u4e2a\u5e73\u53f0\u90fd\u662f D\uff0c\u53ea\u663e\u793a\u4e00\u6b21 *\/\n                var seen = {};\n                var uniqueUncited = [];\n                uncited.forEach(function(u) {\n                    if (!seen[u.question]) {\n                        seen[u.question] = [];\n                    }\n                    seen[u.question].push(PROV_SHORT[u.provider] || u.provider);\n                });\n\n                html += '<div style=\"margin-bottom:16px;\">'\n                      + '<strong style=\"color:var(--geo-text-muted);font-size:14px;\">\u26a0 \u6301\u7eed\u672a\u8986\u76d6 ' + Object.keys(seen).length + ' \u9898<\/strong>'\n                      + '<div style=\"font-size:12px;color:var(--geo-text-faint);margin:4px 0 8px;\">\u4ee5\u4e0b\u95ee\u9898\u5728\u9996\u6b21\u548c\u6700\u8fd1\u4e00\u6b21\u6d4b\u8bd5\u4e2d\u5747\u4e3a D \u7ea7\uff08\u672a\u88ab\u5f15\u7528\uff09\uff0c\u5efa\u8bae\u4f18\u5148\u4f18\u5316<\/div>'\n                      + '<div style=\"display:flex;flex-wrap:wrap;gap:6px;\">';\n                Object.keys(seen).forEach(function(q) {\n                    html += '<span style=\"display:inline-flex;align-items:center;gap:4px;font-size:13px;font-weight:600;padding:4px 12px;border-radius:20px;background:var(--geo-warn-bg);color:#92400e;\">'\n                          + GeoAPI.escapeHtml(q.substring(0,25))\n                          + ' <span style=\"opacity:0.7;font-size:11px;\">' + seen[q].join('\/') + '<\/span>'\n                          + '<\/span>';\n                });\n                html += '<\/div><\/div>';\n            }\n        }\n\n        \/* \u5386\u53f2\u62a5\u544a\u5217\u8868 *\/\n        if (reports.length > 0) {\n            html += '<div class=\"geo-section\"><h3 class=\"geo-section__title\">\ud83d\udccb \u5386\u53f2\u62a5\u544a<\/h3><\/div>';\n            reports.slice(0, 10).forEach(function(r) {\n                var provText = (r.providers || '').split(',').map(function(p){ return PROV_SHORT[p.trim()] || p.trim(); }).join(' \u00b7 ');\n                html += '<div class=\"td-history-item\">'\n                      + '<span class=\"td-history-item__date\">' + shortDate(GeoAPI.escapeHtml(r.created_at)) + '<\/span>'\n                      + '<span class=\"td-history-item__brand\">' + GeoAPI.escapeHtml(r.target_company) + '<\/span>'\n                      + '<span class=\"td-history-item__meta\">' + (r.question_count||0) + '\u9898 \u00b7 ' + provText + ' \u00b7 A:' + r.grade_a + ' B:' + r.grade_b + ' C:' + r.grade_c + ' D:' + r.grade_d + '<\/span>'\n                      + '<span class=\"td-history-item__acc\" style=\"color:' + accColor(r.overall_acc) + '\">' + r.overall_acc + '%<\/span>'\n                      + '<\/div>';\n            });\n        }\n\n        tdSection.innerHTML = html;\n        tdSection.style.display = 'block';\n\n        \/* \u56fe\u8868\u7528\u7b80\u5316\u65e5\u671f *\/\n        var shortTrend = trend.map(function(t){ return { date: shortDate(t.date), acc: t.acc, cited: t.cited, total: t.total }; });\n\n        setTimeout(function() {\n            renderMainChart(shortTrend);\n            var shortProvTrend = {};\n            Object.keys(trendData.provider_trend || {}).forEach(function(p) {\n                shortProvTrend[p] = trendData.provider_trend[p].map(function(pt) {\n                    return { date: shortDate(pt.date), acc: pt.acc };\n                });\n            });\n            renderProviderChart(shortProvTrend);\n        }, 100);\n    }\n\n\/* =========================================================================\n * \u540c\u65f6\u66ff\u6362 renderMainChart\uff0c\u8ba9\u5b83\u7528\u4f20\u5165\u7684 shortTrend \u6570\u636e\n * ========================================================================= *\/\n\n    function renderMainChart(trend) {\n        var ctx = document.getElementById('td-main-chart');\n        if (!ctx || trend.length === 0) return;\n        if (mainChart) { mainChart.destroy(); mainChart = null; }\n\n        mainChart = new Chart(ctx, {\n            type: 'line',\n            data: {\n                labels: trend.map(function(t){ return t.date; }),\n                datasets: [{\n                    label: '\u5f15\u7528\u7387 (%)',\n                    data: trend.map(function(t){ return t.acc; }),\n                    borderColor: '#00b4b3',\n                    backgroundColor: 'rgba(0,180,179,0.08)',\n                    fill: true, tension: 0.3,\n                    pointRadius: 5, pointBackgroundColor: '#00b4b3', borderWidth: 2,\n                }]\n            },\n            options: {\n                responsive: true, maintainAspectRatio: false,\n                plugins: { legend: { display: false } },\n                scales: {\n                    y: { beginAtZero: true, max: 100, ticks: { callback: function(v){ return v+'%'; } } },\n                    x: { ticks: { maxTicksLimit: 10, font: { size: 11 } } }\n                }\n            }\n        });\n    }\n\n    function renderProviderChart(providerTrend) {\n        var ctx = document.getElementById('td-provider-chart');\n        if (!ctx || Object.keys(providerTrend).length === 0) return;\n        if (providerChart) { providerChart.destroy(); providerChart = null; }\n\n        var colors = GeoAPI.LANG==='en' ? { openai: '#10b981', claude: '#f59e0b', gemini: '#3b82f6' } : { baidu: '#3b82f6', doubao: '#f59e0b', qwen: '#10b981' };\n        var names = {}; GeoAPI.getProviders().forEach(function(p){names[p.value]=p.label;});\n        var datasets = [];\n\n        Object.keys(providerTrend).forEach(function(provider) {\n            datasets.push({\n                label: names[provider] || provider,\n                data: providerTrend[provider].map(function(p){ return p.acc; }),\n                borderColor: colors[provider] || '#6b7280',\n                backgroundColor: 'transparent',\n                tension: 0.3, pointRadius: 4, borderWidth: 2,\n            });\n        });\n\n        var firstProvider = Object.keys(providerTrend)[0];\n        var labels = providerTrend[firstProvider].map(function(p){ return p.date; });\n\n        providerChart = new Chart(ctx, {\n            type: 'line',\n            data: { labels: labels, datasets: datasets },\n            options: {\n                responsive: true, maintainAspectRatio: false,\n                plugins: { legend: { position: 'top', labels: { font: { size: 12 } } } },\n                scales: {\n                    y: { beginAtZero: true, max: 100, ticks: { callback: function(v){ return v+'%'; } } },\n                    x: { ticks: { maxTicksLimit: 10, font: { size: 11 } } }\n                }\n            }\n        });\n    }\n});\n<\/script>\n\n        \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":48884,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-48892","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/pages\/48892","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/comments?post=48892"}],"version-history":[{"count":0,"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/pages\/48892\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/pages\/48884"}],"wp:attachment":[{"href":"https:\/\/www.geobok.com\/en\/wp-json\/wp\/v2\/media?parent=48892"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}