Update app.py
Browse files
app.py
CHANGED
|
@@ -1234,7 +1234,7 @@ textarea:focus,input:focus,select:focus{{outline:none;border-color:#003366}}
|
|
| 1234 |
<div class="tab" onclick="st(this,'system')">βοΈ System</div>
|
| 1235 |
</div>
|
| 1236 |
|
| 1237 |
-
<div class="tc active" id="t-analytics"><div
|
| 1238 |
|
| 1239 |
<div class="tc" id="t-behavior">
|
| 1240 |
<div class="card"><h2>π€ Bot Behavior</h2><p style="font-size:.8rem;color:#6b7280;margin-bottom:12px">Changes apply immediately.</p>
|
|
@@ -1281,7 +1281,6 @@ function st(el,t){{document.querySelectorAll('.tab').forEach(e=>e.classList.remo
|
|
| 1281 |
// Fetch analytics from Cloudflare D1
|
| 1282 |
fetch(W+'/analytics').then(r=>r.json()).then(d=>{{
|
| 1283 |
const el=document.getElementById('t-analytics');
|
| 1284 |
-
const fb=(d.feedback||[]); const up=(fb.find(x=>x.feedback==='up')||{{}}).c||0; const down=(fb.find(x=>x.feedback==='down')||{{}}).c||0;
|
| 1285 |
el.innerHTML=`
|
| 1286 |
<div class="grid">
|
| 1287 |
<div class="stat"><div class="n">${{d.total}}</div><div class="l">Total</div></div>
|
|
@@ -1289,9 +1288,6 @@ fetch(W+'/analytics').then(r=>r.json()).then(d=>{{
|
|
| 1289 |
<div class="stat"><div class="n">${{d.week}}</div><div class="l">This Week</div></div>
|
| 1290 |
<div class="stat"><div class="n">${{(d.avg_time||0).toFixed(1)}}s</div><div class="l">Avg Time</div></div>
|
| 1291 |
<div class="stat"><div class="n">${{d.errors}}</div><div class="l">Errors</div></div>
|
| 1292 |
-
<div class="stat"><div class="n">${{up}}</div><div class="l">π Helpful</div></div>
|
| 1293 |
-
<div class="stat"><div class="n">${{down}}</div><div class="l">π Not helpful</div></div>
|
| 1294 |
-
<div class="stat"><div class="n">${{d.click_total||0}}</div><div class="l">Link Clicks</div></div>
|
| 1295 |
</div>
|
| 1296 |
<div class="two">
|
| 1297 |
<div class="card"><h2>Tool Usage</h2><table><tr><th>Tool</th><th>Count</th></tr>${{d.tools.map(t=>`<tr><td>${{t.tool_used}}</td><td>${{t.c}}</td></tr>`).join('')}}</table></div>
|
|
@@ -1301,11 +1297,10 @@ fetch(W+'/analytics').then(r=>r.json()).then(d=>{{
|
|
| 1301 |
<div class="card"><h2>Hourly</h2><canvas id="hc"></canvas></div>
|
| 1302 |
<div class="card"><h2>Daily (14d)</h2><canvas id="dc"></canvas></div>
|
| 1303 |
</div>
|
| 1304 |
-
<div class="card"><h2>Popular (Top 20)</h2><table><tr><th>Question</th><th>Count</th></tr>${{d.popular.map(p=>`<tr><td>${{(p.question||'').substring(0,70)}}</td><td>${{p.c}}</td></tr>`).join('')}}</table></div>
|
| 1305 |
if(d.hourly.length)new Chart(document.getElementById('hc'),{{type:'bar',data:{{labels:d.hourly.map(h=>h.hour+':00'),datasets:[{{label:'Q',data:d.hourly.map(h=>h.c),backgroundColor:'#003366'}}]}},options:{{responsive:true,plugins:{{legend:{{display:false}}}}}}}});
|
| 1306 |
if(d.daily.length)new Chart(document.getElementById('dc'),{{type:'line',data:{{labels:d.daily.map(x=>(x.day||'').slice(5)),datasets:[{{label:'Q',data:d.daily.map(x=>x.c),borderColor:'#003366',backgroundColor:'rgba(0,51,102,0.1)',fill:true,tension:.3}}]}},options:{{responsive:true,plugins:{{legend:{{display:false}}}}}}}});
|
| 1307 |
}}).catch(e=>{{document.getElementById('t-analytics').innerHTML='<div class="card" style="color:#dc2626">Failed to load analytics: '+e.message+'<br>Make sure D1 is initialized: <a href="'+W+'/analytics/init" target="_blank">Click here to init DB</a></div>';}});
|
| 1308 |
-
fetch(W+'/analytics/feedback').then(r=>r.json()).then(d=>{{ const el=document.getElementById('feedback-panel'); if(!el) return; el.innerHTML='<div class="two"><div class="card"><h2>π Top weak questions</h2><table><tr><th>Question</th><th>Count</th></tr>'+((d.low||[]).map(x=>`<tr><td>${{(x.question||'').substring(0,80)}}</td><td>${{x.c}}</td></tr>`).join('')||'<tr><td colspan="2">No negative feedback yet</td></tr>')+'</table></div><div class="card"><h2>π Top clicks</h2><table><tr><th>Type</th><th>Label</th><th>Count</th></tr>'+((d.clicks||[]).slice(0,15).map(x=>`<tr><td>${{x.kind||''}}</td><td>${{(x.label||'').substring(0,60)}}</td><td>${{x.c}}</td></tr>`).join('')||'<tr><td colspan="3">No click data yet</td></tr>')+'</table></div></div><div class="card"><h2>Recent feedback</h2><table><tr><th>Time</th><th>Feedback</th><th>Question</th><th>Tool</th></tr>'+((d.recent||[]).slice(0,20).map(x=>`<tr><td>${{(x.timestamp||'').substring(0,19)}}</td><td>${{x.feedback==='up'?'π':'π'}}</td><td>${{(x.question||'').substring(0,80)}}</td><td>${{x.tool_used||''}}</td></tr>`).join('')||'<tr><td colspan="4">No feedback yet</td></tr>')+'</table></div>'; }}).catch(()=>{{}});
|
| 1309 |
|
| 1310 |
// Fetch recent queries
|
| 1311 |
fetch(W+'/analytics/recent').then(r=>r.json()).then(d=>{{
|
|
@@ -1331,9 +1326,6 @@ async function rebuildIdx(){{
|
|
| 1331 |
loadStatus(); // refresh status after rebuild
|
| 1332 |
}}
|
| 1333 |
|
| 1334 |
-
function downloadAnalytics(){{ window.open(W+'/analytics/export.csv','_blank'); }}
|
| 1335 |
-
async function clearOldData(){{ const days=prompt('Delete records older than how many days?', '90'); if(!days) return; if(!confirm('Delete analytics, feedback, and clicks older than '+days+' days?')) return; const r=await fetch(W+'/analytics/clear-old',{{method:'POST',headers:{{'Content-Type':'application/json'}},body:JSON.stringify({{days:Number(days)}})}}); const res=await r.json(); const s=document.getElementById('sys')||document.getElementById('sv'); s.className=res.status==='ok'?'st ok':'st er'; s.style.display='block'; s.textContent=res.status==='ok' ? `β
Deleted old data: Q ${{res.deleted.queries}}, F ${{res.deleted.feedback}}, C ${{res.deleted.clicks}}` : 'β '+(res.error?.message||JSON.stringify(res)); setTimeout(()=>location.reload(),1200); }}
|
| 1336 |
-
|
| 1337 |
async function restartSpace(){{
|
| 1338 |
if(!confirm('Restart the HF Space? The service will be unavailable for ~30-60 seconds.')) return;
|
| 1339 |
const s=document.getElementById('sys');s.className='st ok';s.textContent='β»οΈ Restarting...';s.style.display='block';
|
|
|
|
| 1234 |
<div class="tab" onclick="st(this,'system')">βοΈ System</div>
|
| 1235 |
</div>
|
| 1236 |
|
| 1237 |
+
<div class="tc active" id="t-analytics"><div id="loading">Loading analytics from Cloudflare D1β¦</div></div>
|
| 1238 |
|
| 1239 |
<div class="tc" id="t-behavior">
|
| 1240 |
<div class="card"><h2>π€ Bot Behavior</h2><p style="font-size:.8rem;color:#6b7280;margin-bottom:12px">Changes apply immediately.</p>
|
|
|
|
| 1281 |
// Fetch analytics from Cloudflare D1
|
| 1282 |
fetch(W+'/analytics').then(r=>r.json()).then(d=>{{
|
| 1283 |
const el=document.getElementById('t-analytics');
|
|
|
|
| 1284 |
el.innerHTML=`
|
| 1285 |
<div class="grid">
|
| 1286 |
<div class="stat"><div class="n">${{d.total}}</div><div class="l">Total</div></div>
|
|
|
|
| 1288 |
<div class="stat"><div class="n">${{d.week}}</div><div class="l">This Week</div></div>
|
| 1289 |
<div class="stat"><div class="n">${{(d.avg_time||0).toFixed(1)}}s</div><div class="l">Avg Time</div></div>
|
| 1290 |
<div class="stat"><div class="n">${{d.errors}}</div><div class="l">Errors</div></div>
|
|
|
|
|
|
|
|
|
|
| 1291 |
</div>
|
| 1292 |
<div class="two">
|
| 1293 |
<div class="card"><h2>Tool Usage</h2><table><tr><th>Tool</th><th>Count</th></tr>${{d.tools.map(t=>`<tr><td>${{t.tool_used}}</td><td>${{t.c}}</td></tr>`).join('')}}</table></div>
|
|
|
|
| 1297 |
<div class="card"><h2>Hourly</h2><canvas id="hc"></canvas></div>
|
| 1298 |
<div class="card"><h2>Daily (14d)</h2><canvas id="dc"></canvas></div>
|
| 1299 |
</div>
|
| 1300 |
+
<div class="card"><h2>Popular (Top 20)</h2><table><tr><th>Question</th><th>Count</th></tr>${{d.popular.map(p=>`<tr><td>${{(p.question||'').substring(0,70)}}</td><td>${{p.c}}</td></tr>`).join('')}}</table></div>`;
|
| 1301 |
if(d.hourly.length)new Chart(document.getElementById('hc'),{{type:'bar',data:{{labels:d.hourly.map(h=>h.hour+':00'),datasets:[{{label:'Q',data:d.hourly.map(h=>h.c),backgroundColor:'#003366'}}]}},options:{{responsive:true,plugins:{{legend:{{display:false}}}}}}}});
|
| 1302 |
if(d.daily.length)new Chart(document.getElementById('dc'),{{type:'line',data:{{labels:d.daily.map(x=>(x.day||'').slice(5)),datasets:[{{label:'Q',data:d.daily.map(x=>x.c),borderColor:'#003366',backgroundColor:'rgba(0,51,102,0.1)',fill:true,tension:.3}}]}},options:{{responsive:true,plugins:{{legend:{{display:false}}}}}}}});
|
| 1303 |
}}).catch(e=>{{document.getElementById('t-analytics').innerHTML='<div class="card" style="color:#dc2626">Failed to load analytics: '+e.message+'<br>Make sure D1 is initialized: <a href="'+W+'/analytics/init" target="_blank">Click here to init DB</a></div>';}});
|
|
|
|
| 1304 |
|
| 1305 |
// Fetch recent queries
|
| 1306 |
fetch(W+'/analytics/recent').then(r=>r.json()).then(d=>{{
|
|
|
|
| 1326 |
loadStatus(); // refresh status after rebuild
|
| 1327 |
}}
|
| 1328 |
|
|
|
|
|
|
|
|
|
|
| 1329 |
async function restartSpace(){{
|
| 1330 |
if(!confirm('Restart the HF Space? The service will be unavailable for ~30-60 seconds.')) return;
|
| 1331 |
const s=document.getElementById('sys');s.className='st ok';s.textContent='β»οΈ Restarting...';s.style.display='block';
|