168 lines
5.5 KiB
PHP
168 lines
5.5 KiB
PHP
<?php
|
|
// V118 KPI UNIFIED - Single source-of-truth endpoint for all dashboards
|
|
// Consolidates source-of-truth.json + nonreg-latest + token-health-cache + docker live
|
|
// Cache 60s for performance
|
|
// UX premium doctrine 60 - zero doublon zero divergence
|
|
header("Content-Type: application/json");
|
|
header("Access-Control-Allow-Origin: *");
|
|
header("Cache-Control: public, max-age=60");
|
|
|
|
$cache_file = "/tmp/kpi-unified-cache.json";
|
|
$cache_ttl = 60;
|
|
$force = !empty($_GET["force"]);
|
|
|
|
// Try cache first
|
|
if (!$force && is_readable($cache_file)) {
|
|
$age = time() - filemtime($cache_file);
|
|
if ($age < $cache_ttl) {
|
|
$cached = @json_decode(@file_get_contents($cache_file), true);
|
|
if (is_array($cached)) {
|
|
$cached["cache_hit"] = true;
|
|
$cached["cache_age_sec"] = $age;
|
|
echo json_encode($cached, JSON_PRETTY_PRINT);
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Build from sources (honest, no fake)
|
|
$sot = [];
|
|
if (is_readable("/var/www/html/api/source-of-truth.json")) {
|
|
$sot = @json_decode(@file_get_contents("/var/www/html/api/source-of-truth.json"), true) ?: [];
|
|
}
|
|
|
|
$nonreg = [];
|
|
if (is_readable("/var/www/html/api/nonreg-latest.json")) {
|
|
$nonreg = @json_decode(@file_get_contents("/var/www/html/api/nonreg-latest.json"), true) ?: [];
|
|
}
|
|
|
|
$tokens = [];
|
|
if (is_readable("/tmp/token-health-cache.json")) {
|
|
$tokens = @json_decode(@file_get_contents("/tmp/token-health-cache.json"), true) ?: [];
|
|
}
|
|
|
|
// Docker running count (live via shell)
|
|
$docker_count = 0;
|
|
$out = @shell_exec("docker ps 2>/dev/null | tail -n +2 | wc -l");
|
|
if ($out !== null) $docker_count = (int)trim($out);
|
|
if ($docker_count === 0 && isset($sot["docker_running"])) $docker_count = (int)$sot["docker_running"];
|
|
|
|
// V83 summary (via architecture_quality)
|
|
$v83 = ["kpis" => null, "ok" => null, "warn" => null, "fail" => null, "complete_pct" => null];
|
|
if (is_readable("/var/www/html/api/v83-business-kpi-latest.json")) {
|
|
$v83_raw = @json_decode(@file_get_contents("/var/www/html/api/v83-business-kpi-latest.json"), true);
|
|
if ($v83_raw && isset($v83_raw["summary"])) {
|
|
$v83 = [
|
|
"kpis" => $v83_raw["summary"]["total_kpis"] ?? null,
|
|
"ok" => $v83_raw["summary"]["ok"] ?? null,
|
|
"warn" => $v83_raw["summary"]["warn"] ?? null,
|
|
"fail" => $v83_raw["summary"]["fail"] ?? null,
|
|
"complete_pct" => $v83_raw["summary"]["data_completeness_pct"] ?? null
|
|
];
|
|
}
|
|
}
|
|
|
|
// Orphans (from V83 architecture_quality KPI)
|
|
$orphans_count = 0;
|
|
if (is_readable("/tmp/wevia-pages-registry-cache.json")) {
|
|
$reg = @json_decode(@file_get_contents("/tmp/wevia-pages-registry-cache.json"), true);
|
|
if ($reg && isset($reg["orphans"])) $orphans_count = (int)$reg["orphans"];
|
|
}
|
|
|
|
// Build unified schema (SINGLE SOURCE OF TRUTH)
|
|
$response = [
|
|
"ok" => true,
|
|
"version" => "v118-kpi-unified",
|
|
"doctrine" => "zero doublon single source-of-truth",
|
|
"ts" => date("c"),
|
|
"cache_hit" => false,
|
|
"cache_ttl_sec" => $cache_ttl,
|
|
|
|
"providers" => [
|
|
"total" => $sot["providers_count"] ?? ($sot["counts"]["providers"] ?? 0),
|
|
"ok" => $tokens["summary"]["live_ok"] ?? null,
|
|
"expired" => $tokens["summary"]["expired_ko"] ?? null,
|
|
"health_pct" => $tokens["summary"]["health_pct"] ?? null
|
|
],
|
|
|
|
"agents" => [
|
|
"active" => $sot["agents_count"] ?? 0,
|
|
"total_live" => $sot["counts"]["agents_total_live"] ?? ($sot["agents_total"] ?? 0)
|
|
],
|
|
|
|
"skills" => [
|
|
"count" => $sot["skills_count"] ?? 0,
|
|
"total" => $sot["skills_total"] ?? ($sot["counts"]["skills_total"] ?? 0)
|
|
],
|
|
|
|
"intents" => [
|
|
"count" => $sot["intents_count"] ?? ($sot["counts"]["intents"] ?? 0),
|
|
"total" => $sot["intents_total"] ?? 0
|
|
],
|
|
|
|
"docker" => [
|
|
"running" => $docker_count
|
|
],
|
|
|
|
"orphans" => [
|
|
"count" => $orphans_count,
|
|
"status" => ($orphans_count === 0) ? "ok" : "warn"
|
|
],
|
|
|
|
"nonreg" => [
|
|
"pass" => $nonreg["pass"] ?? 0,
|
|
"fail" => $nonreg["fail"] ?? 0,
|
|
"total" => ($nonreg["pass"] ?? 0) + ($nonreg["fail"] ?? 0),
|
|
"score" => $nonreg["score"] ?? 0,
|
|
"ts" => $nonreg["ts"] ?? null
|
|
],
|
|
|
|
"v83" => $v83,
|
|
|
|
"autonomy" => [
|
|
"score" => $sot["autonomy_score"] ?? 0,
|
|
"level" => $sot["autonomy_level"] ?? "UNKNOWN"
|
|
],
|
|
|
|
"qdrant" => [
|
|
"collections" => $sot["counts"]["qdrant_cols"] ?? 0,
|
|
"points" => $sot["counts"]["qdrant_points"] ?? 0
|
|
],
|
|
|
|
"dashboards" => [
|
|
"count" => $sot["dashboards_count"] ?? ($sot["counts"]["dashboards"] ?? 0)
|
|
],
|
|
|
|
"brains" => [
|
|
"count" => $sot["brains_count"] ?? ($sot["counts"]["brains"] ?? 0)
|
|
],
|
|
|
|
"doctrines" => [
|
|
"count" => $sot["doctrines_count"] ?? ($sot["counts"]["doctrines"] ?? 0)
|
|
],
|
|
|
|
"business" => [
|
|
"cash_collected_month_keur" => $sot["cash_collected_month_keur"] ?? 0,
|
|
"cash_collected_ytd_keur" => $sot["cash_collected_ytd_keur"] ?? 0,
|
|
"cash_target_month_keur" => $sot["cash_target_month_keur"] ?? 0,
|
|
"dso_days" => $sot["dso_days"] ?? 0
|
|
],
|
|
|
|
"ethica" => [
|
|
"total_hcps" => $sot["ethica_total"] ?? 0
|
|
],
|
|
|
|
"sources_used" => [
|
|
"source_of_truth_json" => !empty($sot),
|
|
"nonreg_latest" => !empty($nonreg),
|
|
"token_health_cache" => !empty($tokens),
|
|
"v83_latest" => ($v83["kpis"] !== null),
|
|
"docker_live" => ($docker_count > 0)
|
|
]
|
|
];
|
|
|
|
// Write cache
|
|
@file_put_contents($cache_file, json_encode($response, JSON_PRETTY_PRINT));
|
|
|
|
echo json_encode($response, JSON_PRETTY_PRINT);
|