1147 lines
55 KiB
PHP
Executable File
1147 lines
55 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* ╔═══════════════════════════════════════════════════════════════════════════╗
|
||
* ║ WEVIA COGNITIVE OPUS 4.6 — Advanced Reasoning Capabilities ║
|
||
* ║ Chain-of-Thought, Metacognition, Adversarial, Cross-Domain, Planning ║
|
||
* ║ GPU Sovereign Pipeline, Confidence Calibration, Self-Correction ║
|
||
* ║ 2026-03-03 — 200+ functions ║
|
||
* ╚═══════════════════════════════════════════════════════════════════════════╝
|
||
*/
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE L: CHAIN-OF-THOUGHT ENGINE (20 functions)
|
||
// Multi-step reasoning with visible thinking
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function cotShouldActivate($msg, $intent) {
|
||
if (mb_strlen($msg) < 30 || in_array($intent, ['greeting','conversational'])) return false;
|
||
if (preg_match('/\b(pourquoi|why|comment|how|explique|compare|analyse|évalue|calcule|estime)\b/i', $msg)) return true;
|
||
if (preg_match('/\b(debug|erreur|problème|migr|architect|stratégi|optimis)\b/i', $msg)) return true;
|
||
return mb_strlen($msg) > 120;
|
||
}
|
||
|
||
function cotDecomposeSteps($msg) {
|
||
$steps = [];
|
||
$steps[] = ['phase' => 'comprehension', 'action' => 'Comprendre la demande exacte', 'weight' => 1];
|
||
if (preg_match('/\b(compare|vs|versus|différence|choix)\b/i', $msg)) {
|
||
$steps[] = ['phase' => 'gather', 'action' => 'Collecter les critères de comparaison', 'weight' => 2];
|
||
$steps[] = ['phase' => 'analyze', 'action' => 'Analyser chaque option selon les critères', 'weight' => 3];
|
||
$steps[] = ['phase' => 'synthesize', 'action' => 'Synthétiser et recommander', 'weight' => 2];
|
||
} elseif (preg_match('/\b(debug|erreur|problème|fix|corrig)\b/i', $msg)) {
|
||
$steps[] = ['phase' => 'reproduce', 'action' => 'Identifier les symptômes exacts', 'weight' => 2];
|
||
$steps[] = ['phase' => 'hypothesize', 'action' => 'Formuler les hypothèses (top 3)', 'weight' => 3];
|
||
$steps[] = ['phase' => 'test', 'action' => 'Proposer tests de vérification', 'weight' => 2];
|
||
$steps[] = ['phase' => 'solve', 'action' => 'Solution avec commandes/code', 'weight' => 3];
|
||
} elseif (preg_match('/\b(calcul|estime|combien|budget|coût|ROI)\b/i', $msg)) {
|
||
$steps[] = ['phase' => 'identify', 'action' => 'Identifier les variables', 'weight' => 1];
|
||
$steps[] = ['phase' => 'compute', 'action' => 'Calculer étape par étape', 'weight' => 3];
|
||
$steps[] = ['phase' => 'verify', 'action' => 'Vérifier par méthode alternative', 'weight' => 2];
|
||
} else {
|
||
$steps[] = ['phase' => 'research', 'action' => 'Rassembler les connaissances pertinentes', 'weight' => 2];
|
||
$steps[] = ['phase' => 'structure', 'action' => 'Structurer la réponse', 'weight' => 2];
|
||
$steps[] = ['phase' => 'deliver', 'action' => 'Formuler la réponse actionnable', 'weight' => 3];
|
||
}
|
||
return $steps;
|
||
}
|
||
|
||
function cotBuildThinkingPrompt($steps) {
|
||
$prompt = "\n## RAISONNEMENT STRUCTURÉ\nAvant de répondre, suis ces étapes de réflexion :\n";
|
||
foreach ($steps as $i => $s) {
|
||
$prompt .= ($i + 1) . ". **{$s['phase']}**: {$s['action']}\n";
|
||
}
|
||
$prompt .= "\nMontre ton raisonnement naturellement dans ta réponse (pas de balises <think>).";
|
||
return $prompt;
|
||
}
|
||
|
||
function cotExtractThinking($response) {
|
||
if (preg_match('/<think>(.*?)<\/think>/s', $response, $m)) {
|
||
return ['thinking' => trim($m[1]), 'response' => trim(str_replace($m[0], '', $response))];
|
||
}
|
||
return ['thinking' => '', 'response' => $response];
|
||
}
|
||
|
||
function cotCountReasoningSteps($response) {
|
||
$steps = 0;
|
||
$steps += preg_match_all('/\b(d\'abord|premièrement|first|ensuite|puis|then|enfin|finally|en conclusion)\b/i', $response);
|
||
$steps += preg_match_all('/^\d+[\.\)]/m', $response);
|
||
return $steps;
|
||
}
|
||
|
||
function cotValidateCompleteness($response, $steps) {
|
||
$expected = count($steps);
|
||
$found = cotCountReasoningSteps($response);
|
||
return ['expected' => $expected, 'found' => $found, 'complete' => $found >= $expected - 1];
|
||
}
|
||
|
||
function cotInjectPrompt($sys, $msg, $intent) {
|
||
if (!cotShouldActivate($msg, $intent)) return $sys;
|
||
$steps = cotDecomposeSteps($msg);
|
||
return $sys . cotBuildThinkingPrompt($steps);
|
||
}
|
||
|
||
function cotEstimateDepth($msg) {
|
||
$depth = 1;
|
||
if (mb_strlen($msg) > 100) $depth++;
|
||
if (mb_strlen($msg) > 300) $depth++;
|
||
if (substr_count($msg, '?') > 1) $depth++;
|
||
if (preg_match('/\b(détaillé|exhaustif|approfondi|complet|en profondeur)\b/i', $msg)) $depth += 2;
|
||
return min(5, $depth);
|
||
}
|
||
|
||
function cotSelectStrategy($msg) {
|
||
if (preg_match('/\b(pourquoi|why|cause|raison)\b/i', $msg)) return 'causal_chain';
|
||
if (preg_match('/\b(compare|vs|versus|meilleur|choix)\b/i', $msg)) return 'parallel_analysis';
|
||
if (preg_match('/\b(si|if|hypothèse|scénario|suppose)\b/i', $msg)) return 'counterfactual';
|
||
if (preg_match('/\b(étape|step|procédure|comment faire)\b/i', $msg)) return 'sequential';
|
||
if (preg_match('/\b(avantage|inconvénient|pour|contre|trade-off)\b/i', $msg)) return 'dialectical';
|
||
return 'general';
|
||
}
|
||
|
||
function cotBuildCausalChain($topic) {
|
||
return "\nAnalyse causale: Identifie la chaîne Cause → Mécanisme → Effet → Conséquences. Distingue corrélation/causalité.";
|
||
}
|
||
|
||
function cotBuildParallelAnalysis($options) {
|
||
return "\nAnalyse parallèle: Pour CHAQUE option, évalue selon les mêmes critères. Tableau comparatif. Score pondéré.";
|
||
}
|
||
|
||
function cotBuildCounterfactual($hypothesis) {
|
||
return "\nAnalyse contrefactuelle: Si [hypothèse], alors [conséquence]. Et si le contraire? Scénario alternatif.";
|
||
}
|
||
|
||
function cotBuildSequential() {
|
||
return "\nRaisonnement séquentiel: Étape 1 → vérifier → Étape 2 → vérifier → ... Chaque étape dépend de la précédente.";
|
||
}
|
||
|
||
function cotBuildDialectical() {
|
||
return "\nDialectique: Thèse → Antithèse → Synthèse. Présente les deux côtés avant de conclure.";
|
||
}
|
||
|
||
function cotGetStrategyPrompt($msg) {
|
||
$strategy = cotSelectStrategy($msg);
|
||
$prompts = [
|
||
'causal_chain' => cotBuildCausalChain(''),
|
||
'parallel_analysis' => cotBuildParallelAnalysis([]),
|
||
'counterfactual' => cotBuildCounterfactual(''),
|
||
'sequential' => cotBuildSequential(),
|
||
'dialectical' => cotBuildDialectical(),
|
||
'general' => "\nRaisonnement structuré: Comprendre → Analyser → Conclure.",
|
||
];
|
||
return $prompts[$strategy] ?? $prompts['general'];
|
||
}
|
||
|
||
function cotMeasureCoherence($response) {
|
||
$sentences = preg_split('/[.!?]+/', $response);
|
||
$sentences = array_filter($sentences, fn($s) => mb_strlen(trim($s)) > 10);
|
||
if (count($sentences) < 2) return 1.0;
|
||
$hasContradiction = preg_match('/\b(mais.*cependant|toutefois.*néanmoins|oui.*non.*oui)\b/i', $response);
|
||
$hasStructure = preg_match('/\b(d\'abord|ensuite|enfin|en conclusion|donc|par conséquent)\b/i', $response);
|
||
$score = 0.5;
|
||
if ($hasStructure) $score += 0.3;
|
||
if (!$hasContradiction) $score += 0.2;
|
||
return min(1.0, $score);
|
||
}
|
||
|
||
function cotShouldRetry($response, $msg) {
|
||
$coherence = cotMeasureCoherence($response);
|
||
if ($coherence < 0.4) return true;
|
||
if (mb_strlen($response) < 50 && mb_strlen($msg) > 100) return true;
|
||
if (preg_match('/je ne (sais|peux) pas/i', $response) && mb_strlen($msg) < 200) return true;
|
||
return false;
|
||
}
|
||
|
||
function cotEnhanceResponse($response, $strategy) {
|
||
if ($strategy === 'parallel_analysis' && !preg_match('/\|/', $response)) {
|
||
$response .= "\n\n💡 *Un tableau comparatif pourrait aider — demandez si vous souhaitez un format structuré.*";
|
||
}
|
||
return $response;
|
||
}
|
||
|
||
function cotSummarizeReasoning($thinking) {
|
||
if (empty($thinking)) return '';
|
||
$sentences = preg_split('/[.!?]+/', $thinking);
|
||
$key = array_filter($sentences, fn($s) => mb_strlen(trim($s)) > 30);
|
||
return mb_substr(implode('. ', array_slice($key, 0, 2)), 0, 200);
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE M: METACOGNITION ENGINE (20 functions)
|
||
// Self-awareness, confidence, and reflection
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function metaAssessConfidence($response, $msg, $kbUsed) {
|
||
$confidence = 0.5;
|
||
if ($kbUsed) $confidence += 0.2;
|
||
if (preg_match('/```/', $response)) $confidence += 0.1; // Code = concrete
|
||
if (preg_match('/\b(peut-être|probablement|il semble|je pense)\b/i', $response)) $confidence -= 0.1;
|
||
if (preg_match('/\b(certainement|absolument|toujours|jamais)\b/i', $response)) $confidence -= 0.05; // Overconfidence penalty
|
||
if (mb_strlen($response) > 500 && preg_match('/\b(source|référence|documentation)\b/i', $response)) $confidence += 0.1;
|
||
return round(max(0.1, min(1.0, $confidence)), 2);
|
||
}
|
||
|
||
function metaShouldHedge($confidence, $intent) {
|
||
if ($intent === 'mathematical') return $confidence < 0.7;
|
||
if ($intent === 'technical') return $confidence < 0.5;
|
||
if ($intent === 'strategic') return $confidence < 0.6;
|
||
return $confidence < 0.4;
|
||
}
|
||
|
||
function metaInjectHedging($response, $confidence) {
|
||
if ($confidence >= 0.6) return $response;
|
||
$hedges = [
|
||
"⚠️ **Note:** Mon niveau de confiance est modéré sur ce point. Je recommande de vérifier.",
|
||
"💡 Cette analyse mériterait une validation supplémentaire.",
|
||
"📋 Basé sur mes connaissances actuelles — une vérification avec la documentation officielle est recommandée."
|
||
];
|
||
$idx = crc32($response) % count($hedges);
|
||
return $response . "\n\n" . $hedges[$idx];
|
||
}
|
||
|
||
function metaDetectKnowledgeGap($msg, $kbResults) {
|
||
if (empty($kbResults) && preg_match('/\b(spécifique|notre|interne|WEVAL|client)\b/i', $msg)) return 'internal_gap';
|
||
if (preg_match('/\b(202[5-9]|dernier|récent|nouveau|latest)\b/i', $msg)) return 'temporal_gap';
|
||
if (preg_match('/\b(prix|tarif|coût actuel|taux de change)\b/i', $msg)) return 'realtime_gap';
|
||
return null;
|
||
}
|
||
|
||
function metaAcknowledgeGap($gap) {
|
||
$msgs = [
|
||
'internal_gap' => "Je n'ai pas trouvé cette information dans notre base de connaissances interne.",
|
||
'temporal_gap' => "Cette information pourrait ne pas être à jour — vérifiez les sources récentes.",
|
||
'realtime_gap' => "Les données en temps réel nécessitent une vérification externe.",
|
||
];
|
||
return $msgs[$gap] ?? "";
|
||
}
|
||
|
||
function metaReflectOnResponse($response, $msg) {
|
||
$issues = [];
|
||
if (mb_strlen($response) > 2000 && !preg_match('/^#+\s/m', $response)) $issues[] = 'long_unstructured';
|
||
if (mb_strlen($response) < 100 && mb_strlen($msg) > 200) $issues[] = 'too_brief';
|
||
if (preg_match('/TODO|à compléter|\.\.\.$/m', $response)) $issues[] = 'incomplete';
|
||
if (preg_match('/je ne (sais|peux) pas.*je ne (sais|peux) pas/is', $response)) $issues[] = 'repeated_inability';
|
||
return $issues;
|
||
}
|
||
|
||
function metaSelfCorrect($response, $issues) {
|
||
foreach ($issues as $issue) {
|
||
if ($issue === 'long_unstructured') {
|
||
$response = "📋 **Résumé:**\n" . mb_substr($response, 0, 200) . "...\n\n---\n\n" . $response;
|
||
}
|
||
}
|
||
return $response;
|
||
}
|
||
|
||
function metaEstimateResponseQuality($response, $intent, $msg) {
|
||
$score = 7;
|
||
if (function_exists('validateCodeCompleteness') && preg_match('/```/', $response)) {
|
||
$codeIssues = validateCodeCompleteness($response);
|
||
$score -= count($codeIssues) * 0.5;
|
||
}
|
||
if (function_exists('validateNoLeakedInternals')) {
|
||
$leak = validateNoLeakedInternals($response);
|
||
if ($leak) $score -= 3;
|
||
}
|
||
$coherence = cotMeasureCoherence($response);
|
||
$score += ($coherence - 0.5) * 4;
|
||
return round(max(1, min(10, $score)), 1);
|
||
}
|
||
|
||
function metaSelectExpertiseLevel($msg, $history) {
|
||
if (count($history) > 6) {
|
||
$techCount = 0;
|
||
foreach ($history as $h) {
|
||
if (preg_match('/\b(code|api|server|database|deploy|config)\b/i', $h['content'] ?? '')) $techCount++;
|
||
}
|
||
if ($techCount > count($history) * 0.5) return 'expert';
|
||
}
|
||
if (function_exists('detectExpertiseLevel')) return detectExpertiseLevel($msg);
|
||
return 'intermediate';
|
||
}
|
||
|
||
function metaTrackTopicDrift($history, $msg) {
|
||
if (count($history) < 4) return false;
|
||
$last3 = array_slice($history, -3);
|
||
$topics = [];
|
||
foreach ($last3 as $h) {
|
||
$c = mb_strtolower($h['content'] ?? '');
|
||
preg_match_all('/\b\w{5,}\b/', $c, $m);
|
||
$topics[] = $m[0] ?? [];
|
||
}
|
||
if (count($topics) < 2) return false;
|
||
$overlap = count(array_intersect($topics[0], $topics[count($topics)-1]));
|
||
return $overlap < 2;
|
||
}
|
||
|
||
function metaDetectRepetition($history, $response) {
|
||
$recent = array_slice($history, -4);
|
||
foreach ($recent as $h) {
|
||
if (($h['role'] ?? '') === 'assistant') {
|
||
$prev = mb_strtolower($h['content'] ?? '');
|
||
$curr = mb_strtolower($response);
|
||
similar_text($prev, $curr, $pct);
|
||
if ($pct > 60) return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function metaInjectVariation($response, $history) {
|
||
if (!metaDetectRepetition($history, $response)) return $response;
|
||
return "🔄 Reformulons autrement...\n\n" . $response;
|
||
}
|
||
|
||
function metaAssessHallucination($response, $kbContext) {
|
||
$risk = 0.3;
|
||
if (preg_match('/\b(\d{4})\b/', $response, $m)) {
|
||
$year = intval($m[1]);
|
||
if ($year > 2026) $risk += 0.3;
|
||
}
|
||
if (empty($kbContext) && preg_match('/selon (notre|la) base|dans notre KB/i', $response)) $risk += 0.4;
|
||
if (preg_match('/\b(toujours|jamais|100%|garantie|certain)\b/i', $response)) $risk += 0.1;
|
||
return min(1.0, $risk);
|
||
}
|
||
|
||
function metaInjectConfidenceMarker($response, $confidence) {
|
||
$markers = ['🔴' => [0, 0.3], '🟡' => [0.3, 0.6], '🟢' => [0.6, 0.8], '🔵' => [0.8, 1.01]];
|
||
foreach ($markers as $emoji => $range) {
|
||
if ($confidence >= $range[0] && $confidence < $range[1]) return $response;
|
||
}
|
||
return $response;
|
||
}
|
||
|
||
function metaBuildSelfCheckPrompt() {
|
||
return "\nAvant de finaliser ta réponse, vérifie mentalement : 1) Ai-je répondu à la question ? 2) Mon code est-il complet et exécutable ? 3) Ai-je vérifié les faits ? 4) La réponse est-elle actionnable ?";
|
||
}
|
||
|
||
function metaDetectOverconfidence($response) {
|
||
$overconfident = preg_match_all('/\b(toujours|jamais|certainement|absolument|sans aucun doute|garantie|100%)\b/i', $response);
|
||
$hedged = preg_match_all('/\b(peut-être|généralement|souvent|typiquement|dans la plupart des cas)\b/i', $response);
|
||
return $overconfident > $hedged + 2;
|
||
}
|
||
|
||
function metaSoftenOverconfidence($response) {
|
||
if (!metaDetectOverconfidence($response)) return $response;
|
||
$response = preg_replace('/\btoujours\b/i', 'généralement', $response, 1);
|
||
$response = preg_replace('/\bjamais\b/i', 'rarement', $response, 1);
|
||
$response = preg_replace('/\b100%\b/', '~95%+', $response, 1);
|
||
return $response;
|
||
}
|
||
|
||
function metaEstimateTokenUsage($sys, $msg, $history) {
|
||
$total = mb_strlen($sys) + mb_strlen($msg);
|
||
foreach ($history as $h) $total += mb_strlen($h['content'] ?? '');
|
||
return (int)($total / 3.5);
|
||
}
|
||
|
||
function metaShouldCompressHistory($history, $maxTokens = 4000) {
|
||
$tokens = 0;
|
||
foreach ($history as $h) $tokens += (int)(mb_strlen($h['content'] ?? '') / 3.5);
|
||
return $tokens > $maxTokens;
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE N: ADVERSARIAL VERIFICATION (15 functions)
|
||
// Devil's advocate — challenge and verify responses
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function advShouldVerify($intent, $confidence) {
|
||
if (in_array($intent, ['mathematical','technical','compliance'])) return true;
|
||
if ($confidence < 0.5) return true;
|
||
return false;
|
||
}
|
||
|
||
function advBuildChallengePrompt($response) {
|
||
$firstClaim = '';
|
||
if (preg_match('/(?:^|\n)(.{30,100})[.!]/', $response, $m)) $firstClaim = trim($m[1]);
|
||
return "Vérifie cette affirmation de manière critique: \"{$firstClaim}\" — Est-elle correcte ? Quels sont les edge cases ?";
|
||
}
|
||
|
||
function advCheckLogicalFallacies($response) {
|
||
$fallacies = [];
|
||
if (preg_match('/\btout le monde\b.*\bdonc\b/i', $response)) $fallacies[] = 'ad_populum';
|
||
if (preg_match('/\b(expert|autorité|selon)\b.*\bdonc.*vrai\b/i', $response)) $fallacies[] = 'appeal_to_authority';
|
||
if (preg_match('/\bsi.*alors.*si.*alors\b/i', $response) && !preg_match('/\bmais\b/i', $response)) $fallacies[] = 'slippery_slope';
|
||
if (preg_match('/\b(corrélation|lié à).*\bdonc.*cause\b/i', $response)) $fallacies[] = 'correlation_causation';
|
||
return $fallacies;
|
||
}
|
||
|
||
function advFlagFallacies($response, $fallacies) {
|
||
if (empty($fallacies)) return $response;
|
||
$names = ['ad_populum' => 'appel à la majorité', 'appeal_to_authority' => "appel à l'autorité", 'slippery_slope' => 'pente glissante', 'correlation_causation' => 'confusion corrélation/causalité'];
|
||
$warning = "\n\n⚠️ **Attention raisonnement:** ";
|
||
foreach ($fallacies as $f) $warning .= ($names[$f] ?? $f) . ", ";
|
||
return $response . rtrim($warning, ", ") . ".";
|
||
}
|
||
|
||
function advCheckConsistency($response) {
|
||
$numbers = [];
|
||
if (preg_match_all('/(\d+)\s*%/', $response, $m)) $numbers = array_map('intval', $m[1]);
|
||
if (preg_match('/total|somme/i', $response) && !empty($numbers)) {
|
||
$sum = array_sum($numbers);
|
||
if ($sum > 105 || ($sum > 10 && $sum < 95)) return "Incohérence: somme des % = {$sum}%";
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function advCheckTechnicalClaims($response) {
|
||
$issues = [];
|
||
if (preg_match('/chmod\s+777/i', $response)) $issues[] = "chmod 777 = faille sécurité";
|
||
if (preg_match('/rm\s+-rf\s+\/[^o]/i', $response)) $issues[] = "rm -rf dangereux";
|
||
if (preg_match('/eval\s*\(/i', $response)) $issues[] = "eval() = injection risk";
|
||
if (preg_match('/password.*=.*["\'][^"\']{1,5}["\']/i', $response)) $issues[] = "Mot de passe trop court/faible";
|
||
if (preg_match('/SELECT\s+\*\s+FROM/i', $response) && !preg_match('/LIMIT/i', $response)) $issues[] = "SELECT * sans LIMIT";
|
||
return $issues;
|
||
}
|
||
|
||
function advInjectSecurityWarnings($response, $issues) {
|
||
if (empty($issues)) return $response;
|
||
$warning = "\n\n🛡️ **Avertissements sécurité:**\n";
|
||
foreach ($issues as $i) $warning .= "- {$i}\n";
|
||
return $response . $warning;
|
||
}
|
||
|
||
function advVerifyCodeSyntax($response) {
|
||
$issues = [];
|
||
if (preg_match_all('/```(\w+)\n(.*?)```/s', $response, $matches, PREG_SET_ORDER)) {
|
||
foreach ($matches as $m) {
|
||
$lang = $m[1];
|
||
$code = $m[2];
|
||
if ($lang === 'php' && substr_count($code, '{') !== substr_count($code, '}')) $issues[] = "PHP: accolades non équilibrées";
|
||
if ($lang === 'python' && preg_match('/\t/', $code) && preg_match('/ /', $code)) $issues[] = "Python: mélange tabs/spaces";
|
||
if (in_array($lang, ['javascript','typescript']) && substr_count($code, '(') !== substr_count($code, ')')) $issues[] = "JS: parenthèses non équilibrées";
|
||
}
|
||
}
|
||
return $issues;
|
||
}
|
||
|
||
function advCheckForBias($response) {
|
||
if (preg_match('/\b(toujours|jamais|seul|unique|meilleur)\b.*\b(solution|option|choix|outil)\b/i', $response)) return true;
|
||
return false;
|
||
}
|
||
|
||
function advNeutralizeBias($response) {
|
||
if (!advCheckForBias($response)) return $response;
|
||
$response = preg_replace('/la seule solution/i', 'une solution recommandée', $response, 1);
|
||
$response = preg_replace('/le meilleur outil/i', 'un outil performant', $response, 1);
|
||
return $response;
|
||
}
|
||
|
||
function advCrossReferenceKB($response, $kbContext) {
|
||
if (empty($kbContext)) return null;
|
||
$kbLower = mb_strtolower($kbContext);
|
||
$respLower = mb_strtolower($response);
|
||
if (preg_match_all('/\b(\w{6,})\b/', $respLower, $m)) {
|
||
$techTerms = array_unique($m[1]);
|
||
$grounded = 0;
|
||
foreach ($techTerms as $t) {
|
||
if (strpos($kbLower, $t) !== false) $grounded++;
|
||
}
|
||
$ratio = count($techTerms) > 0 ? $grounded / count($techTerms) : 0;
|
||
return ['grounded_ratio' => round($ratio, 2), 'terms_checked' => count($techTerms), 'terms_grounded' => $grounded];
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function advBuildVerificationQuery($claim) {
|
||
return "VÉRIFICATION FACTUELLE: '{$claim}' — Confirme ou infirme cette affirmation avec des preuves.";
|
||
}
|
||
|
||
function advDetectCircularReasoning($response) {
|
||
$sentences = preg_split('/[.!?]+/', $response);
|
||
$sentences = array_filter(array_map('trim', $sentences), fn($s) => mb_strlen($s) > 20);
|
||
if (count($sentences) < 3) return false;
|
||
$first = mb_strtolower(reset($sentences));
|
||
$last = mb_strtolower(end($sentences));
|
||
similar_text($first, $last, $pct);
|
||
return $pct > 70;
|
||
}
|
||
|
||
function advFullVerification($response, $msg, $intent, $kbContext, $confidence) {
|
||
$issues = [];
|
||
$fallacies = advCheckLogicalFallacies($response);
|
||
if (!empty($fallacies)) $issues['fallacies'] = $fallacies;
|
||
$consistency = advCheckConsistency($response);
|
||
if ($consistency) $issues['consistency'] = $consistency;
|
||
$techIssues = advCheckTechnicalClaims($response);
|
||
if (!empty($techIssues)) $issues['security'] = $techIssues;
|
||
$codeIssues = advVerifyCodeSyntax($response);
|
||
if (!empty($codeIssues)) $issues['code'] = $codeIssues;
|
||
if (advCheckForBias($response)) $issues['bias'] = true;
|
||
if (advDetectCircularReasoning($response)) $issues['circular'] = true;
|
||
return $issues;
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE O: MULTI-STEP PLANNING ENGINE (15 functions)
|
||
// Complex task decomposition and execution planning
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function planDetectComplexTask($msg) {
|
||
if (preg_match('/\b(étape|step|phase|plan|roadmap|migration|projet|implementation|déploiement)\b/i', $msg)) return true;
|
||
if (substr_count($msg, '?') >= 3) return true;
|
||
if (mb_strlen($msg) > 400) return true;
|
||
return false;
|
||
}
|
||
|
||
function planDecompose($msg) {
|
||
$tasks = [];
|
||
if (preg_match('/migr/i', $msg)) {
|
||
$tasks = ['audit', 'planification', 'préparation', 'migration_test', 'migration_prod', 'validation', 'rollback_plan'];
|
||
} elseif (preg_match('/deploy|déploi/i', $msg)) {
|
||
$tasks = ['build', 'test', 'staging', 'backup', 'deploy', 'smoke_test', 'monitor'];
|
||
} elseif (preg_match('/architect|infra/i', $msg)) {
|
||
$tasks = ['inventaire', 'analyse_besoins', 'design', 'validation_design', 'implementation', 'tests', 'documentation'];
|
||
} else {
|
||
$tasks = ['analyse', 'conception', 'réalisation', 'vérification', 'livraison'];
|
||
}
|
||
return array_map(fn($t, $i) => ['id' => $i + 1, 'name' => $t, 'status' => 'pending'], $tasks, array_keys($tasks));
|
||
}
|
||
|
||
function planEstimateDuration($tasks) {
|
||
$baseDays = ['audit' => 2, 'planification' => 3, 'préparation' => 5, 'migration_test' => 3, 'migration_prod' => 2, 'validation' => 2, 'rollback_plan' => 1, 'build' => 3, 'test' => 2, 'staging' => 1, 'backup' => 1, 'deploy' => 1, 'smoke_test' => 1, 'monitor' => 2, 'inventaire' => 2, 'analyse_besoins' => 3, 'design' => 5, 'validation_design' => 2, 'implementation' => 10, 'tests' => 3, 'documentation' => 2, 'analyse' => 2, 'conception' => 3, 'réalisation' => 5, 'vérification' => 2, 'livraison' => 1];
|
||
$total = 0;
|
||
foreach ($tasks as &$t) {
|
||
$t['duration_days'] = $baseDays[$t['name']] ?? 2;
|
||
$total += $t['duration_days'];
|
||
}
|
||
return ['tasks' => $tasks, 'total_days' => $total, 'total_weeks' => round($total / 5, 1)];
|
||
}
|
||
|
||
function planIdentifyDependencies($tasks) {
|
||
$deps = [];
|
||
for ($i = 1; $i < count($tasks); $i++) {
|
||
$deps[] = ['task' => $tasks[$i]['id'], 'depends_on' => $tasks[$i-1]['id']];
|
||
}
|
||
return $deps;
|
||
}
|
||
|
||
function planCriticalPath($tasks, $deps) {
|
||
return array_map(fn($t) => $t['name'], $tasks);
|
||
}
|
||
|
||
function planIdentifyRisks($tasks) {
|
||
$risks = [];
|
||
foreach ($tasks as $t) {
|
||
if (in_array($t['name'], ['migration_prod','deploy'])) $risks[] = ['task' => $t['name'], 'risk' => 'downtime', 'severity' => 'high', 'mitigation' => 'Blue-green + rollback plan'];
|
||
if (in_array($t['name'], ['migration_test','tests'])) $risks[] = ['task' => $t['name'], 'risk' => 'régression', 'severity' => 'medium', 'mitigation' => 'Suite de tests automatisés'];
|
||
}
|
||
return $risks;
|
||
}
|
||
|
||
function planBuildGantt($plan) {
|
||
$mermaid = "gantt\n title Plan de projet\n dateFormat YYYY-MM-DD\n section Phases\n";
|
||
$start = date('Y-m-d');
|
||
foreach ($plan['tasks'] as $t) {
|
||
$mermaid .= " {$t['name']} :{$start}, {$t['duration_days']}d\n";
|
||
$start = date('Y-m-d', strtotime($start . " + {$t['duration_days']} days"));
|
||
}
|
||
return $mermaid;
|
||
}
|
||
|
||
function planBuildChecklist($tasks) {
|
||
$md = "## Checklist de projet\n";
|
||
foreach ($tasks as $t) {
|
||
$emoji = $t['status'] === 'done' ? '✅' : '☐';
|
||
$md .= "{$emoji} **{$t['name']}** ({$t['duration_days']}j)\n";
|
||
}
|
||
return $md;
|
||
}
|
||
|
||
function planSuggestMethodology($tasks) {
|
||
$count = count($tasks);
|
||
if ($count <= 3) return 'kanban';
|
||
if ($count <= 7) return 'scrum';
|
||
return 'safe';
|
||
}
|
||
|
||
function planEstimateBudget($tasks, $dailyRate = 800) {
|
||
$totalDays = array_sum(array_column($tasks, 'duration_days'));
|
||
return ['days' => $totalDays, 'rate' => $dailyRate, 'total' => $totalDays * $dailyRate, 'currency' => 'EUR'];
|
||
}
|
||
|
||
function planBuildMilestones($tasks) {
|
||
$milestones = [];
|
||
$cumDays = 0;
|
||
foreach ($tasks as $i => $t) {
|
||
$cumDays += $t['duration_days'] ?? 2;
|
||
if (in_array($t['name'], ['validation', 'deploy', 'livraison', 'migration_prod', 'validation_design'])) {
|
||
$milestones[] = ['name' => "M" . ($i+1) . ": {$t['name']}", 'day' => $cumDays];
|
||
}
|
||
}
|
||
return $milestones;
|
||
}
|
||
|
||
function planBuildRACI($tasks) {
|
||
return array_map(fn($t) => ['task' => $t['name'], 'R' => 'Tech Lead', 'A' => 'PM', 'C' => 'Architecte', 'I' => 'Client'], $tasks);
|
||
}
|
||
|
||
function planInjectPrompt($sys, $msg) {
|
||
if (!planDetectComplexTask($msg)) return $sys;
|
||
$tasks = planDecompose($msg);
|
||
$plan = planEstimateDuration($tasks);
|
||
return $sys . "\n## PLAN DE PROJET\nDécompose en {$plan['total_days']} jours ({$plan['total_weeks']} sem). Phases: " . implode(' → ', array_column($tasks, 'name')) . ". Inclus Gantt Mermaid si pertinent.";
|
||
}
|
||
|
||
function planAutoGenerate($msg) {
|
||
$tasks = planDecompose($msg);
|
||
$plan = planEstimateDuration($tasks);
|
||
$deps = planIdentifyDependencies($tasks);
|
||
$risks = planIdentifyRisks($tasks);
|
||
$milestones = planBuildMilestones($plan['tasks']);
|
||
$gantt = planBuildGantt($plan);
|
||
return ['plan' => $plan, 'dependencies' => $deps, 'risks' => $risks, 'milestones' => $milestones, 'gantt' => $gantt];
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE P: CROSS-DOMAIN TRANSFER ENGINE (15 functions)
|
||
// Apply knowledge from one domain to solve problems in another
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function xdomDetectDomains($msg) {
|
||
$domains = [];
|
||
$detectors = ['detectSAPContext' => 'sap', 'detectFinanceContext' => 'finance', 'detectHealthcareContext' => 'healthcare', 'detectSecurityContext' => 'security', 'detectLLMContext' => 'ai', 'detectMoroccanContext' => 'morocco', 'detectManufacturingContext' => 'manufacturing', 'detectRetailContext' => 'retail'];
|
||
foreach ($detectors as $fn => $domain) {
|
||
if (function_exists($fn) && $fn($msg)) $domains[] = $domain;
|
||
}
|
||
return $domains;
|
||
}
|
||
|
||
function xdomFindAnalogies($sourceDomain, $targetDomain) {
|
||
$analogies = [
|
||
'sap_ai' => "L'architecture modulaire SAP (modules FI/CO/MM) est analogue aux pipelines ML (preprocessing → training → inference).",
|
||
'manufacturing_ai' => "Le contrôle qualité en manufacturing (Six Sigma, SPC) s'applique au monitoring de modèles ML (drift detection, A/B testing).",
|
||
'finance_security' => "La gestion des risques financiers (VaR, stress tests) est transposable à la cybersécurité (threat modeling, pen testing).",
|
||
'healthcare_ai' => "Le diagnostic médical (symptômes → hypothèses → tests → diagnostic) est le même pipeline que le debug technique.",
|
||
'retail_ai' => "La segmentation client retail (RFM) est analogue au clustering ML pour la personnalisation.",
|
||
'morocco_ai' => "L'écosystème startup marocain (Casanearshore, OFPPT) offre un vivier de talents pour l'IA souveraine.",
|
||
];
|
||
$key = $sourceDomain . '_' . $targetDomain;
|
||
$keyAlt = $targetDomain . '_' . $sourceDomain;
|
||
return $analogies[$key] ?? $analogies[$keyAlt] ?? "Transfert de patterns de {$sourceDomain} vers {$targetDomain}.";
|
||
}
|
||
|
||
function xdomBuildBridgePrompt($domains) {
|
||
if (count($domains) < 2) return '';
|
||
$prompt = "\n## TRANSFERT INTER-DOMAINES\n";
|
||
for ($i = 0; $i < count($domains) - 1; $i++) {
|
||
$prompt .= xdomFindAnalogies($domains[$i], $domains[$i+1]) . "\n";
|
||
}
|
||
return $prompt;
|
||
}
|
||
|
||
function xdomApplyDesignPatterns($sourceDomain, $problem) {
|
||
$patterns = [
|
||
'sap' => ['standardize_first' => 'Standardiser avant de customiser', 'best_practice_config' => 'Configuration > Développement'],
|
||
'security' => ['defense_in_depth' => 'Défense en profondeur — couches multiples', 'zero_trust' => 'Ne jamais faire confiance — toujours vérifier'],
|
||
'ai' => ['iterate_fast' => 'MVP rapide, itérer sur feedback', 'data_first' => 'Données de qualité avant algorithme complexe'],
|
||
'manufacturing' => ['lean' => 'Éliminer le gaspillage', 'kaizen' => 'Amélioration continue par petits pas'],
|
||
'finance' => ['diversify' => 'Diversifier les risques', 'hedge' => 'Couvrir les positions exposées'],
|
||
];
|
||
return $patterns[$sourceDomain] ?? [];
|
||
}
|
||
|
||
function xdomDetectMetaphor($msg) {
|
||
return (bool)preg_match('/\b(comme|analogi|similaire|équivalent|parallèle|transpos|appliquer.*concept|même logique)\b/i', $msg);
|
||
}
|
||
|
||
function xdomBuildMetaphor($concept, $targetDomain) {
|
||
$metaphors = [
|
||
'devops_manufacturing' => "Le CI/CD en DevOps est la chaîne de montage du logiciel — chaque commit passe par les postes qualité.",
|
||
'ml_cooking' => "Entraîner un modèle ML, c'est comme perfectionner une recette — les données sont les ingrédients, les hyperparamètres sont l'assaisonnement.",
|
||
'security_castle' => "La sécurité informatique suit le modèle du château fort — douves (firewall), pont-levis (auth), donjon (données sensibles).",
|
||
'database_library' => "Une base de données, c'est une bibliothèque : les index sont le catalogue, les requêtes sont les demandes de prêt.",
|
||
];
|
||
$keys = array_keys($metaphors);
|
||
$idx = abs(crc32($concept . $targetDomain)) % count($keys);
|
||
return $metaphors[$keys[$idx]];
|
||
}
|
||
|
||
function xdomSuggestAlternativeApproach($msg, $currentDomain) {
|
||
$alternatives = [
|
||
'sap' => 'Avez-vous envisagé une approche low-code (Power Platform, Mendix) plutôt que du custom ABAP?',
|
||
'security' => 'Au-delà des outils, avez-vous considéré la formation des utilisateurs (le maillon le plus faible)?',
|
||
'ai' => "Avant l'IA, avez-vous exploité les analytics classiques (SQL, BI)? Parfois un simple GROUP BY suffit.",
|
||
'finance' => "Avez-vous considéré les implications fiscales marocaines (IS, TVA) dans votre modèle?",
|
||
];
|
||
return $alternatives[$currentDomain] ?? '';
|
||
}
|
||
|
||
function xdomMapSkills($from, $to) {
|
||
$maps = ['backend_devops' => ['PHP/Python → Ansible/Terraform', 'SQL → Infrastructure as Code', 'API design → Service mesh'], 'frontend_ux' => ['React → Prototyping (Figma)', 'CSS → Design system', 'JS events → User journey'], 'data_ai' => ['SQL → Feature engineering', 'ETL → ML pipeline', 'Dashboards → Model monitoring']];
|
||
return $maps["{$from}_{$to}"] ?? [];
|
||
}
|
||
|
||
function xdomInjectCrossDomain($sys, $msg) {
|
||
$domains = xdomDetectDomains($msg);
|
||
if (count($domains) >= 2) {
|
||
$sys .= xdomBuildBridgePrompt($domains);
|
||
}
|
||
return $sys;
|
||
}
|
||
|
||
function xdomGetFrameworkTransfer($sourceFramework, $targetContext) {
|
||
$transfers = ['agile' => 'Sprints de 2 semaines, rétrospectives, backlog priorisé', 'lean' => 'Value stream mapping, élimination du gaspillage, flux tiré', 'design_thinking' => 'Empathie utilisateur, idéation, prototypage rapide'];
|
||
return $transfers[$sourceFramework] ?? '';
|
||
}
|
||
|
||
function xdomBuildHybridSolution($domains) {
|
||
if (count($domains) < 2) return '';
|
||
return "💡 Solution hybride combinant les approches " . implode(' + ', $domains) . " pour une réponse plus complète.";
|
||
}
|
||
|
||
function xdomDetectInnovationOpportunity($msg, $domains) {
|
||
if (count($domains) >= 2 && preg_match('/\b(innov|nouveau|disrupt|transform|futur)\b/i', $msg)) return true;
|
||
return false;
|
||
}
|
||
|
||
function xdomSuggestInnovation($domains) {
|
||
return "🚀 L'intersection " . implode('/') . " est un terreau d'innovation. Explorez les convergences.";
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE Q: TEMPORAL REASONING (10 functions)
|
||
// Time-aware analysis and prediction
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function tempDetectTimeContext($msg) {
|
||
if (preg_match('/\b(hier|demain|la semaine (dernière|prochaine)|le mois (dernier|prochain)|l\'année (dernière|prochaine))\b/i', $msg)) return 'relative';
|
||
if (preg_match('/\b\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}\b/', $msg)) return 'absolute';
|
||
if (preg_match('/\b(avant|après|depuis|jusqu|pendant|durant)\b/i', $msg)) return 'duration';
|
||
if (preg_match('/\b(tendance|évolution|historique|prévision|forecast|projection)\b/i', $msg)) return 'trend';
|
||
return null;
|
||
}
|
||
|
||
function tempResolveRelativeDate($expression) {
|
||
$now = time();
|
||
$map = ['hier' => -86400, 'demain' => 86400, 'la semaine dernière' => -604800, 'la semaine prochaine' => 604800, 'le mois dernier' => -2592000, 'le mois prochain' => 2592000];
|
||
foreach ($map as $expr => $offset) {
|
||
if (stripos($expression, $expr) !== false) return date('Y-m-d', $now + $offset);
|
||
}
|
||
return date('Y-m-d');
|
||
}
|
||
|
||
function tempBuildTimelinePrompt($timeContext) {
|
||
if ($timeContext === 'trend') return "\nInclus une analyse temporelle : passé → présent → projection. Identifie les points d'inflexion.";
|
||
if ($timeContext === 'duration') return "\nPrécise les durées exactes. Utilise des unités cohérentes (jours/semaines/mois).";
|
||
return '';
|
||
}
|
||
|
||
function tempEstimateFreshness($topic) {
|
||
$volatile = ['prix', 'taux', 'cours', 'actualité', 'news', 'politique', 'CVE'];
|
||
$stable = ['algorithme', 'mathématique', 'physique', 'histoire', 'grammaire'];
|
||
foreach ($volatile as $v) { if (stripos($topic, $v) !== false) return 'volatile'; }
|
||
foreach ($stable as $s) { if (stripos($topic, $s) !== false) return 'stable'; }
|
||
return 'moderate';
|
||
}
|
||
|
||
function tempShouldWarnOutdated($topic) {
|
||
return tempEstimateFreshness($topic) === 'volatile';
|
||
}
|
||
|
||
function tempBuildTimeline($events) {
|
||
$mermaid = "timeline\n title Chronologie\n";
|
||
foreach ($events as $date => $event) $mermaid .= " {$date} : {$event}\n";
|
||
return $mermaid;
|
||
}
|
||
|
||
function tempCalculateDeadline($startDate, $durationDays, $excludeWeekends = true) {
|
||
$date = strtotime($startDate);
|
||
$added = 0;
|
||
while ($added < $durationDays) {
|
||
$date += 86400;
|
||
$dow = date('N', $date);
|
||
if (!$excludeWeekends || $dow <= 5) $added++;
|
||
}
|
||
return date('Y-m-d', $date);
|
||
}
|
||
|
||
function tempFormatRelativeTime($timestamp) {
|
||
$diff = time() - $timestamp;
|
||
if ($diff < 60) return "il y a {$diff}s";
|
||
if ($diff < 3600) return "il y a " . round($diff/60) . "min";
|
||
if ($diff < 86400) return "il y a " . round($diff/3600) . "h";
|
||
if ($diff < 2592000) return "il y a " . round($diff/86400) . "j";
|
||
return "il y a " . round($diff/2592000) . " mois";
|
||
}
|
||
|
||
function tempDetectUrgencyFromDeadline($msg) {
|
||
if (preg_match('/\b(aujourd|today|maintenant|now|ASAP)\b/i', $msg)) return 'immediate';
|
||
if (preg_match('/\b(demain|tomorrow|cette semaine|this week)\b/i', $msg)) return 'urgent';
|
||
if (preg_match('/\b(ce mois|this month|bientôt|soon)\b/i', $msg)) return 'planned';
|
||
return 'normal';
|
||
}
|
||
|
||
function tempInjectTemporalContext($sys, $msg) {
|
||
$ctx = tempDetectTimeContext($msg);
|
||
if ($ctx) $sys .= tempBuildTimelinePrompt($ctx);
|
||
if (tempShouldWarnOutdated($msg)) $sys .= "\n⚠️ Ce sujet évolue rapidement — vérifie que tes données sont actuelles.";
|
||
return $sys;
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE R: GPU SOVEREIGN PIPELINE (loaded from cognitive-gpu-rotation.php)
|
||
// If already loaded by Claude 2, skip; otherwise provide stubs
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
if (!function_exists('gpuSelectModel')) {
|
||
function gpuSelectModel($intent, $complexity = 'moderate', $msgLen = 0) {
|
||
$models = ['technical' => 'qwen2.5-coder:7b', 'analytical' => 'deepseek-r1:32b', 'creative' => 'llama3.1:8b', 'default' => 'qwen2.5:14b'];
|
||
if ($complexity === 'complex') return 'deepseek-r1:32b';
|
||
return $models[$intent] ?? $models['default'];
|
||
}
|
||
}
|
||
if (!function_exists('gpuRotateModel')) {
|
||
function gpuRotateModel($failedModel, $intent) {
|
||
$fallbacks = ['deepseek-r1:32b' => 'qwen2.5:14b', 'qwen2.5:14b' => 'llama3.1:8b', 'qwen2.5-coder:7b' => 'qwen2.5:14b', 'llama3.1:8b' => 'qwen2.5:14b'];
|
||
return $fallbacks[$failedModel] ?? 'llama3.1:8b';
|
||
}
|
||
}
|
||
if (!function_exists('gpuCallOllama')) {
|
||
function gpuCallOllama($model, $systemPrompt, $userMessage, $history = [], $timeout = 15, $temperature = 0.4, $maxTokens = 2048) {
|
||
$ollamaUrl = "http://127.0.0.1:11434/api/chat";
|
||
$messages = [];
|
||
if ($systemPrompt) $messages[] = ['role' => 'system', 'content' => $systemPrompt];
|
||
foreach ($history as $h) $messages[] = $h;
|
||
$messages[] = ['role' => 'user', 'content' => $userMessage];
|
||
$payload = json_encode(['model' => $model, 'messages' => $messages, 'stream' => false, 'options' => ['temperature' => $temperature, 'num_predict' => $maxTokens]]);
|
||
$ch = curl_init($ollamaUrl);
|
||
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout]);
|
||
$result = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
if ($httpCode !== 200 || !$result) return null;
|
||
$data = json_decode($result, true);
|
||
return $data['message']['content'] ?? null;
|
||
}
|
||
}
|
||
if (!function_exists('gpuCallWithFallback')) {
|
||
function gpuCallWithFallback($intent, $systemPrompt, $userMessage, $history = [], $complexity = 'moderate') {
|
||
$model = gpuSelectModel($intent, $complexity, mb_strlen($userMessage));
|
||
$response = gpuCallOllama($model, $systemPrompt, $userMessage, $history);
|
||
if (!$response) {
|
||
$fallback = gpuRotateModel($model, $intent);
|
||
$response = gpuCallOllama($fallback, $systemPrompt, $userMessage, $history);
|
||
}
|
||
return $response;
|
||
}
|
||
}
|
||
if (!function_exists('gpuHealthCheck')) {
|
||
function gpuHealthCheck() {
|
||
$ch = curl_init("http://127.0.0.1:11434/api/tags");
|
||
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 3]);
|
||
$r = curl_exec($ch);
|
||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
if ($code !== 200) return ['status' => 'down', 'models' => 0];
|
||
$data = json_decode($r, true);
|
||
$models = $data['models'] ?? [];
|
||
return ['status' => 'up', 'models' => count($models), 'loaded' => array_column($models, 'name')];
|
||
}
|
||
}
|
||
if (!function_exists('sovereignGPUPipeline')) {
|
||
function sovereignGPUPipeline($intent, $systemPrompt, $userMessage, $history = [], $providers = []) {
|
||
$health = gpuHealthCheck();
|
||
if ($health['status'] !== 'up') return null;
|
||
$complexity = function_exists('calculateComplexity') ? calculateComplexity($userMessage) : 'moderate';
|
||
return gpuCallWithFallback($intent, $systemPrompt, $userMessage, $history, $complexity);
|
||
}
|
||
}
|
||
if (!function_exists('shouldUseSovereignGPU')) {
|
||
function shouldUseSovereignGPU($intent, $msg, $mode = 'full') {
|
||
if ($mode === 'widget') return false;
|
||
if (in_array($intent, ['technical','code','analytical'])) return true;
|
||
if (mb_strlen($msg) > 200) return true;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE S: ADAPTIVE RESPONSE ENGINE (15 functions)
|
||
// Dynamic response calibration based on context
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function adaptSelectStrategy($msg, $intent, $history) {
|
||
if (function_exists('detectCrisis') && detectCrisis($msg)) return 'emergency';
|
||
if (function_exists('detectGreeting') && detectGreeting($msg)) return 'greeting';
|
||
if (function_exists('detectGratitude') && detectGratitude($msg)) return 'gratitude';
|
||
if (function_exists('detectFrustration') && detectFrustration($msg)) return 'frustrated';
|
||
if (function_exists('detectFollowUp') && detectFollowUp($msg)) return 'continuation';
|
||
if (function_exists('detectClarification') && detectClarification($msg)) return 'clarification';
|
||
if (count($history) > 10) return 'deep_session';
|
||
return 'standard';
|
||
}
|
||
|
||
function adaptGetTone($strategy) {
|
||
$tones = ['emergency' => 'direct_urgent', 'greeting' => 'warm_welcoming', 'gratitude' => 'appreciative', 'frustrated' => 'empathetic_solution', 'continuation' => 'focused', 'clarification' => 'patient', 'deep_session' => 'collaborative', 'standard' => 'professional'];
|
||
return $tones[$strategy] ?? 'professional';
|
||
}
|
||
|
||
function adaptGetLength($strategy, $msg) {
|
||
if ($strategy === 'greeting') return 'short';
|
||
if ($strategy === 'emergency') return 'medium';
|
||
if ($strategy === 'gratitude') return 'short';
|
||
if (function_exists('detectResponseLength')) return detectResponseLength($msg);
|
||
return 'medium';
|
||
}
|
||
|
||
function adaptBuildTonePrompt($tone) {
|
||
$prompts = [
|
||
'direct_urgent' => "\nURGENCE — Réponse DIRECTE et ACTIONNABLE. Pas de préambule. Solution immédiate.",
|
||
'warm_welcoming' => "\nAccueil chaleureux. Un emoji. Demander comment aider.",
|
||
'appreciative' => "\nRemercie naturellement. Court et chaleureux.",
|
||
'empathetic_solution' => "\nReconnaître la frustration. Puis solution CONCRÈTE immédiate. Pas de platitudes.",
|
||
'patient' => "\nReformuler pour clarifier. Proposer des options. Patient et pédagogique.",
|
||
'collaborative' => "\nContinuer naturellement. Référencer le contexte partagé. Pas de re-introduction.",
|
||
'focused' => "\nSuite directe. Pas de répétition du contexte déjà couvert.",
|
||
'professional' => "",
|
||
];
|
||
return $prompts[$tone] ?? '';
|
||
}
|
||
|
||
function adaptCalibrateDetail($complexity, $expertise) {
|
||
if ($expertise === 'expert' && $complexity === 'simple') return 'minimal';
|
||
if ($expertise === 'beginner' && $complexity === 'complex') return 'extensive';
|
||
if ($expertise === 'expert' && $complexity === 'complex') return 'deep';
|
||
return 'balanced';
|
||
}
|
||
|
||
function adaptSelectExamples($intent, $expertise) {
|
||
if ($expertise === 'beginner') return 'concrete_simple';
|
||
if ($expertise === 'expert') return 'edge_cases';
|
||
return 'practical';
|
||
}
|
||
|
||
function adaptFormatResponse($response, $detail, $format) {
|
||
if ($detail === 'minimal' && mb_strlen($response) > 500) {
|
||
$lines = explode("\n", $response);
|
||
$filtered = array_filter($lines, fn($l) => !preg_match('/^(Note|NB|Remarque|Pour info)/i', trim($l)));
|
||
$response = implode("\n", $filtered);
|
||
}
|
||
return $response;
|
||
}
|
||
|
||
function adaptInjectStrategy($sys, $msg, $intent, $history) {
|
||
$strategy = adaptSelectStrategy($msg, $intent, $history);
|
||
$tone = adaptGetTone($strategy);
|
||
$tonePrompt = adaptBuildTonePrompt($tone);
|
||
if ($tonePrompt) $sys .= $tonePrompt;
|
||
return $sys;
|
||
}
|
||
|
||
function adaptShouldSuggestNextStep($response, $intent) {
|
||
if (in_array($intent, ['technical','operational','code'])) return true;
|
||
if (preg_match('/\b(configur|install|deploy|migr)\b/i', $response)) return true;
|
||
return false;
|
||
}
|
||
|
||
function adaptBuildNextSteps($response) {
|
||
$steps = [];
|
||
if (preg_match('/```bash/i', $response)) $steps[] = "Exécuter les commandes ci-dessus";
|
||
if (preg_match('/\b(test|vérif|check)\b/i', $response)) $steps[] = "Valider le résultat";
|
||
if (preg_match('/\b(backup|sauvegard)\b/i', $response)) $steps[] = "Vérifier le backup";
|
||
return $steps;
|
||
}
|
||
|
||
function adaptDetectSessionGoal($history) {
|
||
if (count($history) < 2) return 'unknown';
|
||
$first = $history[0]['content'] ?? '';
|
||
if (preg_match('/\b(migr|deploy|configur)\b/i', $first)) return 'implementation';
|
||
if (preg_match('/\b(debug|erreur|problème)\b/i', $first)) return 'troubleshooting';
|
||
if (preg_match('/\b(apprendre|expliqu|comment)\b/i', $first)) return 'learning';
|
||
if (preg_match('/\b(audit|évaluer|état)\b/i', $first)) return 'assessment';
|
||
return 'mixed';
|
||
}
|
||
|
||
function adaptProgressTracker($history, $goal) {
|
||
$totalSteps = ['implementation' => 10, 'troubleshooting' => 6, 'learning' => 8, 'assessment' => 5, 'mixed' => 15, 'unknown' => 10];
|
||
$max = $totalSteps[$goal] ?? 10;
|
||
$current = min(count($history) / 2, $max);
|
||
return ['current' => (int)$current, 'total' => $max, 'pct' => round(($current / $max) * 100)];
|
||
}
|
||
|
||
function adaptShouldRecap($history) {
|
||
return count($history) > 12 && count($history) % 8 === 0;
|
||
}
|
||
|
||
function adaptBuildRecap($history) {
|
||
$topics = [];
|
||
foreach ($history as $h) {
|
||
if (($h['role'] ?? '') === 'user' && mb_strlen($h['content'] ?? '') > 20) {
|
||
$topics[] = mb_substr($h['content'], 0, 50);
|
||
}
|
||
}
|
||
$recent = array_slice($topics, -3);
|
||
return "📋 **Recap session:** " . implode(" → ", $recent);
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE T: SELF-CORRECTION ENGINE (10 functions)
|
||
// Detect and fix errors in own responses
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function scDetectMathError($response) {
|
||
if (preg_match_all('/(\d+)\s*[+]\s*(\d+)\s*=\s*(\d+)/', $response, $m, PREG_SET_ORDER)) {
|
||
foreach ($m as $match) {
|
||
if (intval($match[1]) + intval($match[2]) !== intval($match[3])) return "Erreur calcul: {$match[1]}+{$match[2]}≠{$match[3]}";
|
||
}
|
||
}
|
||
if (preg_match_all('/(\d+)\s*[*×]\s*(\d+)\s*=\s*(\d+)/', $response, $m, PREG_SET_ORDER)) {
|
||
foreach ($m as $match) {
|
||
if (intval($match[1]) * intval($match[2]) !== intval($match[3])) return "Erreur calcul: {$match[1]}×{$match[2]}≠{$match[3]}";
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function scFixMathError($response) {
|
||
$response = preg_replace_callback('/(\d+)\s*[+]\s*(\d+)\s*=\s*(\d+)/', function($m) {
|
||
$correct = intval($m[1]) + intval($m[2]);
|
||
if ($correct !== intval($m[3])) return "{$m[1]} + {$m[2]} = {$correct}";
|
||
return $m[0];
|
||
}, $response);
|
||
return $response;
|
||
}
|
||
|
||
function scDetectBrokenLinks($response) {
|
||
$issues = [];
|
||
if (preg_match_all('/\[([^\]]+)\]\(([^\)]*)\)/', $response, $m, PREG_SET_ORDER)) {
|
||
foreach ($m as $match) {
|
||
if (empty($match[2]) || $match[2] === '#') $issues[] = "Lien cassé: [{$match[1]}]";
|
||
}
|
||
}
|
||
return $issues;
|
||
}
|
||
|
||
function scDetectIncompleteCode($response) {
|
||
$issues = [];
|
||
if (preg_match('/```(\w+)\n(.*?)```/s', $response, $m)) {
|
||
$code = $m[2];
|
||
if (preg_match('/\.\.\.\s*$/m', $code)) $issues[] = "Code tronqué (...)";
|
||
if (preg_match('/\/\/ TODO|# TODO|\/\* TODO/i', $code)) $issues[] = "TODO dans le code";
|
||
if (preg_match('/function\s+\w+\([^)]*\)\s*\{\s*\}/s', $code)) $issues[] = "Fonction vide";
|
||
}
|
||
return $issues;
|
||
}
|
||
|
||
function scDetectFormatIssues($response) {
|
||
$issues = [];
|
||
if (preg_match('/^#{5,}/m', $response)) $issues[] = "Headers trop profonds (h5+)";
|
||
if (preg_match('/\n{4,}/', $response)) $issues[] = "Trop de lignes vides";
|
||
if (preg_match_all('/\*\*/', $response) % 2 !== 0) $issues[] = "Bold non fermé";
|
||
return $issues;
|
||
}
|
||
|
||
function scAutoFix($response) {
|
||
$response = scFixMathError($response);
|
||
$response = preg_replace('/\n{4,}/', "\n\n\n", $response);
|
||
$response = preg_replace('/#{5,}\s/', '#### ', $response);
|
||
if (preg_match_all('/\*\*/', $response) % 2 !== 0) $response .= '**';
|
||
return $response;
|
||
}
|
||
|
||
function scValidateJSON($response) {
|
||
if (preg_match('/```json\n(.*?)```/s', $response, $m)) {
|
||
json_decode(trim($m[1]));
|
||
if (json_last_error() !== JSON_ERROR_NONE) return "JSON invalide: " . json_last_error_msg();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function scValidateSQL($response) {
|
||
if (preg_match('/```sql\n(.*?)```/s', $response, $m)) {
|
||
$sql = trim($m[1]);
|
||
if (preg_match('/DELETE\s+FROM\s+\w+\s*$/im', $sql)) return "DELETE sans WHERE — dangereux";
|
||
if (preg_match('/UPDATE\s+\w+\s+SET.*$/im', $sql) && !preg_match('/WHERE/i', $sql)) return "UPDATE sans WHERE — dangereux";
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function scFullAutoCorrect($response) {
|
||
$corrected = scAutoFix($response);
|
||
$mathErr = scDetectMathError($corrected);
|
||
if ($mathErr) error_log("WEVIA_SC: " . $mathErr);
|
||
$sqlErr = scValidateSQL($corrected);
|
||
if ($sqlErr) $corrected .= "\n\n⚠️ {$sqlErr}";
|
||
$jsonErr = scValidateJSON($corrected);
|
||
if ($jsonErr) $corrected .= "\n\n⚠️ {$jsonErr}";
|
||
return $corrected;
|
||
}
|
||
|
||
function scDetectLanguageMix($response) {
|
||
$fr = preg_match_all('/\b(le|la|les|de|du|des|un|une|et|est|que|qui|dans|pour|avec|sur|pas|plus|mais)\b/i', $response);
|
||
$en = preg_match_all('/\b(the|is|are|was|of|to|in|for|with|on|not|but|this|that|from|have|has)\b/i', $response);
|
||
if ($fr > 10 && $en > 10) return true;
|
||
return false;
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// MODULE U: OPUS 4.6 MASTER PIPELINE
|
||
// Orchestrates all advanced modules
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
function opus46PreProcess($sys, $msg, $intent, $history = [], $kbContext = '') {
|
||
// Chain-of-Thought injection
|
||
$sys = cotInjectPrompt($sys, $msg, $intent);
|
||
|
||
// Strategy-specific reasoning
|
||
$strategy = cotGetStrategyPrompt($msg);
|
||
if (mb_strlen($sys) < 7000) $sys .= $strategy;
|
||
|
||
// Metacognition self-check
|
||
if (mb_strlen($sys) < 7200) $sys .= metaBuildSelfCheckPrompt();
|
||
|
||
// Planning for complex tasks
|
||
$sys = planInjectPrompt($sys, $msg);
|
||
|
||
// Cross-domain bridges
|
||
$sys = xdomInjectCrossDomain($sys, $msg);
|
||
|
||
// Temporal context
|
||
$sys = tempInjectTemporalContext($sys, $msg);
|
||
|
||
// Adaptive tone and strategy
|
||
$sys = adaptInjectStrategy($sys, $msg, $intent, $history);
|
||
|
||
return $sys;
|
||
}
|
||
|
||
function opus46PostProcess($response, $msg, $intent, $history = [], $kbContext = '') {
|
||
// Self-correction
|
||
$response = scFullAutoCorrect($response);
|
||
|
||
// Adversarial verification
|
||
$confidence = metaAssessConfidence($response, $msg, !empty($kbContext));
|
||
$advIssues = advFullVerification($response, $msg, $intent, $kbContext, $confidence);
|
||
if (!empty($advIssues['security'] ?? [])) $response = advInjectSecurityWarnings($response, $advIssues['security']);
|
||
if (!empty($advIssues['fallacies'] ?? [])) $response = advFlagFallacies($response, $advIssues['fallacies']);
|
||
$response = advNeutralizeBias($response);
|
||
|
||
// Metacognition corrections
|
||
if (metaDetectOverconfidence($response)) $response = metaSoftenOverconfidence($response);
|
||
$gap = metaDetectKnowledgeGap($msg, null);
|
||
if ($gap && metaShouldHedge($confidence, $intent)) {
|
||
$gapMsg = metaAcknowledgeGap($gap);
|
||
if ($gapMsg) $response .= "\n\n💡 " . $gapMsg;
|
||
}
|
||
|
||
// Repetition guard
|
||
$response = metaInjectVariation($response, $history);
|
||
|
||
// Quality log
|
||
$quality = metaEstimateResponseQuality($response, $intent, $msg);
|
||
if ($quality < 6) error_log("WEVIA_OPUS46: low_quality={$quality} intent={$intent}");
|
||
|
||
return $response;
|
||
}
|
||
|
||
function opus46GetStats() {
|
||
return [
|
||
'modules' => ['chain_of_thought', 'metacognition', 'adversarial', 'planning', 'cross_domain', 'temporal', 'gpu_sovereign', 'adaptive', 'self_correction'],
|
||
'version' => '4.6',
|
||
'functions' => 200,
|
||
'capabilities' => ['reasoning', 'self_awareness', 'verification', 'planning', 'transfer_learning', 'time_awareness', 'gpu_pipeline', 'adaptation', 'self_correction']
|
||
];
|
||
}
|
||
|
||
if (!defined('OPUS46_LOADED')) define('OPUS46_LOADED', true);
|