nikeshn commited on
Commit
325bca9
·
verified ·
1 Parent(s): 6227c48

Update src/api/admin.py

Browse files
Files changed (1) hide show
  1. src/api/admin.py +62 -43
src/api/admin.py CHANGED
@@ -259,10 +259,17 @@ tr:last-child td{{border-bottom:none}}
259
  </div>
260
 
261
  <div class="card">
262
- <h2>📋 Recent Queries (last 50)</h2>
 
 
 
 
 
 
263
  <div id="recentTable" style="overflow-x:auto"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
264
  </div>
265
 
 
266
  <div class="card">
267
  <h2>🔌 System Status</h2>
268
  <div id="sysStatus"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
@@ -270,18 +277,62 @@ tr:last-child td{{border-bottom:none}}
270
 
271
  </div>
272
  <script>
 
 
273
  async function loadStats(){{
274
  try{{
275
  const r=await fetch('/admin/metrics');
276
  const d=await r.json();
277
  document.getElementById('statsGrid').innerHTML=`
278
- <div class="stat"><div class="val">${{d.agent_requests||0}}</div><div class="lbl">Agent Requests</div></div>
279
- <div class="stat"><div class="val">${{d.search_requests||0}}</div><div class="lbl">Search Requests</div></div>
280
- <div class="stat"><div class="val">${{d.follow_up_hits||0}}</div><div class="lbl">Follow-up Hits</div></div>
281
- <div class="stat"><div class="val">${{d.search_handoffs||0}}</div><div class="lbl">Snapshots</div></div>
282
- <div class="stat"><div class="val">${{d.feedback_total||0}}</div><div class="lbl">Feedback</div></div>
283
  `;
284
- }}catch(e){{document.getElementById('statsGrid').innerHTML='<span style="color:#dc2626">Analytics unavailable</span>';}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  }}
286
 
287
  async function loadMetrics(){{
@@ -296,7 +347,7 @@ async function loadMetrics(){{
296
  .map(([k,v])=>`<tr><td style="color:#dc2626">${{k}}</td><td>${{v}}</td><td style="color:#6b7280">error</td></tr>`).join('');
297
  document.getElementById('metricsTable').innerHTML=rows
298
  ?`<table><thead><tr><th>Key</th><th>Count</th><th>Type</th></tr></thead><tbody>${{rows}}</tbody></table>`
299
- :'<span style="color:#6b7280;font-size:.84rem">No data yet.</span>';
300
  }}catch(e){{document.getElementById('metricsTable').innerHTML='<span style="color:#dc2626">Could not load metrics</span>';}}
301
  }}
302
 
@@ -351,36 +402,14 @@ async function loadStatus(){{
351
  }}
352
  }}
353
 
354
- async function loadRecentQueries(){{
355
- try{{
356
- const r=await fetch('/admin/queries?limit=50');
357
- const d=await r.json();
358
- const rows=(d.queries||[]).map(q=>`<tr>
359
- <td style="white-space:nowrap">${{q.timestamp||''}}</td>
360
- <td style="max-width:260px;word-break:break-word">${{(q.question||'').substring(0,100)}}</td>
361
- <td>${{q.intent||''}}</td>
362
- <td>${{q.tool||''}}</td>
363
- <td>${{q.model||''}}</td>
364
- <td style="white-space:nowrap">${{(q.response_time||0).toFixed(2)}}s</td>
365
- <td>${{q.result_count||0}}</td>
366
- </tr>`).join('');
367
- document.getElementById('recentTable').innerHTML=rows
368
- ?`<table><thead><tr>
369
- <th>Time</th><th>Question</th><th>Intent</th>
370
- <th>Tool</th><th>Model</th><th>Time</th><th>Results</th>
371
- </tr></thead><tbody>${{rows}}</tbody></table>`
372
- :'<span style="color:#6b7280;font-size:.84rem">No queries logged yet — queries appear after users interact with LibBee.</span>';
373
- }}catch(e){{
374
- document.getElementById('recentTable').innerHTML='<span style="color:#dc2626">Could not load recent queries</span>';
375
- }}
376
- }}
377
-
378
  loadStats();
 
 
379
  loadMetrics();
380
  loadRAGInfo();
381
- loadRecentQueries();
382
  loadStatus();
383
  setInterval(loadStatus, 30000);
 
384
  setInterval(loadRecentQueries, 60000);
385
  </script>
386
  </body></html>""")
@@ -467,16 +496,6 @@ async def metrics(request: Request):
467
  return {"error": str(e)}
468
 
469
 
470
- @router.get("/queries")
471
- async def recent_queries(request: Request, limit: int = 50):
472
- _require_session(request)
473
- try:
474
- from app import get_metrics_service
475
- return {"queries": get_metrics_service().recent_queries(limit=min(limit, 200))}
476
- except Exception as e:
477
- return {"queries": [], "error": str(e)}
478
-
479
-
480
  @router.get("/status")
481
  async def system_status(request: Request):
482
  _require_session(request)
 
259
  </div>
260
 
261
  <div class="card">
262
+ <h2>📈 Cloudflare Analytics (Persistent)</h2>
263
+ <div class="stat-grid" id="cfStatsGrid"><div style="color:#6b7280;font-size:.84rem">Loading from Cloudflare D1…</div></div>
264
+ <div style="margin-top:14px" id="cfToolsTable"><div style="color:#6b7280;font-size:.84rem">Loading tool breakdown…</div></div>
265
+ </div>
266
+
267
+ <div class="card">
268
+ <h2>📋 Recent Queries (Cloudflare D1)</h2>
269
  <div id="recentTable" style="overflow-x:auto"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
270
  </div>
271
 
272
+
273
  <div class="card">
274
  <h2>🔌 System Status</h2>
275
  <div id="sysStatus"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
 
277
 
278
  </div>
279
  <script>
280
+ const WORKER_URL = "https://steep-haze-e1f8.nikeshn.workers.dev";
281
+
282
  async function loadStats(){{
283
  try{{
284
  const r=await fetch('/admin/metrics');
285
  const d=await r.json();
286
  document.getElementById('statsGrid').innerHTML=`
287
+ <div class="stat"><div class="val">${{d.agent_requests||0}}</div><div class="lbl">Requests (session)</div></div>
288
+ <div class="stat"><div class="val">${{d.search_requests||0}}</div><div class="lbl">Searches (session)</div></div>
289
+ <div class="stat"><div class="val">${{d.follow_up_hits||0}}</div><div class="lbl">Follow-ups (session)</div></div>
290
+ <div class="stat"><div class="val">${{d.feedback_total||0}}</div><div class="lbl">Feedback (session)</div></div>
 
291
  `;
292
+ }}catch(e){{document.getElementById('statsGrid').innerHTML='<span style="color:#dc2626">Local metrics unavailable</span>';}}
293
+ }}
294
+
295
+ async function loadCFAnalytics(){{
296
+ try{{
297
+ const r=await fetch(WORKER_URL+'/analytics');
298
+ const d=await r.json();
299
+ if(d.error) throw new Error(d.error);
300
+ document.getElementById('cfStatsGrid').innerHTML=`
301
+ <div class="stat"><div class="val">${{d.total||0}}</div><div class="lbl">Total Queries</div></div>
302
+ <div class="stat"><div class="val">${{d.today||0}}</div><div class="lbl">Today</div></div>
303
+ <div class="stat"><div class="val">${{d.week||0}}</div><div class="lbl">This Week</div></div>
304
+ <div class="stat"><div class="val">${{(d.avg_time||0).toFixed(2)}}s</div><div class="lbl">Avg Response</div></div>
305
+ <div class="stat"><div class="val">${{d.errors||0}}</div><div class="lbl">Errors</div></div>
306
+ `;
307
+ const tools=(d.tools||[]).slice(0,15);
308
+ let rows=tools.map(t=>`<tr><td>${{t.tool_used||"unknown"}}</td><td>${{t.c}}</td></tr>`).join('');
309
+ document.getElementById('cfToolsTable').innerHTML=rows
310
+ ?`<table><thead><tr><th>Intent:Tool</th><th>Count</th></tr></thead><tbody>${{rows}}</tbody></table>`
311
+ :'<span style="color:#6b7280;font-size:.84rem">No data yet.</span>';
312
+ }}catch(e){{
313
+ document.getElementById('cfStatsGrid').innerHTML='<span style="color:#dc2626">Cloudflare D1 unavailable: '+e.message+'</span>';
314
+ }}
315
+ }}
316
+
317
+ async function loadRecentQueries(){{
318
+ try{{
319
+ const r=await fetch(WORKER_URL+'/analytics/recent');
320
+ const d=await r.json();
321
+ if(d.error) throw new Error(d.error);
322
+ const rows=(d.results||[]).map(q=>`<tr>
323
+ <td style="white-space:nowrap;font-size:.74rem">${{q.timestamp||""}}</td>
324
+ <td style="max-width:280px;word-break:break-word">${{(q.question||"").substring(0,100)}}</td>
325
+ <td>${{q.tool_used||""}}</td>
326
+ <td>${{q.model||""}}</td>
327
+ <td style="white-space:nowrap">${{(q.response_time||0).toFixed(2)}}s</td>
328
+ <td>${{q.result_count||0}}</td>
329
+ </tr>`).join('');
330
+ document.getElementById('recentTable').innerHTML=rows
331
+ ?`<table><thead><tr><th>Time</th><th>Question</th><th>Tool</th><th>Model</th><th>Time</th><th>Results</th></tr></thead><tbody>${{rows}}</tbody></table>`
332
+ :'<span style="color:#6b7280;font-size:.84rem">No queries logged yet.</span>';
333
+ }}catch(e){{
334
+ document.getElementById('recentTable').innerHTML='<span style="color:#dc2626">Could not load: '+e.message+'</span>';
335
+ }}
336
  }}
337
 
338
  async function loadMetrics(){{
 
347
  .map(([k,v])=>`<tr><td style="color:#dc2626">${{k}}</td><td>${{v}}</td><td style="color:#6b7280">error</td></tr>`).join('');
348
  document.getElementById('metricsTable').innerHTML=rows
349
  ?`<table><thead><tr><th>Key</th><th>Count</th><th>Type</th></tr></thead><tbody>${{rows}}</tbody></table>`
350
+ :'<span style="color:#6b7280;font-size:.84rem">No session data yet — resets on deploy.</span>';
351
  }}catch(e){{document.getElementById('metricsTable').innerHTML='<span style="color:#dc2626">Could not load metrics</span>';}}
352
  }}
353
 
 
402
  }}
403
  }}
404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  loadStats();
406
+ loadCFAnalytics();
407
+ loadRecentQueries();
408
  loadMetrics();
409
  loadRAGInfo();
 
410
  loadStatus();
411
  setInterval(loadStatus, 30000);
412
+ setInterval(loadCFAnalytics, 60000);
413
  setInterval(loadRecentQueries, 60000);
414
  </script>
415
  </body></html>""")
 
496
  return {"error": str(e)}
497
 
498
 
 
 
 
 
 
 
 
 
 
 
499
  @router.get("/status")
500
  async def system_status(request: Request):
501
  _require_session(request)