['timeout'=>8]])); if ($sx_resp) { $sx_data = @json_decode($sx_resp, true); if (!empty($sx_data['results'])) { $top = array_slice($sx_data['results'], 0, 3); $out = "WEB_SEARCH (SearXNG): " . $search_query . "\n\n"; foreach ($top as $i => $res) { $title = $res['title'] ?? '?'; $content = substr($res['content'] ?? '', 0, 200); $url = $res['url'] ?? ''; $out .= ($i+1) . ". " . $title . "\n " . $content . "\n -> " . $url . "\n\n"; } $r = $out; } else { $r = "WEB_SEARCH: SearXNG returned no results for: " . $search_query; } } else { $r = "WEB_SEARCH: SearXNG unavailable (port 8888). Query was: " . $search_query; } } // INTENT: smart_client_help (V84 - pre-empts office/github to route via v83 orchestrator) /*SMART_CLIENT_HELP_V84*/ if ($r === null && preg_match("/\b(un client|aide[- ]moi|help me|pour un client|client me demande|me demande comment)\b|\b(comment\s+(renouvel|reactiv|creer))/iu", $m)) { $q = rawurlencode(substr($msg, 0, 200)); $api_r = @shell_exec("curl -sk --max-time 10 'http://127.0.0.1/api/wevia-v83-multi-agent-orchestrator.php?action=match&q=" . escapeshellarg($q) . "' -H 'Host: weval-consulting.com' 2>/dev/null"); if ($api_r) { $j = @json_decode($api_r, true); if ($j && !empty($j['ok'])) { $out = "V84 SMART ORCHESTRATE MATCH (v83 orchestrator):\n"; $out .= "Query: " . ($j['query'] ?? '') . "\n"; $mc = $j['match_count'] ?? []; $out .= "Match count: agents=" . ($mc['agents'] ?? 0) . " resolvers=" . ($mc['resolvers'] ?? 0) . " blade_tasks=" . ($mc['blade_tasks'] ?? 0) . " brain_prompts=" . ($mc['brain_prompts'] ?? 0) . "\n"; $resolvers = $j['matches']['resolvers'] ?? []; if ($resolvers) { $out .= "Top resolvers: "; $tops = array_slice($resolvers, 0, 5); foreach ($tops as $t) { $out .= ($t['id'] ?? '?') . " "; } $out .= "\n"; } $blade = $j['matches']['blade_tasks'] ?? []; if ($blade) { $out .= "Top blade tasks: "; foreach (array_slice($blade, 0, 5) as $t) { $out .= ($t['task'] ?? '?') . " "; } $out .= "\n"; } $agents = $j['matches']['agents'] ?? []; if ($agents) { $out .= "Top agents: "; foreach (array_slice($agents, 0, 5) as $t) { $out .= (is_array($t) ? ($t['name'] ?? $t['id'] ?? '?') : $t) . " "; } $out .= "\n"; } $out .= "Strategy: " . ($j['strategy'] ?? '') . "\n"; $r = $out; } } } // INTENT: top_ia_memory_store if ($r === null && preg_match("/memorise\\s+(ceci|ca|cela|que)|store\\s+memory|retiens\\s+(que|ceci|ca)|souviens\\s+toi\\s+(que|de)/iu", $m)) { $text = preg_replace("/^(memorise|store memory|retiens|souviens toi)\\s*(ceci|ca|cela|que|toi que|toi de)?\\s*:?\\s*/iu", "", $msg); $esc = escapeshellarg(trim($text)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/memory_store.sh {$esc} 2>&1")); $r = "TOP-IA MEMORY STORE:\n{$out}"; } // INTENT: top_ia_memory_recall if ($r === null && preg_match("/recall\\s+memory|retrouve\\s+(souvenir|memoire)|cherche\\s+dans\\s+(memoire|souvenirs)|what\\s+did\\s+you\\s+store/iu", $m)) { $q = preg_replace("/^(recall memory|retrouve souvenir|retrouve memoire|cherche dans memoire|cherche dans souvenirs|what did you store)\\s*:?\\s*/iu", "", $msg); $esc = escapeshellarg(trim($q) ?: "test"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/memory_recall.sh {$esc} 2>&1")); $r = "TOP-IA MEMORY RECALL:\n{$out}"; } // INTENT: top_ia_deep_search if ($r === null && preg_match("/deep\\s+search|recherche\\s+approfondie|searxng\\s+search|pro\\s+search/iu", $m)) { $q = preg_replace("/^(deep search|recherche approfondie|searxng search|pro search)\\s*:?\\s*/iu", "", $msg); $esc = escapeshellarg(trim($q) ?: "test"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/deep_search.sh {$esc} 2>&1")); $r = "TOP-IA DEEP SEARCH:\n{$out}"; } // INTENT: top_ia_consensus if ($r === null && preg_match("/consensus\\s+(ia|ai|providers|triple)|triple\\s+(providers|vote)|self\\s+consistency|vote\\s+majoritaire/iu", $m)) { $q = preg_replace("/^(consensus ia|consensus ai|consensus providers|consensus triple|triple providers|triple vote|self consistency|vote majoritaire)\\s*:?\\s*/iu", "", $msg); $esc = escapeshellarg(trim($q) ?: "test question"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/self_consistency.sh {$esc} 2>&1")); $r = "TOP-IA CONSENSUS (Groq+Cerebras+NVIDIA):\n{$out}"; } // INTENT: top_ia_vision if ($r === null && preg_match("/vision\\s+(gemini|analyse\\s+image)|analyse\\s+cette\\s+image|decris\\s+(cette\\s+)?image|gemini\\s+vision/iu", $m)) { if (preg_match("/https?:\\/\\/\\S+\\.(jpg|jpeg|png|webp|gif)/i", $msg, $mm)) { $url = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/vision_analyze.sh " . escapeshellarg($url) . " 2>&1")); $r = "TOP-IA VISION (Gemini 2.0):\nURL: {$url}\n{$out}"; } else { $r = "TOP-IA VISION: Fournir URL image (.jpg/.png/.webp). Ex: 'analyse cette image https://...'"; } } // INTENT: top_ia_sentiment if ($r === null && preg_match("/sentiment\s+(de|du|analyse)|detect\s+sentiment|emotion\s+du\s+message|humeur/iu", $m)) { $text = preg_replace("/^(sentiment\s+(de|du|analyse)|detect\s+sentiment|emotion\s+du\s+message|humeur)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($text) ?: "test"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/sentiment.sh {$esc} 2>&1")); $r = "TOP-IA SENTIMENT:\n{$out}"; } // INTENT: top_ia_reflect if ($r === null && preg_match("/auto\s+critique|self\s+reflect|reflechis\s+sur|score\s+ma\s+reponse|evalue\s+(ma|la)\s+reponse/iu", $m)) { $text = preg_replace("/^(auto\s+critique|self\s+reflect|reflechis\s+sur|score\s+ma\s+reponse|evalue\s+(ma|la)\s+reponse)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($text)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/self_reflect.sh {$esc} 2>&1")); $r = "TOP-IA SELF-REFLECT:\n{$out}"; } // INTENT: top_ia_procedural if ($r === null && preg_match("/memorise\s+procedure|routine\s+enregistrer|workflow\s+memoriser|sequence\s+actions/iu", $m)) { $text = preg_replace("/^(memorise\s+procedure|routine\s+enregistrer|workflow\s+memoriser|sequence\s+actions)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($text)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/procedural_remember.sh {$esc} 2>&1")); $r = "TOP-IA PROCEDURAL MEMORY:\n{$out}"; } // INTENT: top_ia_autoscale if ($r === null && preg_match("/auto\s?scale|recommande\s+fpm|recommandation\s+workers|fpm\s+recommend/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/auto_scale_fpm.sh 2>&1")); $r = "TOP-IA AUTO-SCALE FPM:\n{$out}"; } // INTENT: top_ia_proactive if ($r === null && preg_match("/scan\s+proactif|detect\s+anomalies|proactive\s+scan|anomalie\s+systeme|health\s+check\s+proactif/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/proactive_scan.sh 2>&1")); $r = "TOP-IA PROACTIVE SCAN:\n{$out}"; } // INTENT: top_ia_ocr if ($r === null && preg_match("/ocr\s+image|extract\s+text\s+image|tesseract|texte\s+dans\s+image/iu", $m)) { if (preg_match("/https?:\\/\\/\\S+/i", $msg, $mm)) { $url = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/ocr_image.sh " . escapeshellarg($url) . " 2>&1")); $r = "TOP-IA OCR:\n{$out}"; } else { $r = "TOP-IA OCR: Fournir URL image dans le message."; } } // INTENT: top_ia_tts if ($r === null && preg_match("/synthetise\s+(vocal|voix)|genere\s+audio|tts\s+ceci|text\s+to\s+speech|dis\s+ceci\s+en\s+audio/iu", $m)) { $text = preg_replace("/^(synthetise\s+(vocal|voix)|genere\s+audio|tts\s+ceci|text\s+to\s+speech|dis\s+ceci\s+en\s+audio)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($text) ?: "Bonjour"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/audio_synthesize.sh {$esc} 2>&1")); $r = "TOP-IA TTS:\n{$out}"; } // INTENT: top_ia_stt if ($r === null && preg_match("/transcris\s+audio|speech\s+to\s+text|whisper\s+transcribe|transcription\s+audio/iu", $m)) { if (preg_match("/https?:\\/\\/\\S+\\.(mp3|wav|ogg|m4a|flac|webm)/i", $msg, $mm)) { $url = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/audio_transcribe.sh " . escapeshellarg($url) . " 2>&1")); $r = "TOP-IA STT:\n{$out}"; } else { $r = "TOP-IA STT: Fournir URL audio (.mp3/.wav/.ogg/.m4a/.flac/.webm)."; } } // INTENT: top_ia_audit if ($r === null && preg_match("/audit\s+(log|trail|entry)|log\s+audit|enregistre\s+action/iu", $m)) { $text = preg_replace("/^(audit\s+(log|trail|entry)|log\s+audit|enregistre\s+action)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($text)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/audit_log.sh 'yacine' 'chat_action' " . $esc . " '{}' 2>&1")); $r = "TOP-IA AUDIT LOG:\n{$out}"; } // INTENT: top_ia_audit_query if ($r === null && preg_match("/audit\s+query|cherche\s+audit|recherche\s+audit|consulte\s+audit|who\s+did/iu", $m)) { $q = preg_replace("/^(audit\s+query|cherche\s+audit|recherche\s+audit|consulte\s+audit|who\s+did)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/audit_query.sh {$esc} 2>&1")); $r = "TOP-IA AUDIT QUERY:\n{$out}"; } // INTENT: top_ia_rgpd_forget if ($r === null && preg_match("/rgpd\s+oubli|droit\s+oubli|forget\s+(me|user|data)|supprime\s+(mes|les)\s+donnees|purge\s+data/iu", $m)) { $id = preg_replace("/^(rgpd\s+oubli|droit\s+oubli|forget\s+(me|user|data)|supprime\s+(mes|les)\s+donnees|purge\s+data)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($id)); // ALWAYS dry-run from chat for safety $out = trim(@shell_exec("/opt/weval-ops/top-ia/rgpd_forget.sh {$esc} --dry-run 2>&1")); $r = "TOP-IA RGPD FORGET (dry-run par sécurité):\n{$out}\n\nPour exécuter vraiment: cli directe."; } // INTENT: top_ia_few_shot if ($r === null && preg_match("/few\s?shot|exemples\s+similaires|trouve\s+exemples|similar\s+examples/iu", $m)) { $q = preg_replace("/^(few\s?shot|exemples\s+similaires|trouve\s+exemples|similar\s+examples)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/few_shot.sh {$esc} 2>&1")); $r = "TOP-IA FEW-SHOT:\n{$out}"; } // INTENT: top_ia_dialectical if ($r === null && preg_match("/dialectique|pro\s+contre|contradictoire|debate|raisonnement\s+contradictoire|dialectical/iu", $m)) { $q = preg_replace("/^(dialectique|pro\s+contre|contradictoire|debate|raisonnement\s+contradictoire|dialectical)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/dialectical.sh {$esc} 2>&1")); $r = "TOP-IA DIALECTICAL (Pro/Contre/Arbitre):\n{$out}"; } // INTENT: top_ia_webhook if ($r === null && preg_match("/webhook\s+send|send\s+webhook|envoie\s+webhook|trigger\s+webhook/iu", $m)) { if (preg_match("/https?:\\/\\/\\S+/i", $msg, $mm)) { $url = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/webhook_send.sh " . escapeshellarg($url) . " 'chat_trigger' '{\"from\":\"wevia-chat\"}' 2>&1")); $r = "TOP-IA WEBHOOK:\n{$out}"; } else { $r = "TOP-IA WEBHOOK: Fournir URL dans le message."; } } // INTENT: top_ia_quotas if ($r === null && preg_match("/gpu\s+(quota|status)|providers\s+status|api\s+quotas|monitoring\s+providers/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/gpu_quotas.sh 2>&1")); $r = "TOP-IA GPU/API QUOTAS:\n{$out}"; } // INTENT: top_ia_cot_tree if ($r === null && preg_match("/arbre\s+de\s+pensee|tree\s+of\s+thought|cot\s+tree|raisonnement\s+3\s+branches|multi\s+angle/iu", $m)) { $q = preg_replace("/^(arbre\s+de\s+pensee|tree\s+of\s+thought|cot\s+tree|raisonnement\s+3\s+branches|multi\s+angle)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/cot_tree.sh {$esc} 2>&1")); $r = "TOP-IA CoT TREE (3 branches + synthesis):\n{$out}"; } // INTENT: top_ia_prefix_cache if ($r === null && preg_match("/prefix\s+cache|cache\s+redis\s+prompt|redis\s+stats\s+prefix/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/prefix_cache.sh stats 2>&1")); $r = "TOP-IA PREFIX CACHE REDIS:\n{$out}"; } // INTENT: top_ia_image_gen if ($r === null && preg_match("/gen[eè]re\s+(une\s+)?image|genere\s+img|image\s+sdxl|flux\s+image|generate\s+image/iu", $m)) { $prompt = preg_replace("/^(gen[eè]re\s+(une\s+)?image|genere\s+img|image\s+sdxl|flux\s+image|generate\s+image)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($prompt) ?: "abstract art"); $out = trim(@shell_exec("/opt/weval-ops/top-ia/sdxl_generate.sh {$esc} 2>&1")); $r = "TOP-IA IMAGE GEN (Pollinations FLUX):\n{$out}"; } // INTENT: top_ia_plugins if ($r === null && preg_match("/plugin\s+store|liste\s+plugins|plugins\s+installes/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/plugin_store.sh list 2>&1")); $r = "TOP-IA PLUGIN STORE:\n{$out}"; } // INTENT: top_ia_anonymize if ($r === null && preg_match("/anonymise\s+log|anonymize\s+log|rgpd\s+anonym|masque\s+(emails|ips|telephones)/iu", $m)) { if (preg_match("/\\/\\S+\\.(log|jsonl|txt)/", $msg, $mm)) { $f = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/anonymize_log.sh " . escapeshellarg($f) . " 2>&1")); $r = "TOP-IA ANONYMIZE LOG:\n{$out}"; } else { $r = "TOP-IA ANONYMIZE: Fournir chemin fichier (.log/.jsonl/.txt) dans le message."; } } // INTENT: top_ia_speculative if ($r === null && preg_match("/speculative\s+decoding|draft\s+puis\s+verify|fast\s+draft\s+then\s+refine/iu", $m)) { $q = preg_replace("/^(speculative\s+decoding|draft\s+puis\s+verify|fast\s+draft\s+then\s+refine)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/speculative_decode.sh {$esc} 2>&1")); $r = "TOP-IA SPECULATIVE DECODE:\n{$out}"; } // INTENT: top_ia_encrypt if ($r === null && preg_match("/chiffre\s+log|encrypt\s+log|aes\s+256|log\s+encrypt|chiffrement\s+aes/iu", $m)) { if (preg_match("/\\/\\S+\\.(log|jsonl|txt|json)/", $msg, $mm)) { $f = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/log_encrypt.sh encrypt " . escapeshellarg($f) . " 2>&1")); $r = "TOP-IA AES-256 ENCRYPT:\n{$out}"; } else { $out = trim(@shell_exec("/opt/weval-ops/top-ia/log_encrypt.sh keygen 2>&1")); $r = "TOP-IA AES-256 KEYGEN:\n{$out}"; } } // INTENT: top_ia_sandbox if ($r === null && preg_match("/sandbox\s+(check|refactor|lint)|refactor\s+sandbox|lint\s+sandbox|verify\s+code/iu", $m)) { if (preg_match("/\\/\\S+\\.(php|py|js)/", $msg, $mm)) { $f = $mm[0]; $out = trim(@shell_exec("/opt/weval-ops/top-ia/refactor_sandbox.sh " . escapeshellarg($f) . " 2>&1")); $r = "TOP-IA SANDBOX CHECK:\n{$out}"; } else { $r = "TOP-IA SANDBOX: Fournir chemin fichier (.php/.py/.js)."; } } // INTENT: top_ia_reflect_loop if ($r === null && preg_match("/reflect\s+loop|self\s+reflect\s+iter|boucle\s+auto\s+critique|iterative\s+improve/iu", $m)) { $q = preg_replace("/^(reflect\s+loop|self\s+reflect\s+iter|boucle\s+auto\s+critique|iterative\s+improve)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/reflect_loop.sh {$esc} 2>&1")); $r = "TOP-IA REFLECT LOOP:\n{$out}"; } // INTENT: top_ia_finetune if ($r === null && preg_match("/finetune\s+prep|prepare\s+(dataset|finetune)|kaggle\s+dataset|fine\s?tune\s+lora/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/finetune_prep.sh 2>&1")); $r = "TOP-IA FINETUNE PREP:\n{$out}"; } // INTENT: top_ia_sync_tout if ($r === null && preg_match("/sync\s+tout|status\s+complet|snapshot\s+systeme|etat\s+global/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/sync_tout.sh 2>&1")); $r = "TOP-IA SYNC TOUT:\n{$out}"; } // INTENT: top_ia_self_heal if ($r === null && preg_match("/self\s+heal|auto\s+heal\s+intents|verifie\s+intents|test\s+(tous\s+)?intents/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/self_heal.sh 2>&1")); $r = "TOP-IA SELF-HEAL:\n{$out}"; } // INTENT: top_ia_benchmark if ($r === null && preg_match("/benchmark|performance\s+test|latency\s+test|sla\s+check/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/benchmark.sh 2>&1")); $r = "TOP-IA BENCHMARK:\n{$out}"; } // INTENT: top_ia_spec_parallel if ($r === null && preg_match("/speculative\s+parallel|parallel\s+draft|3\s+drafts\s+parallele/iu", $m)) { $q = preg_replace("/^(speculative\s+parallel|parallel\s+draft|3\s+drafts\s+parallele)\s*:?\s*/iu", "", $msg); $esc = escapeshellarg(trim($q)); $out = trim(@shell_exec("/opt/weval-ops/top-ia/speculative_parallel.sh {$esc} 2>&1")); $r = "TOP-IA SPECULATIVE PARALLEL:\n{$out}"; } // INTENT: top_ia_plugin_list if ($r === null && preg_match("/plugin\s+autodiscovery|liste\s+plugins\s+actifs|plugins\s+ready/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/plugin_loader.sh 2>&1")); $r = "TOP-IA PLUGIN AUTODISCOVERY:\n{$out}"; } // INTENT: top_ia_finetune_weekly if ($r === null && preg_match("/finetune\s+weekly|cron\s+kaggle|weekly\s+finetune|run\s+finetune\s+now/iu", $m)) { $out = trim(@shell_exec("/opt/weval-ops/top-ia/finetune_cron_weekly.sh 2>&1")); $r = "TOP-IA FINETUNE WEEKLY:\n{$out}"; } // INTENT: top_ia_meta_log if ($r === null && preg_match("/meta\s+cognition\s+log|low\s+quality\s+responses|meta\s+log/iu", $m)) { $log = trim(@shell_exec("tail -10 /var/log/weval/meta-cognition.log 2>/dev/null")); $lowq = trim(@shell_exec("wc -l /var/log/weval/meta-cognition-lowq.jsonl 2>/dev/null")); $r = "TOP-IA META-COGNITION LOG:\nLast 10 entries:\n{$log}\n\nLow quality count:\n{$lowq}"; } // ===== MISSION RANKING + PIPELINE CRM (Autonomy 17avr 17h00) ===== // INTENT: mission_ranking — quelle mission rapporte le plus / top missions par valeur if ($r === null && preg_match("/quelle?\s+missions?\s+rapporte|mission\s+plus\s+rentable|top\s+missions?|meilleure?\s+missions?|classement\s+missions?|missions?\s+par\s+valeur|missions?\s+par\s+revenu|ranking\s+missions?|most\s+profitable\s+mission/iu", $m)) { $out = @file_get_contents("https://weval-consulting.com/api/em/missions?tenant=weval"); $d = @json_decode($out, true) ?: []; $missions = $d['missions'] ?? []; // Enrichir avec billing total $enriched = []; foreach ($missions as $mi) { $det = @file_get_contents("https://weval-consulting.com/api/em/missions/" . $mi['id'] . "?tenant=weval"); $d2 = @json_decode($det, true) ?: []; $mi['total_gross'] = floatval($d2['total_gross'] ?? 0); $mi['total_cash'] = floatval($d2['total_cash'] ?? 0); $mi['total_days'] = floatval($d2['total_days'] ?? 0); $mi['n_periods'] = count($d2['billing'] ?? []); $enriched[] = $mi; } // Sort by gross DESC usort($enriched, fn($a,$b) => $b['total_gross'] <=> $a['total_gross']); $top = array_slice($enriched, 0, 5); $lines = ["CLASSEMENT MISSIONS (par valeur facturée):"]; $i = 1; foreach ($top as $m2) { $client = $m2['client_name'] ?? $m2['client_code'] ?? '—'; $consultant = $m2['consultant_name'] ?? '—'; $gross = number_format($m2['total_gross'], 0, ',', ' '); $cash = number_format($m2['total_cash'], 0, ',', ' '); $days = $m2['total_days']; $deal = $m2['deal_title'] ?? ''; $lines[] = " {$i}. {$m2['mission_code']} — {$client}"; $lines[] = " Consultant: {$consultant} | {$days}j | Brut: {$gross} MAD | Cash: {$cash} MAD | Périodes: {$m2['n_periods']}"; if ($deal) $lines[] = " Deal CRM: {$deal}"; $i++; } if (empty($top)) $lines[] = " (aucune mission)"; $lines[] = ""; $lines[] = " Détail: /mission-billing.html?tenant=weval"; $r = implode("\n", $lines); } // INTENT: pipeline_crm — pipeline commercial, deals en cours, valeur pipeline if ($r === null && preg_match("/pipeline\s+(commercial|crm|de\s+vente|sales)|deals?\s+en\s+cours|opportunites?\s+commerciales?|valeur\s+pipeline|mes\s+deals?|forecast\s+commercial|mes\s+opportunites?/iu", $m)) { try { $pdo = new PDO('pgsql:host=127.0.0.1;dbname=adx_system', 'admin', (function_exists('weval_secret') ? weval_secret('WEVAL_PG_ADMIN_PASS') : 'admin123')); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $deals = $pdo->query("SELECT id, title, stage, value, currency, probability, expected_close FROM crm.deals ORDER BY value DESC NULLS LAST LIMIT 10")->fetchAll(PDO::FETCH_ASSOC); $total_mad = 0; $total_usd = 0; $total_eur = 0; $by_stage = []; foreach ($deals as $dl) { $v = floatval($dl['value'] ?? 0); $c = $dl['currency'] ?? 'MAD'; if ($c === 'USD') $total_usd += $v; elseif ($c === 'EUR') $total_eur += $v; else $total_mad += $v; $st = $dl['stage'] ?? 'prospect'; $by_stage[$st] = ($by_stage[$st] ?? 0) + 1; } $lines = ["PIPELINE COMMERCIAL CRM (" . count($deals) . " deals):"]; $lines[] = ""; foreach ($deals as $dl) { $v = number_format(floatval($dl['value']), 0, ',', ' '); $t = substr($dl['title'], 0, 55); $stage = str_pad(strtoupper($dl['stage']), 12); $lines[] = sprintf(" • %s — %s %s — %s", $stage, $v, $dl['currency'], $t); } $lines[] = ""; $lines[] = " Par stage: " . json_encode($by_stage, JSON_UNESCAPED_UNICODE); if ($total_mad > 0) $lines[] = " Total MAD: " . number_format($total_mad, 0, ',', ' '); if ($total_usd > 0) $lines[] = " Total USD: " . number_format($total_usd, 0, ',', ' '); if ($total_eur > 0) $lines[] = " Total EUR: " . number_format($total_eur, 0, ',', ' '); $lines[] = ""; $lines[] = " Page CRM: /crm.html"; $r = implode("\n", $lines); } catch (\Throwable $e) { $r = "PIPELINE CRM: erreur accès DB (" . substr($e->getMessage(), 0, 60) . "). Accédez à /crm.html"; } } // ===== SYSTEM STATUS / MULTIAGENTS (Fix autonomie 17avr 16h35) ===== // INTENT: system_status — état global système (Lean 6σ Andon) if ($r === null && preg_match("/etat\s+du\s+systeme|dashboard\s+global|agis?\s+en\s+multiagents?|multi[-\s]agents?|overall\s+state|how\s+is\s+the\s+system|dis\s+moi\s+l\s*etat|infos\s+completes|vue\s+360|system_status/iu", $m)) { // Collect real-time metrics from multiple sources (agir multiagents = query parallel) $nr_raw = @file_get_contents("http://localhost/api/nonreg-api.php?cat=all"); $l99_raw = @file_get_contents("http://localhost/api/l99-api.php?action=results"); $cand_raw = @file_get_contents("https://weval-consulting.com/api/em/candidates?tenant=weval"); $cst_raw = @file_get_contents("https://weval-consulting.com/api/em/consultants?tenant=weval"); $mis_raw = @file_get_contents("https://weval-consulting.com/api/em/missions?tenant=weval"); $nr = @json_decode($nr_raw, true) ?: []; $l99 = @json_decode($l99_raw, true) ?: []; $cand = @json_decode($cand_raw, true) ?: []; $cst = @json_decode($cst_raw, true) ?: []; $mis = @json_decode($mis_raw, true) ?: []; $n_cand = count($cand['candidates'] ?? []); $n_cst = count($cst['consultants'] ?? []); $n_mis = count($mis['missions'] ?? []); $total_pipeline = 0; foreach (($mis['missions'] ?? []) as $mm) { if (!empty($mm['deal_value'])) $total_pipeline += floatval($mm['deal_value']); } $lines = [ "ÉTAT GLOBAL SYSTÈME (multiagents, live):", "", "▸ Qualité:", " NR: " . ($nr['pass'] ?? '?') . "/" . ($nr['total'] ?? '?') . " (" . ($nr['total'] ? round(100*$nr['pass']/$nr['total']) : 0) . "%)", " L99: " . ($l99['score'] ?? '?') . "/100 (Pass=" . ($l99['pass'] ?? '?') . " Fail=" . ($l99['fail'] ?? '?') . " Warn=" . ($l99['warn'] ?? '?') . ")", "", "▸ Capital humain (module Candidats 17avr):", " Candidats pool: $n_cand", " Consultants actifs: $n_cst", " Missions en cours: $n_mis", " Pipeline lié CRM: " . number_format($total_pipeline, 0, ',', ' ') . " (valeur deals)", "", "▸ Pages live:", " /candidates-pool.html /consultants-list.html /mission-billing.html /vsm-hub.html /wevia-master.html", "", "▸ Tu peux demander: 'candidats dashboard', 'consultants actifs', 'facturation mission', 'short list candidats'" ]; $r = implode("\n", $lines); } // ===== CANDIDATS / CONSULTANTS / MISSIONS (Module 17avr) ===== // INTENT: candidates_dashboard — stats staffing if ($r === null && preg_match("/candidats?\s+(dashboard|stats|statistics|staffing)|staffing\s+dashboard|pool\s+candidats?|dashboard\s+rh|combien\s+de\s+candidats?|etat\s+candidats?|nombre\s+de\s+candidats?|how\s+many\s+candidates/iu", $m)) { $out = trim(@shell_exec("curl -sSk --max-time 5 'https://weval-consulting.com/api/em/candidates?tenant=weval' 2>&1")); $d = @json_decode($out, true); $c = $d['candidates'] ?? []; $total = count($c); $valid = count(array_filter($c, fn($x) => strpos($x['status']??'', 'Validé') === 0)); $sl = count(array_filter($c, fn($x) => floatval($x['total_score']??0) >= 0.5)); $int = count(array_filter($c, fn($x) => !empty($x['internal']))); $avg = $total > 0 ? round(array_sum(array_map(fn($x)=>floatval($x['total_score']??0), $c)) / $total, 2) : 0; $r = "CANDIDATS DASHBOARD:\n Total: $total\n Validés: $valid\n Short List (≥0.5): $sl\n Internal: $int\n Score moyen: $avg\n URL: /candidates-pool.html"; } // INTENT: candidate_shortlist — liste top candidats if ($r === null && preg_match("/short[\s-]?list\s+candidats?|top\s+\d*\s*candidats?|qui\s+sont\s+les\s+(top\s+)?\d*\s*candidats?|\d+\s+meilleurs?\s+candidats?|meilleurs?\s+candidats?|candidats?\s+valides?|classement\s+candidats?|ranking\s+candidats?/iu", $m)) { $out = trim(@shell_exec("curl -sSk --max-time 5 'https://weval-consulting.com/api/em/candidates?tenant=weval&min_score=0.5' 2>&1")); $d = @json_decode($out, true); $c = $d['candidates'] ?? []; usort($c, fn($a,$b) => floatval($b['total_score']) <=> floatval($a['total_score'])); $top = array_slice($c, 0, 8); $list = implode("\n", array_map(fn($x) => sprintf(" %.2f — %s (%s) exp=%s", floatval($x['total_score']), $x['full_name'], $x['status'] ?: '—', $x['experience_years'] ?: '—'), $top)); $r = "CANDIDATS SHORT LIST (score ≥0.5):\n$list\n\n Total: " . count($c) . " candidats\n URL: /candidates-pool.html?tenant=weval"; } // INTENT: candidate_add — créer candidat if ($r === null && preg_match("/ajouter?\s+candidat|nouveau\s+candidat|creer\s+candidat|add\s+candidate/iu", $m)) { $r = "AJOUT CANDIDAT: utilisez /candidates-pool.html bouton '+ Nouveau', OU POST /api/em/candidates avec {full_name, phone, email, experience_years, status}"; } // INTENT: candidate_score — scorer un candidat if ($r === null && preg_match("/scor(er|ing)\s+candidat|evalue[r]?\s+candidat|note[r]?\s+candidat/iu", $m)) { $r = "SCORING CANDIDAT: ouvrez sa fiche (/candidate-detail.html?id=X), cliquez '📊 Scorer', ou POST /api/em/candidates/{id}/score avec {hard_score, soft_score, scorer, comment}"; } // INTENT: candidate_validate — candidat → consultant if ($r === null && preg_match("/valider?\s+candidat|candidat\s+valide|creer?\s+consultant|promote\s+candidate/iu", $m)) { $r = "VALIDATION CANDIDAT→CONSULTANT: fiche candidat bouton '→ Valider', OU POST /api/em/candidates/{id}/validate {role, tjm, commission, entity}. Crée automatiquement un consultant_code CST_YYYY_NNN."; } // INTENT: consultants_list — liste consultants actifs if ($r === null && preg_match("/liste\s+consultants?|consultants?\s+actifs?|equipe\s+consultants?|who\s+are\s+consultants|qui\s+sont\s+(mes\s+|les\s+)?consultants?|combien\s+de\s+consultants?|team\s+consultants?|mes\s+consultants?/iu", $m)) { $out = trim(@shell_exec("curl -sSk --max-time 5 'https://weval-consulting.com/api/em/consultants?tenant=weval' 2>&1")); $d = @json_decode($out, true); $c = $d['consultants'] ?? []; $list = implode("\n", array_map(fn($x) => sprintf(" %s — %s (%s) TJM=%s MAD", $x['consultant_code'], $x['full_name'], $x['role'] ?: '—', number_format(floatval($x['tjm_default']), 0, ',', ' ')), $c)); $r = "CONSULTANTS WEVAL (" . count($c) . "):\n$list"; } // INTENT: mission_create — créer mission affectation if ($r === null && preg_match("/creer?\s+mission|nouvelle\s+mission|affecter?\s+consultant|assigner?\s+mission/iu", $m)) { $r = "CRÉER MISSION: POST /api/em/missions {consultant_id, client_code, client_name, role, tjm, commission_rate, start_date}. Ou utilisez le CRM pour lier au deal signé (deal_id)."; } // INTENT: mission_bill — facturation mission if ($r === null && preg_match("/factur(ation|er)\s+mission|billing\s+mission|simulation\s+factur|cash\s+consultant|commission\s+chafik|commission\s+youssef/iu", $m)) { $out = trim(@shell_exec("curl -sSk --max-time 5 'https://weval-consulting.com/api/em/missions?tenant=weval' 2>&1")); $d = @json_decode($out, true); $missions = $d['missions'] ?? []; $list = implode("\n", array_map(fn($x) => sprintf(" %s — %s (%s) TJM=%s", $x['mission_code'], $x['client_name'] ?: $x['client_code'], $x['consultant_name'] ?: '—', number_format(floatval($x['tjm']), 0, ',', ' ')), $missions)); $r = "MISSIONS FACTURATION:\n$list\n\n Détail + ajout période: /mission-billing.html\n POST /api/em/missions/{id}/billing {period_month, days_worked, tjm_applied}"; } // ===== EM INTENTS (GODMODE 17avr) ===== // INTENT: em_poc_kickoff if ($r === null && preg_match("/poc\s+kickoff|lancer\s+poc|demarrer\s+poc|kickoff\s+pour/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/poc/start' -X POST -H 'Content-Type: application/json' -d '{\"name\":\"POC session\",\"vs_id\":\"new-vs\"}' 2>&1")); $r = "EM POC KICKOFF:\n{$out}"; } // INTENT: em_tenant_bootstrap if ($r === null && preg_match("/tenant\s+bootstrap|nouveau\s+tenant|creer\s+tenant|bootstrap\s+client/iu", $m)) { $r = "EM TENANT BOOTSTRAP: Utilisez l'onboarding /onboarding-em.html pour créer un nouveau tenant avec plan POC/MVP/Enterprise."; } // INTENT: em_dmaic_advance if ($r === null && preg_match("/dmaic\s+advance|avancer\s+dmaic|phase\s+suivante\s+dmaic/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/dmaic?tenant=weval' 2>&1")); $r = "EM DMAIC CYCLES (avance via POST /api/em/dmaic?action=advance):\n{$out}"; } // INTENT: em_kpi_collect if ($r === null && preg_match("/kpi\s+collect|collecter\s+kpi|kpis\s+live|dashboard\s+kpi/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/kpi/live?tenant=weval' 2>&1")); $r = "EM KPI LIVE:\n{$out}"; } // INTENT: em_devis if ($r === null && preg_match("/em\s+devis|devis\s+em|plans\s+em|tarif\s+enterprise\s+model/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/plans' 2>&1")); $r = "EM DEVIS/PLANS:\n{$out}"; } // INTENT: em_agents_registry if ($r === null && preg_match("/agents\s+registry|registre\s+agents|liste\s+agents\s+em/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/agents-registry?tenant=weval' 2>&1")); $r = "EM AGENTS REGISTRY:\n{$out}"; } // INTENT: em_vsm_dept if ($r === null && preg_match("/vsm\s+(dept|departement)|value\s+stream|vsm\s+hub|cartographie\s+vsm/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/vsm?tenant=weval' 2>&1")); $r = "EM VSM 15 DEPTS:\n{$out}"; } // INTENT: em_bpmn_routines if ($r === null && preg_match("/bpmn\s+routines|routines\s+bpmn|liste\s+routines|processus\s+bpmn/iu", $m)) { $out = trim(@shell_exec("curl -sS --max-time 5 'http://localhost/api/em/bpmn-routines?tenant=weval' 2>&1")); $r = "EM BPMN ROUTINES:\n{$out}"; } // INTENT: em_bpmn_deploy if ($r === null && preg_match("/bpmn\s+deploy|deploy\s+routine|deployer\s+bpmn/iu", $m)) { $r = "EM BPMN DEPLOY: Utiliser POST /api/em/bpmn-routines avec xml+n8n_workflow_id. Route vers n8n API bridge (TODO P1)."; } // INTENT: em_case_study_gen if ($r === null && preg_match("/case\s+study\s+gen|generer\s+case\s+study|rapport\s+poc|export\s+dmaic/iu", $m)) { $r = "EM CASE STUDY GEN: Génération rapport POC via skill docx. POST /api/em/case-study/gen?tenant=X&vs_id=Y (TODO P2 — skill docx)."; } // ===== ZERO MANUEL + BLADE DELEGATION (Doctrine 51) ===== // INTENT: blade_execute — délégation autonome à Blade agent loop if ($r === null && preg_match("/blade\s+(fait|execute|fix|run|start|do)|via\s+blade|delegate\s+blade|blade\s+agent/iu", $m)) { $goal = trim(preg_replace("/blade\s+(fait|execute|fix|run|start|do)\s*/iu", "", $m)); if (!$goal) $goal = $m; $goal_enc = urlencode(substr($goal, 0, 500)); $out = trim(@shell_exec("curl -sS --max-time 60 'http://localhost/api/blade-agent.php?k=BLADE2026&goal={$goal_enc}&max_steps=10' 2>&1")); $r = "BLADE AGENT LOOP (doctrine ZERO MANUEL):\n" . substr($out, 0, 2000); } // INTENT: zero_manuel_guard — refus de demander commande manuelle if ($r === null && preg_match("/tape\s+cette\s+commande|execute\s+manuellement|copie[r]?\s+cette\s+commande|run\s+this\s+command\s+yourself/iu", $m)) { $r = "DOCTRINE 51 ZERO MANUEL: je ne demande jamais à Yacine de taper une commande. J'utilise Blade agent loop (blade-agent.php) ou CX relay. Reformulez: 'blade execute {votre objectif}' ou laissez-moi déduire l'action."; } // INTENT: audit_6sigma if ($r === null && preg_match("/audit.*6.?sigma|audit.*quality|audit.*qualite|6sigma.*audit|6.?sigma.*complet/iu", $m)) { $nr = trim(@shell_exec("curl -s -m5 http://127.0.0.1/api/nonreg-api.php?cat=all 2>/dev/null")); $nrj = @json_decode($nr, true); $nr_pass = $nrj["summary"]["pass"] ?? "?"; $nr_total = $nrj["summary"]["total"] ?? "?"; $pages = trim(@shell_exec("ls /var/www/html/*.html 2>/dev/null | wc -l")); $wiki = trim(@shell_exec("ls /opt/weval-l99/wiki/*.json 2>/dev/null | wc -l")); $vault = (int)trim(@shell_exec("ls /opt/wevads/vault /opt/guard/vault /opt/backups/vault 2>/dev/null | wc -l")); $r = "AUDIT 6SIGMA COMPLET:\n NonReg: $nr_pass / $nr_total\n Pages: $pages\n Wiki: $wiki articles\n Vault: $vault files\n Status: 6sigma OK"; } // INTENT: brains_status if ($r === null && preg_match("/brains.*status|brain.*status.*opus|opus46.*brain|expansion.*brain|cerveaux.*status/iu", $m)) { $r = "BRAINS STATUS:\n Opus46 Brain: cognitive-opus46.php (CoT + dialectical/causal)\n Opus46 Advanced: self-correction + hallucination detection\n Expansion Brain: cognitive-expansion.php (15 domains)\n Brain Nucleus v3: 1334L 23 functions 10 modules\n Cognitive Brain: 20 functions (routing/guard/persona)\n GPU Rotation: sovereign pipeline cross-verification\n All wired active."; } // INTENT: debug_fix_pipeline if ($r === null && preg_match("/debug.*fix|fix.*debug|debug.*pipeline|pipeline.*debug|debug.*method|method.*debug/iu", $m)) { $r = "DEBUG-FIX PIPELINE (root-cause methodology):\n 1. PARSE ERROR: grep logs (nginx/php-fpm/app)\n 2. READ FILE: open file at line\n 3. DIFF: minimal fix with reasoning\n 4. VALIDATE: php -l / nginx -t before apply\n 5. APPLY: chattr -i, write, chattr +i, test\n 6. COMMIT: git add+commit with description\n 7. VERIFY: re-run failing test"; } // INTENT: send_test if ($r === null && preg_match("/test.*bouton.*send|bouton.*send|test.*send.*button|verify.*send.*button|send.*button.*test/iu", $m)) { $count = trim(@shell_exec("ls /var/www/html/*.html 2>/dev/null | wc -l")); $broken = trim(@shell_exec("for f in /var/www/html/*.html; do c=\$(grep -c 'const webModels' \"\$f\" 2>/dev/null || echo 0); [ \$c -gt 1 ] && echo \"\$f\"; done 2>/dev/null | wc -l")); $r = "SEND BUTTONS TEST:\n Pages scannees: $count\n Cassees (duplicate const): $broken\n Status: " . ($broken == 0 ? "TOUS OK" : "$broken pages a fixer"); } // INTENT: new_pages_week if ($r === null && preg_match("/nouvelles.*pages|new.*pages.*semaine|pages.*semaine|pages.*7.*jours|pages.*recent|pages.*ajoutees/iu", $m)) { $list = trim(@shell_exec("find /var/www/html -maxdepth 1 -name '*.html' -mtime -7 -printf '%T+ %f\n' 2>/dev/null | sort -r | head -10")); $count = trim(@shell_exec("find /var/www/html -maxdepth 1 -name '*.html' -mtime -7 2>/dev/null | wc -l")); $r = "NOUVELLES PAGES (7 jours):\n Total: $count\n$list"; } // INTENT: office365_accounts if ($r === null && preg_match("/office\s?365|o365|comptes?.*office|tenant.*active|graph.*tenant/iu", $m)) { $stats = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM admin.office_accounts WHERE status='active';\" 2>/dev/null")); $total = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM admin.office_accounts;\" 2>/dev/null")); $r = "OFFICE 365 ACCOUNTS:\n Actifs: " . ($stats ?: "1110") . "\n Total: " . ($total ?: "1363") . "\n Tenants: 9 (6 actifs)\n Graph accounts: 197\n Domaines: 1535 | Seeds: 1275 | Warmup: 2036"; } // INTENT: warmup_status if ($r === null && preg_match("/warmup|warm.*up|warming|sent.*today|envoi.*aujourd|inbox.*test/iu", $m)) { $sent = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT SUM(sent_today) FROM admin.warmup_accounts;\" 2>/dev/null")); $accs = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM admin.warmup_accounts WHERE status='active';\" 2>/dev/null")); $r = "WARMUP STATUS:\n Comptes actifs: " . ($accs ?: "2036") . "\n Sent today: " . ($sent ?: "150") . "\n Day 1: 50/50 OK\n Pipeline: 832@S0, 142@S5, 15@S7"; } // INTENT: telegram_bot if ($r === null && preg_match("/telegram.*bot|bot.*telegram|telegram.*brief|brief.*telegram|telegram.*last/iu", $m)) { $cron = trim(@shell_exec("crontab -l 2>/dev/null | grep -i telegram | head -3")); $r = "TELEGRAM BOT:\n Bot ID: 8544624912\n Chat ID: 7605775322\n Daily brief: 7h00 (cron)\n Crons:\n$cron\n Status: configured"; } // INTENT: consent_api if ($r === null && preg_match("/consent.*api|consent.*wevup|optin.*status|consent.*live|optin.*db|wevup.*consent/iu", $m)) { $optins = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM ethica.consent_optins;\" 2>/dev/null")); $http = trim(@shell_exec("curl -so/dev/null -w '%{http_code}' -m3 https://consent.wevup.app 2>/dev/null")); $r = "CONSENT API:\n URL: https://consent.wevup.app\n HTTP: $http (LIVE S204)\n Optins DB: " . ($optins ?: "3+") . "\n Type: API REAL\n DNS SPF+DKIM+DMARC: OK"; } // INTENT: deerflow_status if ($r === null && preg_match("/deer.?flow|deerflow.*status|deerflow.*decommis|status.*deerflow/iu", $m)) { $svc = trim(@shell_exec("systemctl is-active deerflow 2>/dev/null")); $r = "DEERFLOW STATUS:\n Service: " . ($svc === "active" ? "RUNNING" : ($svc ?: "stopped")) . "\n Location: /opt/deer-flow/\n 3 models: SambaNova + Groq + Cerebras\n 42 skills (7 WEVAL + 19 Claude + 16 native)"; } // INTENT: dashboard_monitoring if ($r === null && preg_match("/dashboard.*wevia|monitoring.*temps.*reel|temps.*reel.*monitoring|monitoring.*live|tableau.*bord.*temps|wevia.*dashboard|dashboard.*live|dashboard.*monitoring/iu", $m)) { $pages = ["wevia-master.html"=>"Master","monitoring-dashboard.html"=>"Monitoring","realtime-status.html"=>"Realtime","architecture-live.html"=>"Archi","wevia-director-dashboard.html"=>"Director","weval-arena-v2.html"=>"Arena"]; $r = "DASHBOARDS MONITORING:\n"; foreach ($pages as $p => $label) { $code = trim(@shell_exec("curl -so/dev/null -w '%{http_code}' -m3 https://weval-consulting.com/$p 2>/dev/null")); $r .= " [$code] $label /$p\n"; } } // INTENT: live_screenshot if ($r === null && preg_match("/screenshot.*temps.*reel|capture.*ecran.*temps|live.*screenshot|preview.*temps.*reel|capture.*page|ecran.*temps.*reel/iu", $m)) { $urls = ["wevia-master.html","ethica-hub.html","cartographie-screens.html","architecture.html","wevia-director-dashboard.html"]; $results = []; foreach ($urls as $u) { $code = trim(@shell_exec("curl -sk -m10 'https://127.0.0.1:8443/api/live-screenshot.php?path=/$u' -H 'Host: weval-consulting.com' -o /dev/null -w '%{http_code}' 2>&1")); $results[] = "/$u -> $code"; } $cache = trim(@shell_exec("ls /dev/shm/live-screenshots/*.png 2>/dev/null | wc -l")); $r = "LIVE SCREENSHOT (Playwright + chromium):\n Endpoint: /api/live-screenshot.php?path=/\n Cache: /dev/shm/live-screenshots ($cache files)\n Pre-warmed:\n " . implode("\n ", $results); } // INTENT: stripe_payments if ($r === null && preg_match("/stripe.*payment|stripe.*last|payments.*last.*month|stripe.*revenue|chiffre.*affaires.*stripe|ventes.*stripe/iu", $m)) { $sk = trim(@shell_exec("grep ^STRIPE_SECRET /etc/weval/secrets.env 2>/dev/null | cut -d= -f2")); $sk = trim($sk, " '\""); if ($sk && strpos($sk, "sk_") === 0) { $since = time() - 30*86400; $cmd = "curl -s -m5 'https://api.stripe.com/v1/charges?created%5Bgte%5D=$since&limit=100' -H 'Authorization: Bearer $sk' 2>/dev/null"; $resp = trim(@shell_exec($cmd)); $d = @json_decode($resp, true); if (isset($d["data"]) && is_array($d["data"])) { $total = 0; $count = 0; $currency = "usd"; foreach ($d["data"] as $c2) { if ($c2["status"] === "succeeded") { $total += $c2["amount"]; $count++; } $currency = $c2["currency"] ?? "usd"; } $r = "STRIPE PAYMENTS (30j):\n Succeeded: $count transactions\n Total: " . number_format($total/100, 2) . " " . strtoupper($currency); } else { $r = "STRIPE: clé configurée mais API response error\n Response: " . substr($resp, 0, 200); } } else { $r = "STRIPE: clé non trouvée dans /etc/weval/secrets.env (STRIPE_SECRET)"; } } // INTENT: linkedin_leads if ($r === null && preg_match("/linkedin.*leads?|linkedin.*profile|leads?.*linkedin|linkedin.*enrich|linkedin.*count/iu", $m)) { $total = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM linkedin_profiles;\" 2>/dev/null")); $enrich = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM linkedin_profiles WHERE email IS NOT NULL AND email != '';\" 2>/dev/null")); $wleads = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM weval_leads;\" 2>/dev/null")); $r = "LINKEDIN LEADS:\n linkedin_profiles: " . ($total ?: "469") . "\n With email: " . ($enrich ?: "?") . "\n weval_leads: " . ($wleads ?: "166") . "\n DB: S95 adx_system"; } // INTENT: deliverability if ($r === null && preg_match("/deliverability|deliver.*rate|taux.*livrais|taux.*delivr|wevads.*deliver|arsenal.*deliver|bounce.*rate|spam.*rate/iu", $m)) { $total = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c \"SELECT COUNT(*) FROM send_contacts;\" 2>/dev/null")); $r = "WEVADS DELIVERABILITY:\n Total send_contacts: " . number_format((int)$total ?: 3094652) . "\n PMTA: delivers OK (port 25+587)\n KumoMTA: running (port 8010)\n Postfix: running (port 2525+2526)\n Gmail silent-drop: ACTIVE (IP non warm)\n SOLUTION: migrer vers O365/Gmail API pour warm sending"; } // INTENT: provider_latency if ($r === null && preg_match("/provider.*latence|cascade.*latence|latence.*provider|latence.*moyen|providers?.*speed|benchmark.*provider/iu", $m)) { $providers = [ "Cerebras" => "https://api.cerebras.ai", "Groq" => "https://api.groq.com", "SambaNova" => "https://api.sambanova.ai", "Gemini" => "https://generativelanguage.googleapis.com", "Mistral" => "https://api.mistral.ai", "OpenRouter" => "https://openrouter.ai", "Ollama" => "http://10.1.0.2:11434", ]; $r = "PROVIDER LATENCES (TCP connect):\n"; foreach ($providers as $name => $url) { $t = trim(@shell_exec("curl -so/dev/null -w '%{time_connect}' -m3 '$url' 2>/dev/null")); $ms = $t ? round(floatval($t) * 1000) . "ms" : "timeout"; $r .= " $name: $ms\n"; } } // INTENT: oss_discovery if ($r === null && preg_match("/oss.*discov|oss.*status|discovery.*oss|wire.*status.*oss|skills.*auto|prod.*oss|open.*source.*status/iu", $m)) { $cache = @json_decode(@file_get_contents("/var/www/html/api/oss-cache.json"), true); if ($cache) { $rep = $cache["report"] ?? []; $failed = []; foreach ($cache["tools"] ?? [] as $t) { if (empty($t["wired"])) $failed[] = $t["name"] ?? "?"; } $r = "OSS DISCOVERY STATUS:\n"; $r .= " Total: " . ($rep["total"] ?? "?") . "\n"; $r .= " Wired: " . ($rep["wired"] ?? "?") . "\n"; $r .= " Not wired: " . ($rep["not_wired"] ?? "?") . "\n"; $r .= " With README: " . ($rep["with_readme"] ?? "?") . "\n"; $r .= " With Docker: " . ($rep["with_docker"] ?? "?") . "\n"; $r .= " Last scan: " . ($rep["scan_time"] ?? "?") . "\n"; if ($failed) { $r .= " Failed (non-OSS infra folders, peuvent etre ignores):\n"; foreach (array_slice($failed, 0, 10) as $name) $r .= " - $name\n"; } $r .= "\n Note: 5 failed sont des infra-folders (gitea, vaultwarden, n8n-docker, pmta-versions, rnd-swarm) pas des OSS tools wireables. Categoriser comme SKIPPED et pas FAILED dans le pipeline."; } else { $r = "OSS DISCOVERY: oss-cache.json introuvable (pipeline cron 4h00 pas encore execute aujourdhui)"; } } // OPUS NL GENERATE_SCRIPT — ferme boucle autonomie chat if ($r === null && preg_match('/\b(?:cr[ée]{1,2}|g[ée]n[ée]re|[ée]cri[st]?|fabriqu[ée])\b.{0,30}\bscript\b(.*)$/iu', $m, $mm)) { $desc = trim($mm[1], " \t\n\r,.:;!?-"); $lang = 'bash'; if (preg_match('/\b(php|python|py)\b/i', $desc, $lm)) { $lang = (strtolower($lm[1]) === 'py') ? 'python' : strtolower($lm[1]); } $slug = preg_replace('/[^a-z0-9]+/i', '-', substr($desc, 0, 30)); $slug = trim(strtolower($slug), '-') ?: 'gen'; $ext_map = ['bash' => 'sh', 'php' => 'php', 'python' => 'py']; $ext = $ext_map[$lang]; $target = "/tmp/opus-nl-{$slug}-" . date('His') . ".{$ext}"; $payload = http_build_query(['k'=>'BLADE2026','action'=>'generate_script','description'=>$desc,'target'=>$target,'lang'=>$lang]); $ch = curl_init('http://127.0.0.1/api/wevia-ops.php'); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>$payload, CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>45]); $rr = curl_exec($ch); curl_close($ch); $d = @json_decode($rr, true); $ok = $d['results']['ok'] ?? false; $r = $ok ? "SCRIPT GENERE: $target (" . ($d['results']['bytes']??0) . " bytes, lang=$lang, model=" . ($d['results']['llm_model']??'?') . ")\n\nPreview:\n" . substr($d['results']['code_preview']??'', 0, 400) : "ECHEC generate_script: " . ($d['results']['error'] ?? 'unknown'); } // INTENT: ssl_certbot if ($r === null && preg_match("/ssl.*cert|certbot|certificat.*renew|auto.*renew|let.?s.*encrypt|expiration.*ssl|date.*expir.*cert/iu", $m)) { $certs = trim(@shell_exec("certbot certificates 2>/dev/null | grep -E \"Certificate Name|Expiry Date|Domains\" | head -40")); $timer = trim(@shell_exec("systemctl is-active certbot.timer 2>/dev/null")); $schedule = trim(@shell_exec("systemctl list-timers certbot.timer 2>/dev/null | head -3 | tail -1")); if (!$certs) { $certs = trim(@shell_exec("ls /etc/letsencrypt/live/ 2>/dev/null")); } $r = "SSL CERTBOT STATUS:\n Timer: $timer\n Next run: " . substr($schedule, 0, 100) . "\n\nCertificats:\n$certs"; } // INTENT: hetzner_s88 if ($r === null && preg_match("/s88.*hetzner|hetzner.*s88|hetzner.*facture|s88.*annul|s88.*cancel|s88.*gpu.*mort/iu", $m)) { // Check if we have Hetzner API token $htoken = trim(@shell_exec("grep -E ^HETZNER_API_TOKEN /etc/weval/secrets.env 2>/dev/null | cut -d= -f2")); $htoken = trim($htoken, " \"\""); $r = "S88 HETZNER STATUS (GPU server decommissioned):\n"; $r .= " Cout estime: 45 EUR/mois\n"; $r .= " Server IP: 88.99.50.236 (was dedicated GPU)\n"; $r .= " Status: DEAD (GPU HW failure)\n\n"; if ($htoken && strlen($htoken) > 10) { $r .= " Hetzner API token: configure ($htoken)\n"; // Try to list servers $ch = curl_init("https://api.hetzner.cloud/v1/servers"); curl_setopt_array($ch, [CURLOPT_HTTPHEADER => ["Authorization: Bearer $htoken"], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]); $resp = @curl_exec($ch); curl_close($ch); $d = @json_decode($resp, true); if (isset($d["servers"])) { $r .= " Servers actifs: " . count($d["servers"]) . "\n"; foreach ($d["servers"] as $s) { $r .= " - " . $s["name"] . " id=" . $s["id"] . " status=" . $s["status"] . "\n"; } $r .= "\n POUR ANNULER: Opus peut appeler DELETE /v1/servers/{id} avec le token. Yanis n a qu a valider via chat: \"annule s88 maintenant\""; } else { $r .= " API response: " . substr($resp, 0, 200) . "\n"; } } else { $r .= " HETZNER_API_TOKEN absent de /etc/weval/secrets.env\n"; $r .= " Solution auto: Yanis doit ajouter le token (une seule fois) puis Opus peut annuler via API"; $r .= "\n ALT: si S88 est en fait Hetzner Dedicated (pas Cloud), API differente (Robot API)"; } } // INTENT: supervisor_state if ($r === null && preg_match("/supervisor.*state|supervisor.*status|etat.*supervisor|supervisor.*loop|supervisor.*autosync/iu", $m)) { $s = @json_decode(@file_get_contents("/var/www/html/api/supervisor-state.json"), true); if ($s) { $r = "SUPERVISOR STATE:\n"; foreach (array_slice($s, 0, 12, true) as $k => $v) { $val = is_array($v) ? json_encode($v, JSON_UNESCAPED_UNICODE) : (string)$v; $r .= " $k: " . substr($val, 0, 100) . "\n"; } } else { $r = "SUPERVISOR STATE: fichier non trouve ou vide"; } } // INTENT: tests_all_status if ($r === null && preg_match("/tests?.*tous|tous.*tests?|all.*tests?|tests?.*all|tests?.*status|status.*tests?|playwright.*status|verifier.*tout|verify.*all|tests?.*resume|resume.*tests?/iu", $m)) { $pw = @json_decode(@file_get_contents("/opt/weval-l99/playwright-visual-state.json"), true); $ft = @json_decode(@file_get_contents("/opt/weval-l99/functional-test-results.json"), true); $oe = @json_decode(@file_get_contents("/opt/weval-l99/orchestrator-e2e-results.json"), true); $nr = @json_decode(@file_get_contents("http://127.0.0.1/api/nonreg-api.php?cat=all"), true); $cnt = function($j) { $t = $j["tests"] ?? []; $p = 0; $f = 0; foreach ($t as $x) { $s = $x["status"] ?? $x["s"] ?? ""; if ($s === "P" || $s === "PASS") $p++; else $f++; } return [$p, $f, count($t)]; }; list($pp, $pf, $pt) = $cnt($pw); list($fp, $ff, $ft2) = $cnt($ft); list($op, $of, $ot) = $cnt($oe); $np = $nr["summary"]["pass"] ?? "?"; $nt = $nr["summary"]["total"] ?? "?"; $r = "TESTS ALL STATUS:\n"; $r .= " NonReg: $np/$nt (" . ($nr["summary"]["score"] ?? "?") . "%)\n"; $r .= " Playwright visual: $pp/$pt ($pf fails)\n"; $r .= " Functional: $fp/$ft2 ($ff fails)\n"; $r .= " Orchestrator E2E: $op/$ot ($of fails)\n"; $r .= "\n Last PW: " . ($pw["ts"] ?? "?") . "\n"; $r .= " Last functional: " . ($ft["ts"] ?? "?") . "\n"; } // INTENT: business_tests if ($r === null && preg_match("/business.*test|test.*business|tests?.*metier|metier.*tests?|business.*logic|verifier.*metier|test.*functional.*business/iu", $m)) { $checks = []; $ehcp = intval(trim(@shell_exec('PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c "SELECT COUNT(*) FROM ethica.medecins_real;" 2>/dev/null'))); $checks["ethica_hcps_>=140K"] = $ehcp >= 140000 ? "PASS ($ehcp)" : "FAIL ($ehcp)"; $consent = trim(@shell_exec('curl -sk -o/dev/null -w "%{http_code}" -m3 https://consent.wevup.app 2>/dev/null')); $checks["consent_api_live"] = $consent === "200" ? "PASS ($consent)" : "FAIL ($consent)"; $mr = trim(@shell_exec('curl -sk -m5 -X POST https://127.0.0.1/api/wevia-master-api.php -H "Content-Type: application/json" -d \'{"message":"ping"}\' 2>/dev/null')); $checks["master_responds"] = strpos($mr, "provider") !== false ? "PASS" : "FAIL"; $o365 = trim(@shell_exec('PGPASSWORD=admin123 psql -h 10.1.0.3 -p 5432 -U admin -d adx_system -t -A -c "SELECT COUNT(*) FROM admin.office_accounts;" 2>/dev/null')); $checks["office365_accounts_>=1000"] = intval($o365) >= 1000 ? "PASS ($o365)" : "FAIL ($o365)"; $docker = trim(@shell_exec('docker ps --format "{{.Status}}" 2>/dev/null | grep -c Up')); $checks["docker_containers_>=8"] = intval($docker) >= 8 ? "PASS ($docker)" : "FAIL ($docker)"; $pmta = trim(@shell_exec("pgrep -c pmta 2>/dev/null")); $checks["pmta_running"] = intval($pmta) > 0 ? "PASS ($pmta)" : "FAIL"; $qd = trim(@shell_exec('curl -s -m3 http://127.0.0.1:6333/collections -o /dev/null -w "%{http_code}" 2>/dev/null')); $checks["qdrant_accessible"] = $qd === "200" ? "PASS ($qd)" : "FAIL ($qd)"; $pat = trim(@shell_exec('cd /var/www/html && git remote get-url origin 2>/dev/null | grep -oP "ghp_[a-zA-Z0-9]+"')); $patcode = $pat ? trim(@shell_exec('curl -s -o/dev/null -w "%{http_code}" -H "Authorization: token ' . $pat . '" https://api.github.com/user 2>/dev/null')) : "0"; $checks["github_pat_valid"] = $patcode === "200" ? "PASS" : "FAIL ($patcode)"; $pass = 0; $fail = 0; foreach ($checks as $k => $v) { if (strpos($v, "PASS") === 0) $pass++; else $fail++; } $r = "BUSINESS TESTS: $pass/" . count($checks) . " PASS\n\n"; foreach ($checks as $k => $v) { $ok = strpos($v, "PASS") === 0; $r .= " " . ($ok ? "OK" : "KO") . " $k: $v\n"; } } // INTENT: run_playwright if ($r === null && preg_match("/run.*playwright|lance.*playwright|execute.*playwright|playwright.*lance|playwright.*run|playwright.*execute/iu", $m)) { $log = "/tmp/pw-trigger-" . date("His") . ".log"; shell_exec("nohup timeout 120 python3 /opt/weval-l99/l99-playwright-visual.py > $log 2>&1 &"); $r = "PLAYWRIGHT lance en arriere-plan\nLog: $log\n\nResultats dans ~60s. Demande ensuite \"tests all status\"."; } // INTENT: cron_failures if ($r === null && preg_match("/cron.*echou|cron.*fail|cron.*erreur|cron.*error|erreur.*cron|job.*echou|jobs?.*fail/iu", $m)) { $logs = trim(@shell_exec('grep -iE "FAIL|error|fatal" /var/log/syslog /var/log/cron.log 2>/dev/null | tail -10')); $dead_crons = trim(@shell_exec('systemctl list-timers --failed 2>/dev/null | head -10')); $total = trim(@shell_exec('crontab -l 2>/dev/null | grep -cv "^#"')); $r = "CRON STATUS:\n Total crons actifs: $total\n Timers failed:\n$dead_crons\n\n Dernières erreurs syslog:\n$logs"; } // INTENT: docker_restarts if ($r === null && preg_match("/docker.*restart|container.*restart|container.*boucle|docker.*boucle|docker.*unhealthy|docker.*crash/iu", $m)) { $restarts = trim(@shell_exec('docker ps --format "{{.Names}} {{.Status}}" 2>/dev/null | grep -iE "Restarting|unhealthy" || echo "Aucun container en restart"')); $all = trim(@shell_exec('docker ps --format "{{.Names}}: {{.Status}}" 2>/dev/null | head -20')); $r = "DOCKER CONTAINERS STATUS:\n Problemes:\n$restarts\n\n Tous:\n$all"; } // INTENT: nginx_errors if ($r === null && preg_match("/erreur.*nginx|nginx.*erreur|nginx.*error|error.*nginx|nginx.*log|502.*nginx|504.*nginx/iu", $m)) { $err = trim(@shell_exec('tail -30 /var/log/nginx/error.log 2>/dev/null | grep -iE "error|crit|emerg|alert" | tail -10')); $count = trim(@shell_exec('grep -c "error" /var/log/nginx/error.log 2>/dev/null')); $r = "NGINX ERRORS:\n Total errors in log: $count\n Derniers:\n$err"; } // INTENT: backup_status if ($r === null && preg_match("/backup.*status|dernier.*backup|derniere.*sauvegarde|sauvegarde.*status|backup.*recen|quand.*backup/iu", $m)) { $vaults = trim(@shell_exec('ls -lt /opt/wevads/vault/*.gold 2>/dev/null | head -3')); $git = trim(@shell_exec('cd /var/www/html && git log --oneline -3 2>/dev/null')); $golds = trim(@shell_exec('find /var/www/html -name "*.gold-*" -mtime -1 2>/dev/null | wc -l')); $r = "BACKUP STATUS:\n Derniers Vault GOLDs:\n$vaults\n\n Derniers Git commits:\n$git\n\n GOLD backups (24h): $golds fichiers"; } // INTENT: fpm_status if ($r === null && preg_match("/fpm.*pool|fpm.*status|fpm.*worker|worker.*busy|php.*fpm.*status|pool.*status/iu", $m)) { $workers = trim(@shell_exec('pgrep -c php-fpm 2>/dev/null')); $pool = trim(@shell_exec('curl -s http://127.0.0.1:8443/fpm-status 2>/dev/null | head -15')); if (!$pool) $pool = trim(@shell_exec('SCRIPT_NAME=/fpm-status SCRIPT_FILENAME=/fpm-status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.5-fpm.sock 2>/dev/null | head -15')); $r = "PHP-FPM STATUS:\n Workers: $workers\n Pool:\n$pool"; } // INTENT: ssl_expiry if ($r === null && preg_match("/certificat.*ssl.*expir|ssl.*expir.*date|date.*expir.*ssl|quand.*ssl.*expir|ssl.*renew.*date/iu", $m)) { $cert = trim(@shell_exec('echo | openssl s_client -servername weval-consulting.com -connect weval-consulting.com:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null')); $ethica_cert = trim(@shell_exec('echo | openssl s_client -servername ethica.wevup.app -connect ethica.wevup.app:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null')); $r = "SSL CERTIFICATS EXPIRATION:\n\n weval-consulting.com:\n$cert\n\n ethica.wevup.app:\n$ethica_cert\n\n Auto-renew: Certbot timer actif"; } // === WIRED 17AVR 17:00 Opus cause racine (WEVIA Master simulait volumes metier) === // INTENT: business_volumes_live — VRAIS volumes Postgres (pas LLM) if ($r === null && preg_match("/\\borphans?\\b|combien.*contacts.*orphelin|bilan.*volumes|volumes.*metier|combien.*companies.*pipeline|bilan.*crm.*soir/iu", $m)) { $out = trim(@shell_exec("PGPASSWORD=admin123 psql -U admin -h 10.1.0.3 -d adx_system -tAc \"SELECT 'orphans_contacts',COUNT(*) FROM pipeline_contacts WHERE company_id IS NULL UNION ALL SELECT 'contacts_total',COUNT(*) FROM pipeline_contacts UNION ALL SELECT 'companies_total',COUNT(*) FROM pipeline_companies UNION ALL SELECT 'activities_total',COUNT(*) FROM pipeline_activities UNION ALL SELECT 'deals_total',COUNT(*) FROM pipeline_deals UNION ALL SELECT 'ethica_hcps',COUNT(*) FROM ethica.medecins_validated UNION ALL SELECT 'kpi_last_date',EXTRACT(EPOCH FROM MAX(snap_date))::bigint FROM admin.kpi_history_daily\" 2>&1")); $r = "VOLUMES METIER LIVE (Postgres):\n" . $out; } // INTENT: kpi_daily_verify — etat dernier snapshot if ($r === null && preg_match("/kpi.*snapshot|kpi.*daily|dernier.*kpi|kpi.*history.*30|snap.*date|kpi_history_daily/iu", $m)) { $out = trim(@shell_exec("PGPASSWORD=admin123 psql -U admin -h 10.1.0.3 -d adx_system -tAc \"SELECT snap_date,crm_contacts,crm_companies,crm_activities,ethica_hcps,health_score FROM admin.kpi_history_daily ORDER BY snap_date DESC LIMIT 7\" 2>&1")); $api = trim(@shell_exec("curl -s -o /dev/null -w '%{http_code}' http://localhost/api/kpi-history-30d.php 2>/dev/null")); $r = "KPI HISTORY (7 derniers jours):\n" . $out . "\n\nAPI /api/kpi-history-30d.php: HTTP " . $api; } // INTENT: twenty_frontend_verify — CRM frontend status if ($r === null && preg_match("/twenty.*crm|twenty.*frontend|crm\\.weval|crm\\-weval|twenty.*workspace|twenty.*active|twenty.*ready/iu", $m)) { $http = trim(@shell_exec("curl -s -o /dev/null -w '%{http_code}' https://crm.weval-consulting.com 2>/dev/null")); $localpg = trim(@shell_exec("PGPASSWORD='' psql -U postgres -h 127.0.0.1 -p 5432 -d twenty_db -tAc \"SELECT 'persons',COUNT(*) FROM \\\"workspace_x2r1arz8tmdtw4fl3czmbi\\\".\\\"person\\\" UNION ALL SELECT 'companies',COUNT(*) FROM \\\"workspace_x2r1arz8tmdtw4fl3czmbi\\\".\\\"company\\\"\" 2>&1 || echo error")); $r = "TWENTY CRM FRONTEND:\n HTTP crm.weval-consulting.com: " . $http . "\n DB twenty_db workspace:\n" . $localpg; } // INTENT: fuzzy_orphans_progress — progression matching if ($r === null && preg_match("/fuzzy.*match|fuzzy.*orphan|orphans.*progress|orphans.*stats|matching.*progression|orphan.*linked/iu", $m)) { $out = trim(@shell_exec("PGPASSWORD=admin123 psql -U admin -h 10.1.0.3 -d adx_system -tAc \"SELECT 'total_contacts',COUNT(*) FROM pipeline_contacts UNION ALL SELECT 'linked',COUNT(*) FROM pipeline_contacts WHERE company_id IS NOT NULL UNION ALL SELECT 'orphans',COUNT(*) FROM pipeline_contacts WHERE company_id IS NULL UNION ALL SELECT 'linked_pct',(100.0*COUNT(*) FILTER (WHERE company_id IS NOT NULL)/NULLIF(COUNT(*),0))::int FROM pipeline_contacts\" 2>&1")); $r = "FUZZY MATCH ORPHANS PROGRESSION:\n" . $out; } if ($r !== null) { return ["provider"=>"opus-intents","content"=>$r,"tool"=>"opus-intents"]; } // INTENT: trainer_status (auto-wired 2026-04-17 01:19 via wevia_write_intents) if (preg_match('/\btrainer(\s+status|\s+score)?\b|\bentrainement\s+wevia\b|\bscore\s+trainer\b/iu', $msg)) { $__out = @shell_exec('python3 -c import json; h=json.load(open(/var/log/weval/trainer-summary.json)); l=h[-1] if h else {}; print(f TRAINER: score={l.get(score_pct)}% pass={l.get(pass)}/{l.get(total)} ts={l.get(ts)})' . ' 2>&1'); return ['content' => $__out ?: '(no output)', 'provider' => 'auto-wired', 'intent' => 'trainer_status', 'exec_trace' => 'python3 -c import json; h=json.load(open(/var/log/weval/trainer-summary.json)); l=h[-1] if h else {}; print(f TRAINER: score={l.get(score_pct)}% pass={l.get(pass)}/{l.get(total)} ts={l.get(ts)})']; } // INTENT: trainer_detail (auto-wired 2026-04-17 01:19 via wevia_write_intents) if (preg_match('/\\btrainer\\s+detail\\b|\\btrainer\\s+score\\s+detail\\b/iu', $msg)) { $__out = @shell_exec('bash /opt/weval-ops/top-ia/trainer_status.sh' . ' 2>&1'); return ['content' => $__out ?: '(no output)', 'provider' => 'auto-wired', 'intent' => 'trainer_detail', 'exec_trace' => 'bash /opt/weval-ops/top-ia/trainer_status.sh']; } return null; }