Files
html/api/learning-analytics.php
Opus Wire 160b2a57bd
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
feat(learning-dashboard-v22): analytics apprentissage universel · 24h window
NEW:
- /learning-dashboard.html (8.2KB) · UX premium dashboard
- /api/learning-analytics.php (3.3KB) · PG aggregator
- dashboards-index enriched · section Learning & Analytics

METRICS LIVE (24h window):
- Hero: total_learned, success_pct, bots_count, conversations, sessions, avg_ms
- Per chatbot: total queries, success rate, progress bar colored
- Intents distribution: count, success rate per intent
- Latest 10 learnings: time, chatbot, intent, outcome badge

AUTO-REFRESH 15s · fetch /api/learning-analytics.php
Color-coded cards: excellent (>=90pct green), good (>=70 blue), ok (>=50 orange), low (<50 red)

Data sources:
- ai_learning_log (table v20) avec experience jsonb + outcome_success
- wevia_conversations (table v18) conversations count + sessions distinct

Validation LIVE:
- HTTP 200 on /learning-dashboard.html (9870b served)
- API returns structured JSON in <200ms
- 6 rows learned · 83pct success · 2 bots used (wevia-master 100pct, blade-ai 0pct)
- 10 conversations · 9 sessions

Doctrine:
- Point verite unique (1 dashboard = tout apprentissage)
- UX PREMIUM (gradients, badges colorés, progress bars, refresh pulse)
- RELIER toutes pages (dashboards-index -> learning-dashboard)
- Zero regression
- Additif pur
2026-04-22 05:18:23 +02:00

90 lines
3.2 KiB
PHP

<?php
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
try {
$pg = @pg_connect("host=127.0.0.1 dbname=adx_system user=admin password=admin123 connect_timeout=3");
if (!$pg) throw new Exception("PG connect failed");
// Summary
$r = pg_query($pg, "SELECT
COUNT(*)::int as total_learned,
SUM(CASE WHEN outcome_success THEN 1 ELSE 0 END)::int as success_total,
COUNT(DISTINCT (experience->>'chatbot'))::int as bots_count,
COALESCE(ROUND(AVG((experience->>'total_ms')::int))::int, 0) as avg_ms
FROM ai_learning_log
WHERE learned_at > NOW() - interval '24 hours'");
$summary = pg_fetch_assoc($r);
$summary['success_pct'] = $summary['total_learned'] > 0
? round(100.0 * $summary['success_total'] / $summary['total_learned'])
: 0;
// Conversations count
$r = pg_query($pg, "SELECT COUNT(*)::int as total, COUNT(DISTINCT session_id)::int as sessions FROM wevia_conversations");
$c = pg_fetch_assoc($r);
$summary['conversations'] = (int)$c['total'];
$summary['sessions'] = (int)$c['sessions'];
// Per chatbot (24h)
$r = pg_query($pg, "SELECT
experience->>'chatbot' as chatbot,
COUNT(*)::int as total,
SUM(CASE WHEN outcome_success THEN 1 ELSE 0 END)::int as success
FROM ai_learning_log
WHERE learned_at > NOW() - interval '24 hours' AND experience->>'chatbot' IS NOT NULL
GROUP BY experience->>'chatbot'
ORDER BY total DESC");
$chatbots = [];
while ($row = pg_fetch_assoc($r)) {
$row['total'] = (int)$row['total'];
$row['success'] = (int)$row['success'];
$row['success_pct'] = $row['total'] > 0 ? round(100.0 * $row['success'] / $row['total']) : 0;
$chatbots[] = $row;
}
// Intents distribution
$r = pg_query($pg, "SELECT
experience->>'intent' as intent,
COUNT(*)::int as count,
SUM(CASE WHEN outcome_success THEN 1 ELSE 0 END)::int as success
FROM ai_learning_log
WHERE learned_at > NOW() - interval '24 hours'
GROUP BY experience->>'intent'
ORDER BY count DESC");
$intents = [];
while ($row = pg_fetch_assoc($r)) {
$row['count'] = (int)$row['count'];
$row['success'] = (int)$row['success'];
$row['rate'] = $row['count'] > 0 ? round(100.0 * $row['success'] / $row['count']) : 0;
$intents[] = $row;
}
// Latest 10
$r = pg_query($pg, "SELECT
learned_at,
experience->>'chatbot' as chatbot,
experience->>'intent' as intent,
outcome_success as outcome
FROM ai_learning_log
ORDER BY learned_at DESC LIMIT 10");
$latest = [];
while ($row = pg_fetch_assoc($r)) {
$row['outcome'] = $row['outcome'] === 't';
$latest[] = $row;
}
pg_close($pg);
echo json_encode([
'ts' => date('c'),
'window' => '24h',
'summary' => $summary,
'chatbots' => $chatbots,
'intents' => $intents,
'latest' => $latest,
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}