PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
} catch (Exception $e) { $error = $e->getMessage(); }
$stats = ['total'=>0,'today'=>0,'avg_latency'=>0,'thumbs_up'=>0,'thumbs_down'=>0,'models'=>[]];
$todayRows = []; $recentRows = []; $feedbackRows = []; $topQueries = [];
if ($db) {
try {
$today = date('Y-m-d');
$r = $db->query("SELECT COUNT(*) as t, ROUND(AVG(latency_ms)) as a FROM ask_logs WHERE ok=1")->fetch();
$stats['total'] = (int)($r['t']??0);
$stats['avg_latency'] = (int)($r['a']??0);
$stmt = $db->prepare("SELECT COUNT(*) as c FROM ask_logs WHERE ts LIKE ?");
$stmt->execute([$today . '%']);
$stats['today'] = (int)($stmt->fetch()['c'] ?? 0);
foreach ($db->query("SELECT verdict, COUNT(*) as c FROM feedback GROUP BY verdict")->fetchAll() as $r) {
if ($r['verdict']==='up') $stats['thumbs_up'] = (int)$r['c'];
if ($r['verdict']==='down') $stats['thumbs_down'] = (int)$r['c'];
}
$stats['models'] = $db->query("SELECT model, COUNT(*) as c FROM ask_logs GROUP BY model ORDER BY c DESC LIMIT 5")->fetchAll();
$stmt = $db->prepare("SELECT id,ts,query,answer,latency_ms,model,scope,ok,COALESCE(topk_json,'[]') as topk_json FROM ask_logs WHERE ts LIKE ? ORDER BY ts DESC LIMIT 100");
$stmt->execute([$today . '%']);
$todayRows = $stmt->fetchAll();
$stmt = $db->prepare("SELECT id,ts,query,answer,latency_ms,model,scope,ok,COALESCE(topk_json,'[]') as topk_json FROM ask_logs WHERE ts NOT LIKE ? ORDER BY ts DESC LIMIT 200");
$stmt->execute([$today . '%']);
$recentRows = $stmt->fetchAll();
$feedbackRows = $db->query("SELECT id,ts,verdict,query,note,model,scope FROM feedback ORDER BY ts DESC LIMIT 50")->fetchAll();
$topQueries = $db->query("SELECT normalized,COUNT(*) as hits,ROUND(AVG(latency_ms)) as avg_ms FROM ask_logs WHERE normalized!='' AND ok=1 GROUP BY normalized ORDER BY hits DESC LIMIT 10")->fetchAll();
} catch (Exception $e) { $error = $e->getMessage(); }
}
function fmtLatency(int $ms): string {
return $ms < 1000 ? "{$ms}ms" : round($ms/1000,1)."s";
}
function fmtTs(string $ts): string {
try { return (new DateTime($ts))->format('d M H:i:s'); } catch(Exception $e) { return $ts; }
}
function trunc(string $s, int $n=80): string {
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
return strlen($s)<=$n ? $s : substr($s,0,$n).'…';
}
function sources(string $j): string {
$items = json_decode($j,true) ?: [];
if (!$items) return '—';
$out=[];
foreach(array_slice($items,0,3) as $s)
$out[] = "".htmlspecialchars($s['id']??'')."";
return implode(' ',$out);
}
$totalFb = $stats['thumbs_up']+$stats['thumbs_down'];
$satPct = $totalFb > 0 ? round($stats['thumbs_up']/$totalFb*100) : null;
?>
No data yet.
| Time | Query | Latency | Scope | Top sources | Model |
|---|---|---|---|---|---|
| No queries yet today | |||||
| = fmtTs($row['ts']) ?> |
= trunc($row['query']??'', 100) ?>
Show answer= htmlspecialchars($row['answer']??'') ?>
|
= fmtLatency($ms) ?> | = htmlspecialchars($row['scope']??'—') ?> | = sources($row['topk_json']) ?> | = htmlspecialchars($row['model']??'—') ?> |
| Time | Verdict | Query | Note | Model | Scope |
|---|---|---|---|---|---|
| = fmtTs($row['ts']) ?> | = $row['verdict']==='up' ? ' Helpful' : ' Not helpful' ?> |
= trunc($row['query']??'', 100) ?>
Show answer= htmlspecialchars($row['answer']??'') ?>
|
= trunc($row['note']??'',80) ?> | = htmlspecialchars($row['model']??'—') ?> | = htmlspecialchars($row['scope']??'—') ?> |
| Date / Time | Query | Latency | Scope | Top sources | Model |
|---|---|---|---|---|---|
| No previous queries | |||||
| = fmtTs($row['ts']) ?> |
= trunc($row['query']??'', 100) ?>
Show answer= htmlspecialchars($row['answer']??'') ?>
|
= fmtLatency($ms) ?> | = htmlspecialchars($row['scope']??'—') ?> | = sources($row['topk_json']) ?> | = htmlspecialchars($row['model']??'—') ?> |