true, 'module' => 'DSH-PREDICT', 'version' => '1.0-opus-18avr', 'ts' => date('c'), 'sources' => [] ]; // Helper: safe internal curl function _fetch($url, $timeout = 5) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, ]); $r = curl_exec($ch); $err = curl_error($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($err || $code !== 200) return ['ok' => false, 'error' => $err ?: "http_$code"]; $j = json_decode($r, true); return $j ?: ['ok' => false, 'raw' => substr((string)$r, 0, 300)]; } // === LOAD prediction (regression) === $heal = _fetch('http://127.0.0.1/api/opus-arch-predictive-heal.php', 5); $out['sources']['heal'] = ['ok' => true]; if (isset($heal['predicted_next_hour'])) { $out['load'] = [ 'current_metric' => $heal['metric'] ?? 'load', 'predicted_next_hour' => $heal['predicted_next_hour'] ?? null, 'threshold' => $heal['threshold'] ?? 5, 'alert' => $heal['alert'] ?? false, 'regression_slope' => $heal['regression']['slope'] ?? null, 'n_samples' => $heal['n_samples'] ?? null, 'recommended_actions' => $heal['recommended_actions'] ?? [], ]; } else { $out['sources']['heal']['ok'] = false; $out['sources']['heal']['error'] = $heal['error'] ?? 'no data'; } // === CACHE predict stats === $cache = _fetch('http://127.0.0.1/api/opus5-predictive-cache.php', 5); $out['sources']['cache'] = ['ok' => true]; if (isset($cache['stats'])) { $out['cache'] = [ 'gets' => $cache['stats']['gets'] ?? 0, 'hits' => $cache['stats']['hits'] ?? 0, 'misses' => $cache['stats']['misses'] ?? 0, 'hit_rate_pct' => $cache['stats']['hit_rate_pct'] ?? 0, 'patterns_count' => $cache['patterns_count'] ?? 0, 'top_patterns' => array_slice((array)($cache['top_5_patterns'] ?? []), 0, 5, true), ]; } else { $out['sources']['cache']['ok'] = false; $out['sources']['cache']['error'] = $cache['error'] ?? 'no data'; } // === Summary health badge === $load_p = $out['load']['predicted_next_hour'] ?? 0; $thr = $out['load']['threshold'] ?? 5; $hit = $out['cache']['hit_rate_pct'] ?? 0; $out['badge'] = [ 'status' => ($load_p < $thr && !($out['load']['alert'] ?? false)) ? 'GREEN' : 'RED', 'label' => sprintf('Load %.2f / Cache %d%%', $load_p, $hit), 'color' => ($load_p < $thr * 0.7) ? '#10b981' : (($load_p < $thr) ? '#f59e0b' : '#ef4444'), ]; $out['elapsed_ms'] = round((microtime(true) - $started) * 1000, 1); echo json_encode($out, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);