diff --git a/api/web-ia-health.php b/api/web-ia-health.php index a0d28523e..bc2dcf19e 100644 --- a/api/web-ia-health.php +++ b/api/web-ia-health.php @@ -1,12 +1,11 @@ true, "ts" => date("c"), "sections" => []]; -// === SECTION 1: BLADE PC YACINE === +// === SECTION 1: BLADE === $hb_file = "/var/www/html/api/blade-tasks/heartbeat.json"; $blade = ["online" => false, "heartbeat_age_s" => -1, "ip" => null, "agent_version" => null, "recommendation" => null]; if (file_exists($hb_file)) { @@ -19,79 +18,106 @@ if (file_exists($hb_file)) { $blade["online"] = $blade["heartbeat_age_s"] >= 0 && $blade["heartbeat_age_s"] < 120; } } -if ($blade["online"]) { - $blade["status_label"] = "ACTIF"; - $blade["color"] = "teal"; - $blade["recommendation"] = "OK - Yacine accessible. Chrome sessions cookies persistants."; -} elseif ($blade["heartbeat_age_s"] < 0) { - $blade["status_label"] = "JAMAIS VU"; - $blade["color"] = "red"; - $blade["recommendation"] = "Installer/demarrer agent Blade v2.0 sur PC Yacine"; -} elseif ($blade["heartbeat_age_s"] < 600) { - $blade["status_label"] = "RECENT SILENCE"; - $blade["color"] = "orange"; - $blade["recommendation"] = "PC Yacine probablement en veille courte. Bouger la souris ou reveiller."; -} else { - $blade["status_label"] = "LONGUE VEILLE"; - $blade["color"] = "red"; - $blade["recommendation"] = "PC Yacine eteint ou mode avion. Verifier: 1) alim + wifi 2) agent Blade lance 3) Chrome foreground 4) mode performance (pas economie batterie)"; -} +if ($blade["online"]) { $blade["status_label"]="ACTIF"; $blade["color"]="teal"; $blade["recommendation"]="OK - Yacine accessible. Chrome sessions cookies persistants."; } +elseif ($blade["heartbeat_age_s"] < 0) { $blade["status_label"]="JAMAIS VU"; $blade["color"]="red"; $blade["recommendation"]="Installer/demarrer agent Blade v2.0 sur PC Yacine"; } +elseif ($blade["heartbeat_age_s"] < 600) { $blade["status_label"]="RECENT SILENCE"; $blade["color"]="orange"; $blade["recommendation"]="PC probablement en veille courte. Auto-harden s'activera au retour."; } +else { $blade["status_label"]="LONGUE VEILLE"; $blade["color"]="red"; $blade["recommendation"]="PC eteint ou mode avion. Auto-fallback CDP local actif."; } $out["sections"]["blade"] = $blade; -// === SECTION 2: TASKS STATS === +// === SECTION 2: TASKS STATS + TIMELINE 24h === $tasks = glob("/var/www/html/api/blade-tasks/task_*.json"); -$stats = ["total" => count($tasks), "pending" => 0, "dispatched" => 0, "done" => 0, "failed" => 0, "failed_timeout" => 0, "stale" => 0]; +$stats = ["total"=>count($tasks),"pending"=>0,"dispatched"=>0,"done"=>0,"failed"=>0,"failed_timeout"=>0,"stale"=>0]; $now = time(); +$bucket_hours = 24; +$buckets = array_fill(0, $bucket_hours, ["done"=>0,"failed"=>0,"pending"=>0]); +$recent_tasks = []; foreach ($tasks as $t) { $d = @json_decode(file_get_contents($t), true); if (!$d) continue; $s = $d["status"] ?? "?"; if (isset($stats[$s])) $stats[$s]++; + $cts = strtotime($d["created"] ?? "") ?: 0; + if ($cts && ($now - $cts) < ($bucket_hours * 3600)) { + $hrs_ago = floor(($now - $cts) / 3600); + $idx = $bucket_hours - 1 - $hrs_ago; + if ($idx >= 0 && $idx < $bucket_hours) { + if ($s === "done") $buckets[$idx]["done"]++; + elseif (strpos($s, "failed") === 0) $buckets[$idx]["failed"]++; + elseif ($s === "dispatched" || $s === "pending") $buckets[$idx]["pending"]++; + } + } if ($s === "dispatched") { $da = strtotime($d["dispatched_at"] ?? ""); if ($da && ($now - $da) > 90) $stats["stale"]++; } + if ($cts && count($recent_tasks) < 10) $recent_tasks[] = [ + "id"=>$d["id"]??"?","status"=>$s,"label"=>$d["label"]??"?", + "cmd"=>substr($d["cmd"]??"",0,60),"age_s"=>$now-$cts,"created"=>$d["created"]??"" + ]; } +usort($recent_tasks, fn($a,$b)=>$a["age_s"]-$b["age_s"]); +$recent_tasks = array_slice($recent_tasks, 0, 10); $out["sections"]["tasks"] = $stats; +$out["sections"]["tasks_timeline_24h"] = $buckets; +$out["sections"]["tasks_recent"] = $recent_tasks; -// === SECTION 3: CDP LOCAL S204 8 PROVIDERS === +// === SECTION 3: CDP LOCAL === $cdp = []; $ch = curl_init("http://127.0.0.1/api/cdp-status.php"); -curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, - CURLOPT_HTTPHEADER => ["Host: weval-consulting.com"] -]); -$cdp_raw = curl_exec($ch); -curl_close($ch); -if ($cdp_raw) { - $cdp_data = @json_decode($cdp_raw, true); - if ($cdp_data && isset($cdp_data["providers"])) { - $cdp = $cdp_data; - } -} -$out["sections"]["cdp_local"] = $cdp ?: ["err" => "cdp_api_down"]; +curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>5,CURLOPT_HTTPHEADER=>["Host: weval-consulting.com"]]); +$cdp_raw = curl_exec($ch); curl_close($ch); +if ($cdp_raw) { $cdp_data = @json_decode($cdp_raw, true); if ($cdp_data && isset($cdp_data["providers"])) $cdp = $cdp_data; } +$out["sections"]["cdp_local"] = $cdp ?: ["err"=>"cdp_api_down"]; -// === SECTION 4: INTENTS AVAILABLE === +// === SECTION 4: INTENTS === $nl_count = 0; $nl_f = "/opt/wevia-brain/priority-intents-nl.json"; -if (file_exists($nl_f)) { - $nl_data = @json_decode(file_get_contents($nl_f), true) ?: []; - $nl_count = count($nl_data); -} +if (file_exists($nl_f)) $nl_count = count(@json_decode(file_get_contents($nl_f), true) ?: []); $opus4_count = count(glob("/var/www/html/api/wired-pending/intent-opus4-*.php") ?: []); -$out["sections"]["intents"] = ["nl_priority" => $nl_count, "opus4_wired" => $opus4_count, "total" => $nl_count + $opus4_count]; +$out["sections"]["intents"] = ["nl_priority"=>$nl_count,"opus4_wired"=>$opus4_count,"total"=>$nl_count+$opus4_count]; -// === SECTION 5: RECOMMENDATIONS ZERO MANUEL === +// === SECTION 5: S204 METRICS === +$metrics = []; +$load = @file_get_contents("/proc/loadavg"); +if ($load) { $p = explode(" ", $load); $metrics["load"] = ["1m"=>floatval($p[0]??0),"5m"=>floatval($p[1]??0),"15m"=>floatval($p[2]??0)]; } +$df = @shell_exec("df -B1 / | tail -1"); +if ($df) { $p = preg_split("/\s+/", trim($df)); $metrics["disk"] = ["total_gb"=>round($p[1]/1e9,1),"used_gb"=>round($p[2]/1e9,1),"avail_gb"=>round($p[3]/1e9,1),"pct"=>intval(rtrim($p[4],"%"))]; } +$mem = @file_get_contents("/proc/meminfo"); +if ($mem) { preg_match("/MemTotal:\s+(\d+)/",$mem,$mt); preg_match("/MemAvailable:\s+(\d+)/",$mem,$ma); + if ($mt && $ma) $metrics["mem"] = ["total_gb"=>round($mt[1]/1e6,1),"avail_gb"=>round($ma[1]/1e6,1),"used_pct"=>100-intval($ma[1]*100/$mt[1])]; } +$metrics["chromes"] = intval(trim(@shell_exec("pgrep -cf 'remote-debugging-port' 2>/dev/null") ?: "0")); +$metrics["fpm"] = intval(trim(@shell_exec("pgrep -c php-fpm 2>/dev/null") ?: "0")); +$out["sections"]["s204"] = $metrics; + +// === SECTION 6: RECENT JOBS (async-exec) === +$jobs = glob("/tmp/wevia-job-*.log"); +usort($jobs, fn($a,$b)=>filemtime($b)-filemtime($a)); +$recent_jobs = []; +foreach (array_slice($jobs, 0, 8) as $j) { + $size = filesize($j); + $mt = filemtime($j); + $id = basename($j, ".log"); + $content = $size > 0 ? @file_get_contents($j, false, null, 0, 400) : ""; + $recent_jobs[] = ["id"=>$id,"age_s"=>$now-$mt,"size"=>$size,"preview"=>substr($content,0,300)]; +} +$out["sections"]["jobs_recent"] = $recent_jobs; + +// === SECTION 7: RECOMMENDATIONS === $recs = []; if (!$blade["online"]) { - $recs[] = ["priority" => "high", "text" => "Fallback: utiliser ask__web (CDP local S204)"]; - if (isset($cdp["summary"]["running"]) && $cdp["summary"]["running"] == 0) { - $recs[] = ["priority" => "high", "text" => "Lancer 'launch_chromes_all' dans WEVIA chat pour activer les 8 profiles CDP"]; - } + $recs[] = ["priority"=>"high","text"=>"Blade offline: auto-fallback CDP local actif. Lancez launch_chromes_all si pas encore fait."]; +} else { + $recs[] = ["priority"=>"low","text"=>"Blade actif: ask_blade_ pret. Auto-harden se lance toutes les 5min."]; } -if ($stats["stale"] > 0) $recs[] = ["priority" => "med", "text" => "Cron auto recovery 2min traite. Taper 'blade_tasks_recover' pour force reset immediat"]; -if ($blade["online"] && isset($cdp["summary"]["running"]) && $cdp["summary"]["running"] > 0) { - $recs[] = ["priority" => "low", "text" => "TOUT OPERATIONNEL: ask_blade_ ET ask__web disponibles"]; +if ($stats["stale"] > 0) $recs[] = ["priority"=>"med","text"=>"{$stats['stale']} tasks stale. Cron recovery 2min traite. Force: blade_tasks_recover"]; +if (isset($cdp["summary"]["running"]) && $cdp["summary"]["running"] == 0) { + $recs[] = ["priority"=>"med","text"=>"0/8 CDP local running. Tapez 'launch_chromes_all' pour activer fallback."]; +} +if (isset($metrics["load"]["5m"]) && $metrics["load"]["5m"] > 40) { + $recs[] = ["priority"=>"med","text"=>"Load S204 haut ({$metrics['load']['5m']}). Tapez 'disaster_clean all' pour decharger."]; +} +if (isset($metrics["disk"]["pct"]) && $metrics["disk"]["pct"] > 85) { + $recs[] = ["priority"=>"high","text"=>"Disk S204 a {$metrics['disk']['pct']}%. Tapez 'deep_clean' pour cleanup agressif."]; } $out["sections"]["recommendations"] = $recs; diff --git a/web-ia-health.html b/web-ia-health.html index f8948c34c..4d62df6e7 100644 --- a/web-ia-health.html +++ b/web-ia-health.html @@ -3,114 +3,170 @@ -WEVIA Web IA Health — Zero Manuel Dashboard +WEVIA Web IA Health — Command Center +
-
WEVIA · Web IA Health
-
+
WEVIA · Command Center
+
Blade: — CDP: — Tasks: — Intents: — + Load: —
-
- auto-refresh 30s +
+ auto-refresh 30s - VNC Picker + VNC WEVIA Chat
-
-
Chargement...
-
+
Chargement...
+
+