Update src/api/admin.py
Browse files- src/api/admin.py +41 -0
src/api/admin.py
CHANGED
|
@@ -258,6 +258,11 @@ tr:last-child td{{border-bottom:none}}
|
|
| 258 |
<div id="metricsTable" style="overflow-x:auto"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
|
| 259 |
</div>
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
<div class="card">
|
| 262 |
<h2>🔌 System Status</h2>
|
| 263 |
<div id="sysStatus"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
|
|
@@ -346,11 +351,37 @@ async function loadStatus(){{
|
|
| 346 |
}}
|
| 347 |
}}
|
| 348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
loadStats();
|
| 350 |
loadMetrics();
|
| 351 |
loadRAGInfo();
|
|
|
|
| 352 |
loadStatus();
|
| 353 |
setInterval(loadStatus, 30000);
|
|
|
|
| 354 |
</script>
|
| 355 |
</body></html>""")
|
| 356 |
|
|
@@ -436,6 +467,16 @@ async def metrics(request: Request):
|
|
| 436 |
return {"error": str(e)}
|
| 437 |
|
| 438 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
@router.get("/status")
|
| 440 |
async def system_status(request: Request):
|
| 441 |
_require_session(request)
|
|
|
|
| 258 |
<div id="metricsTable" style="overflow-x:auto"><div style="color:#6b7280;font-size:.84rem">Loading…</div></div>
|
| 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>
|
|
|
|
| 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>""")
|
| 387 |
|
|
|
|
| 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)
|