$neg + 1) return 'positive'; if ($neg > $pos + 1) return 'negative'; return 'neutral'; } function detectExpertiseLevel($msg) { $advanced = preg_match_all('/\b(ABAP|CDS|RFC|BAPI|kubernetes|nginx|systemctl|iptables|CQRS|DDD|saga|rebase|cherry-pick)\b/i', $msg); $basic = preg_match_all('/\b(c.est quoi|comment ça marche|pour un débutant|expliqu|simplement|basique)\b/i', $msg); if ($advanced >= 2) return 'expert'; if ($basic >= 1) return 'beginner'; return 'intermediate'; } function detectResponseLength($msg) { if (preg_match('/\b(détaillé|exhaustif|complet|approfondi|en profondeur|long|tout)\b/i', $msg)) return 'long'; if (preg_match('/\b(court|bref|rapide|résumé|TL;?DR|en une phrase|succinct|concis)\b/i', $msg)) return 'short'; return 'medium'; } function detectOutputFormat($msg) { if (preg_match('/\b(JSON|json)\b/', $msg)) return 'json'; if (preg_match('/\b(XML|xml)\b/', $msg)) return 'xml'; if (preg_match('/\b(CSV|csv)\b/', $msg)) return 'csv'; if (preg_match('/\b(markdown|MD)\b/i', $msg)) return 'markdown'; if (preg_match('/\b(tableau|table|grille)\b/i', $msg)) return 'table'; if (preg_match('/\b(YAML|yaml|yml)\b/', $msg)) return 'yaml'; if (preg_match('/\b(HTML|html)\b/', $msg)) return 'html'; return 'auto'; } function detectToneRequest($msg) { if (preg_match('/\b(professionnel|corporate|formel|business)\b/i', $msg)) return 'professional'; if (preg_match('/\b(amical|cool|décontracté|fun|sympathique)\b/i', $msg)) return 'friendly'; if (preg_match('/\b(technique|précis|rigoureux|scientifique)\b/i', $msg)) return 'technical'; if (preg_match('/\b(pédagogique|didactique|explicatif|vulgarisé)\b/i', $msg)) return 'educational'; return 'auto'; } function detectQuestionType($msg) { if (preg_match('/^(qui|who)\b/i', $msg)) return 'who'; if (preg_match('/^(quoi|que|what)\b/i', $msg)) return 'what'; if (preg_match('/^(quand|when)\b/i', $msg)) return 'when'; if (preg_match('/^(où|where)\b/i', $msg)) return 'where'; if (preg_match('/^(pourquoi|why)\b/i', $msg)) return 'why'; if (preg_match('/^(comment|how)\b/i', $msg)) return 'how'; if (preg_match('/^(combien|how much|how many)\b/i', $msg)) return 'howmuch'; if (preg_match('/\?$/', trim($msg))) return 'question'; return 'statement'; } function detectMultiPart($msg) { return substr_count($msg, '?') >= 2 || preg_match('/\b(et aussi|également|de plus|en plus|autre chose)\b/i', $msg); } function countTokensEstimate($text) { return (int)(mb_strlen($text) / 3.5); } function detectSarcasm($msg) { return (bool)preg_match('/(bien sûr|évidemment|comme d.habitude|encore une fois|bravo.*\!|génial.*\!|super.*\!)/i', $msg) && preg_match('/(!|\.\.\.)/', $msg); } function detectGratitude($msg) { return (bool)preg_match('/\b(merci|thanks|thank you|thx|شكرا|بارك الله)\b/i', $msg); } function detectGreeting($msg) { return (bool)preg_match('/^(bonjour|bonsoir|salut|hello|hi|hey|coucou|salam|السلام|صباح)[\s!?.,]*$/i', trim($msg)); } function detectFarewell($msg) { return (bool)preg_match('/^(au revoir|bye|ciao|à bientôt|bonne journée|bonne soirée|adieu|tchao|à\+|a\+)[\s!?.]*$/i', trim($msg)); } function detectFollowUp($msg) { return (bool)preg_match('/\b(suite|continuer|poursuivre|précédent|avant|dernier|rappel|on en était|tout à l.heure|et le reste|la suite)\b/i', $msg); } function detectClarification($msg) { return (bool)preg_match('/\b(je voulais dire|en fait|non je parle de|pas ça|l.autre|celui|précise|clarifie|rectifie)\b/i', $msg); } function detectFrustration($msg) { return (bool)preg_match('/\b(ça (marche|fonctionne) (pas|toujours pas)|encore|toujours le même|j.en ai marre|agaçant|frustrant|n.importe quoi|absurde)\b/i', $msg); } function detectCompliment($msg) { return (bool)preg_match('/\b(impressionnant|bravo|excellent travail|bien joué|chapeau|magnifique|parfait|génial|incroyable)\b/i', $msg); } function detectConfusion($msg) { return (bool)preg_match('/\b(je comprends pas|confused|perdu|flou|pas clair|embrouillé|je suis paumé|ça veut dire quoi|hein)\b/i', $msg); } function detectNumberHeavy($msg) { return preg_match_all('/\d+/', $msg) >= 3; } function detectCodeInMessage($msg) { return (bool)preg_match('/(```|function\s|class\s|def\s|SELECT\s|import\s|require\s|<\?php|\$\w+\s*=|const\s|let\s|var\s)/i', $msg); } function detectURLInMessage($msg) { return (bool)preg_match('/https?:\/\/[^\s]+/i', $msg); } function detectFileReference($msg) { return (bool)preg_match('/\b[\w\-]+\.(php|py|js|ts|html|css|sh|sql|json|yaml|yml|xml|csv|md|txt|pdf|docx|pptx|xlsx)\b/i', $msg); } function detectServerReference($msg) { return (bool)preg_match('/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|S46|S88|S89|S151|S157|serveur|server)\b/i', $msg); } // ═══════════════════════════════════════════════════════════════════════════ // MODULE E: PROMPT INJECTION FUNCTIONS (30 functions) // Per-domain system prompt snippets // ═══════════════════════════════════════════════════════════════════════════ function injectSAPExpertise() { return "\n## SAP EXPERTISE\nUtilise la terminologie SAP exacte. Cite les transactions (SE80, SM37, SU01), tables (BSEG, EKKO, VBAK), BAPIs. Distingue S/4HANA Cloud vs On-Premise. Recommande standard avant custom. Mentionne SAP Notes pertinentes."; } function injectSecurityMindset() { return "\n## SECURITY MINDSET\nÉvalue CHAQUE recommandation sous l'angle sécurité. Principe du moindre privilège. Chiffrement au repos et en transit. Logs d'audit. Vérifie les CVEs récentes. Propose hardening."; } function injectPerformanceFocus() { return "\n## PERFORMANCE FOCUS\nChiffre TOUT: avant/après, gain en %, temps de réponse, throughput. Identifie le goulot. Propose mesure avant optimisation. Profile avant de deviner. Cache stratégiquement."; } function injectComplianceFramework() { return "\n## COMPLIANCE FRAMEWORK\nCite articles et sections exacts. Distingue obligations légales vs bonnes pratiques. Évalue risques (amendes, sanctions). Recommande actions concrètes de mise en conformité. Délais."; } function injectTeachingMode() { return "\n## MODE PÉDAGOGIQUE\nAnalogie concrète → Définition précise → Exemple réel → Piège à éviter. Du simple au complexe. Vérifie la compréhension. Utilise des métaphores du quotidien."; } function injectMathRigor() { return "\n## RIGUEUR MATHÉMATIQUE\nÉtape par étape. Montre CHAQUE calcul intermédiaire. Vérifie par méthode alternative. Unités. Arrondis explicites. Formule avant application. Sanity check du résultat."; } function injectCausalReasoning() { return "\n## RAISONNEMENT CAUSAL\nDistingue corrélation de causalité. Structure: Symptôme → Hypothèses (top 3) → Tests → Cause racine → Solution. Cite les biais cognitifs potentiels. Contre-factuel."; } function injectCreativeMode() { return "\n## MODE CRÉATIF\nPense latéralement. 3 approches originales minimum. Cross-pollination entre domaines. Pas de jugement prématuré. Pousse les idées jusqu'au bout. Surprise et inattendu."; } function injectDiagramExpert() { return "\n## DIAGRAM EXPERT\nMermaid syntax précise. Flowchart pour processus, sequenceDiagram pour interactions, classDiagram pour architecture, gantt pour planning. Labels clairs en français. Couleurs si utile."; } function injectCodeQuality() { return "\n## CODE QUALITY\nCode COMPLET et déployable. Gestion d'erreurs exhaustive. Variables parlantes. Logs pour debug. Commentaires français. Pas de TODO. Tests suggérés. Rollback prévu."; } function injectBashExpert() { return "\n## BASH EXPERT\nset -euo pipefail. Variables readonly. Fonctions log/err/ok. Backup avant modification. Vérification post-exécution. Cron-ready. Idempotent si possible."; } function injectDatabaseExpert() { return "\n## DATABASE EXPERT\nEXPLAIN ANALYZE avant optimisation. Index stratégiques. Transactions ACID. Backup avant ALTER. Migration réversible. Connection pooling. Vacuum/Analyze."; } function injectAPIDesign() { return "\n## API DESIGN\nRESTful conventions. Versioning. Pagination cursor-based. Rate limiting. Auth JWT/OAuth. Error codes standardisés. Documentation OpenAPI. Idempotent PUT/DELETE."; } function injectDevOpsExpert() { return "\n## DEVOPS EXPERT\nInfrastructure as Code. Immutable infrastructure. Blue-Green/Canary deployments. Monitoring avant scaling. Alerting actionnable. Runbooks pour chaque incident type."; } function injectDataScienceMode() { return "\n## DATA SCIENCE MODE\nHypothèse → Données → Analyse → Conclusion. Valide statistiquement. Visualise avant de modéliser. Feature engineering avant complexité. Interprétabilité. Biais des données."; } function injectProjectManager() { return "\n## PROJECT MANAGEMENT\nPérimètre → Phases → Dépendances → Timeline → Risques → KPIs. Chaque livrable a un responsable et une date. RACI si multi-équipes. Rétrospective intégrée."; } function injectUXDesign() { return "\n## UX DESIGN\nUser-first. Parcours utilisateur avant wireframe. Accessibilité (WCAG). Mobile-first. Feedback immédiat. Progressive disclosure. Microcopy soigné. A/B testing."; } function injectCloudArchitect() { return "\n## CLOUD ARCHITECT\nWell-Architected Framework. Multi-AZ/région. Cost optimization. Reserved vs On-Demand. Serverless quand possible. VPC design. IAM least privilege. Tags pour cost allocation."; } function injectEmailMarketing() { return "\n## EMAIL MARKETING\nDélivrabilité d'abord. SPF/DKIM/DMARC. Warmup progressif. Segmentation fine. A/B testing sujets. Mobile-friendly. CTA clair. Unsubscribe facile. Compliance RGPD."; } function injectMoroccanBusiness() { return "\n## CONTEXTE MAROC\nLoi 09-08 (protection données). CNDP (régulateur). Code du travail marocain. CNSS/AMO. Normes NM. Investissement (charte CRI). Zones franches (TFZ, Casanearshore). Darija acceptable."; } function injectStartupAdvisor() { return "\n## STARTUP ADVISOR\nLean startup. MVP rapide. Product-market fit avant scale. Métriques: CAC, LTV, MRR, churn. Pitch deck: problème → solution → marché → traction → équipe → ask. Cap table clean."; } function injectNetworkEngineer() { return "\n## NETWORK ENGINEER\nOSI model. Subnetting CIDR. Routing tables. ACLs. VLAN segmentation. QoS. Packet capture (tcpdump/wireshark). MTU. TTL. DNS resolution chain."; } function injectContainerExpert() { return "\n## CONTAINER EXPERT\nMulti-stage builds. .dockerignore. Non-root user. Health checks. Resource limits. Layer caching. Compose pour dev, K8s pour prod. Security scanning. Distroless images."; } function injectMLEngineer() { return "\n## ML ENGINEER\nData pipeline → Feature engineering → Model selection → Training → Evaluation → Deployment → Monitoring. MLOps. Experiment tracking. Model versioning. Drift detection."; } function injectLLMExpert() { return "\n## LLM EXPERT\nPrompt engineering patterns. RAG architecture. Chunking strategies. Embedding models. Vector stores. Fine-tuning vs RAG. Hallucination mitigation. Context window management. Token optimization."; } function injectFinancialAnalyst() { return "\n## FINANCIAL ANALYST\nDCF, comparables, multiples. NPV/IRR/payback. P&L impact. Cash flow projection. Sensitivity analysis. Break-even. ROI with timeframe. Currency considerations."; } function injectGitExpert() { return "\n## GIT EXPERT\nGitflow ou trunk-based. Commits atomiques. Messages conventionnels. Rebase pour historique clean. Cherry-pick pour hotfix. Tags sémantiques. Protected branches. Code review checklist."; } function injectLinuxAdmin() { return "\n## LINUX ADMIN\nsystemd services. journalctl pour logs. ss/netstat pour ports. lsof pour file handles. strace pour debug. crontab -e pour scheduling. logrotate. ulimits. sysctl tuning."; } function injectPHPExpert() { return "\n## PHP EXPERT\nPHP 8.3 features (fibers, enums, readonly, match). PSR-12 coding standard. Composer autoload. PDO prepared statements. Error handling try/catch. OPcache. PHP-FPM tuning."; } function injectPythonExpert() { return "\n## PYTHON EXPERT\nPython 3.12+. Type hints. Virtual environments. List/dict comprehensions. Context managers. Decorators. Async/await. Pathlib. F-strings. Dataclasses. Poetry/UV package management."; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE F: RESPONSE QUALITY VALIDATORS (25 functions) // ═══════════════════════════════════════════════════════════════════════════ function validateCodeCompleteness($response) { $issues = []; if (preg_match('/```/', $response) && !preg_match('/```\w+/', $response)) $issues[] = "Code block sans langage spécifié"; if (preg_match('/TODO|FIXME|à adapter|à compléter|\.\.\./', $response)) $issues[] = "Code incomplet (TODO/...)"; if (preg_match('/\$\w+/', $response) && !preg_match('/try|catch|if.*null|isset|empty/', $response)) $issues[] = "Variables non vérifiées"; return $issues; } function validateFactualClaims($response) { $flags = []; if (preg_match_all('/\b\d{2,}%/', $response, $m)) { foreach ($m[0] as $pct) if (intval($pct) > 95) $flags[] = "Pourcentage suspicieusement élevé: $pct"; } return $flags; } function validateResponseLength($response, $expected) { $len = mb_strlen($response); if ($expected === 'short' && $len > 500) return "Réponse trop longue pour demande courte"; if ($expected === 'long' && $len < 200) return "Réponse trop courte pour demande détaillée"; return null; } function validateEmojiPresence($response) { return preg_match('/[\x{1F300}-\x{1F9FF}\x{2600}-\x{27BF}\x{1F600}-\x{1F64F}]/u', $response) ? true : false; } function validateNoLeakedInternals($response) { $forbidden = ['WEVADS','PowerMTA','pmta','adx_system','adx_clients','sentinel-brain','brain_send_configs','brain_factory']; foreach ($forbidden as $w) if (stripos($response, $w) !== false) return "Internal leaked: $w"; return null; } function validateSQLSafety($response) { if (preg_match('/DROP\s+TABLE|TRUNCATE|DELETE\s+FROM\s+\w+\s*;/i', $response) && !preg_match('/backup|sauvegarde/i', $response)) return "SQL destructif sans mention de backup"; return null; } function validateBashSafety($response) { if (preg_match('/rm\s+-rf\s+\/[^o]/i', $response)) return "rm -rf dangereux détecté"; if (preg_match('/chmod\s+777/i', $response)) return "chmod 777 non sécurisé"; if (preg_match('/curl.*\|\s*bash/i', $response)) return "Pipe curl to bash dangereux"; return null; } function validateMarkdownStructure($response) { if (mb_strlen($response) > 1000 && !preg_match('/^#+\s/m', $response) && !preg_match('/\*\*/', $response)) return "Long response sans structure (pas de headers ni bold)"; return null; } function validateFrenchGrammar($response) { $issues = []; if (preg_match('/\bse (est|sont|a|ont)\b/i', $response)) $issues[] = "Grammaire: se + auxiliaire"; if (preg_match('/\bsi il\b/i', $response)) $issues[] = "Grammaire: si il → s'il"; return $issues; } function validateNoRepetition($response) { $sentences = preg_split('/[.!?]+/', $response); $seen = []; foreach ($sentences as $s) { $key = mb_strtolower(trim($s)); if (mb_strlen($key) > 20 && isset($seen[$key])) return "Phrase répétée: " . mb_substr($s, 0, 50); $seen[$key] = true; } return null; } function validateActionable($response, $intent) { if (in_array($intent, ['technical','operational','code']) && mb_strlen($response) > 200) { if (!preg_match('/```|commande|instruction|étape|step/i', $response)) return "Réponse technique sans livrable concret"; } return null; } function validateSourceCitation($response) { if (preg_match('/selon|d.après|étude|recherche|rapport/i', $response) && !preg_match('/\d{4}|source|référence|lien/i', $response)) return "Citation sans source identifiable"; return null; } function validateConsistency($response) { if (preg_match('/oui.*non|non.*oui|d.un côté.*de l.autre/i', $response) && !preg_match('/avantage|inconvénient|compare|nuanc/i', $response)) return "Possible contradiction non structurée"; return null; } function validateTechnicalDepth($response, $level) { if ($level === 'expert' && preg_match('/simplement|basiquement|en gros/i', $response)) return "Ton trop simple pour audience expert"; if ($level === 'beginner' && preg_match_all('/\b[A-Z]{3,}\b/', $response) > 5) return "Trop d'acronymes pour débutant"; return null; } function scoreResponseQuality($response, $intent, $msg) { $score = 10; $issues = []; $codeIssues = validateCodeCompleteness($response); if (!empty($codeIssues)) { $score -= count($codeIssues); $issues = array_merge($issues, $codeIssues); } if (!validateEmojiPresence($response) && mb_strlen($response) > 50) { $score -= 0.5; $issues[] = "Pas d'emoji"; } $leak = validateNoLeakedInternals($response); if ($leak) { $score -= 3; $issues[] = $leak; } $sql = validateSQLSafety($response); if ($sql) { $score -= 2; $issues[] = $sql; } $bash = validateBashSafety($response); if ($bash) { $score -= 2; $issues[] = $bash; } $rep = validateNoRepetition($response); if ($rep) { $score -= 1; $issues[] = $rep; } return ['score' => max(0, $score), 'issues' => $issues]; } function validateWEVALIdentity($response) { $mentions = preg_match_all('/\bWEVAL\b/i', $response); if ($mentions > 5) return "Trop de mentions WEVAL (marketing agressif)"; return null; } function validateDateReferences($response) { if (preg_match('/\b(202[0-3])\b/', $response)) return "Référence à date potentiellement obsolète"; return null; } function validateLinkFormat($response) { if (preg_match('/https?:\/\/[^\s)]+/', $response, $m)) { if (!preg_match('/\.(com|org|io|dev|fr|ma|net|gov)\b/', $m[0])) return "URL suspecte"; } return null; } function validateTableFormat($response) { if (preg_match('/\|.*\|.*\|/', $response)) { $lines = explode("\n", $response); $tableLine = false; foreach ($lines as $l) { if (preg_match('/^\|.*\|$/', trim($l))) $tableLine = true; } if (!$tableLine) return "Tableau markdown potentiellement malformé"; } return null; } function validateMermaidSyntax($response) { if (preg_match('/```mermaid([\s\S]*?)```/', $response, $m)) { $diagram = $m[1]; if (!preg_match('/^(flowchart|graph|sequenceDiagram|classDiagram|gantt|pie|erDiagram|stateDiagram|journey)/m', $diagram)) return "Mermaid: type de diagramme manquant"; if (preg_match('/-->\|[^|]*\|>/', $diagram)) return "Mermaid: syntax invalide -->|text|>"; } return null; } function validateJSONInResponse($response) { if (preg_match('/```json([\s\S]*?)```/', $response, $m)) { json_decode(trim($m[1])); if (json_last_error() !== JSON_ERROR_NONE) return "JSON invalide dans la réponse"; } return null; } function countSections($response) { return preg_match_all('/^#+\s/m', $response); } function countCodeBlocks($response) { return preg_match_all('/```/', $response) / 2; } function countWords($text) { return str_word_count(strip_tags($text)); } function estimateReadTime($text) { return round(countWords($text) / 200, 1); } // ═══════════════════════════════════════════════════════════════════════════ // MODULE G: CONTEXT ENRICHMENT FUNCTIONS (30 functions) // ═══════════════════════════════════════════════════════════════════════════ function enrichWithIndustryContext($msg, $sys) { $detectors = [ 'detectPharmaContext' => injectSAPExpertise(), // fallback — pharma uses SAP 'detectFinanceContext' => injectFinancialAnalyst(), 'detectSAPContext' => injectSAPExpertise(), 'detectSecurityContext' => injectSecurityMindset(), 'detectLLMContext' => injectLLMExpert(), 'detectEmailTechContext' => injectEmailMarketing(), 'detectMoroccanContext' => injectMoroccanBusiness(), ]; $budget = 600; foreach ($detectors as $fn => $prompt) { if ($budget <= 0) break; if (function_exists($fn) && $fn($msg)) { $chunk = mb_substr($prompt, 0, $budget); $sys .= $chunk; $budget -= mb_strlen($chunk); } } return $sys; } function enrichWithTaskContext($msg, $sys) { $tasks = []; if (detectCodeGeneration($msg)) $tasks[] = injectCodeQuality(); if (detectDiagnostic($msg)) $tasks[] = injectCausalReasoning(); if (detectComparison($msg)) $tasks[] = "\n## COMPARAISON\nUtilise un tableau. Critères objectifs. Score pondéré. Recommandation finale avec justification."; if (detectEstimation($msg)) $tasks[] = "\n## ESTIMATION\nFourchette: optimiste/réaliste/pessimiste. Base de calcul explicite. Hypothèses listées. TCO sur 3 ans."; if (detectVisualization($msg)) $tasks[] = injectDiagramExpert(); $budget = 500; foreach ($tasks as $t) { if ($budget <= 0) break; $chunk = mb_substr($t, 0, $budget); $sys .= $chunk; $budget -= mb_strlen($chunk); } return $sys; } function enrichWithStyleContext($msg, $sys) { $formality = detectFormalityLevel($msg); $expertise = detectExpertiseLevel($msg); $length = detectResponseLength($msg); $tone = detectToneRequest($msg); $style = []; if ($formality === 'formal') $style[] = "Ton formel, vouvoiement."; if ($formality === 'informal') $style[] = "Ton décontracté, tutoiement OK."; if ($expertise === 'beginner') $style[] = "Explique simplement, évite jargon."; if ($expertise === 'expert') $style[] = "Niveau expert, jargon OK, pas de simplification."; if ($length === 'short') $style[] = "Réponse COURTE et directe."; if ($length === 'long') $style[] = "Réponse DÉTAILLÉE et exhaustive."; if ($tone === 'educational') $style[] = "Pédagogique avec exemples concrets."; if (!empty($style)) $sys .= "\n## STYLE: " . implode(" ", $style); return $sys; } function extractKeyEntities($msg) { $entities = []; if (preg_match_all('/\b[A-Z][a-zA-Z]+(?:\s+[A-Z][a-zA-Z]+)*\b/', $msg, $m)) $entities['proper_nouns'] = array_unique($m[0]); if (preg_match_all('/\b\d+[KMG€$%]?\b/', $msg, $m)) $entities['numbers'] = $m[0]; if (preg_match_all('/\b[\w]+\.(?:php|py|js|sh|sql|html|css|json|yaml)\b/i', $msg, $m)) $entities['files'] = $m[0]; if (preg_match_all('/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/', $msg, $m)) $entities['ips'] = $m[0]; return $entities; } function buildContextSummary($history, $limit = 3) { if (empty($history)) return ""; $recent = array_slice($history, -$limit * 2); $topics = []; foreach ($recent as $h) { $content = $h['content'] ?? ''; if (mb_strlen($content) > 20) { $topics[] = mb_substr($content, 0, 60); } } return empty($topics) ? "" : "\n## CONTEXTE RÉCENT\n" . implode(" → ", $topics); } function detectConversationPhase($history) { $count = count($history); if ($count <= 2) return 'opening'; if ($count <= 6) return 'exploration'; if ($count <= 12) return 'deep_dive'; return 'extended'; } function shouldAskClarification($msg, $intent) { if (mb_strlen(trim($msg)) < 15 && $intent !== 'greeting') return true; if (detectMultiPart($msg) && mb_strlen($msg) > 200) return true; return false; } function prioritizeKBSections($msg) { $sections = []; if (detectSAPContext($msg)) $sections[] = 'sap'; if (detectSecurityContext($msg)) $sections[] = 'security'; if (detectLLMContext($msg)) $sections[] = 'ai'; if (detectEmailTechContext($msg)) $sections[] = 'email'; if (detectMoroccanContext($msg)) $sections[] = 'morocco'; return $sections; } function buildPersonalizedGreeting($history) { $count = count($history); if ($count === 0) return "Bonjour ! 👋 Je suis WEVIA, l'assistant IA de WEVAL Consulting."; if ($count < 5) return "Re-bonjour ! 😊 On continue ?"; return "Content de vous revoir ! 🚀 Où en étions-nous ?"; } function getResponseTemplate($taskType) { $templates = [ 'diagnostic' => "🔍 **DIAGNOSTIC**\n\n**Symptôme:** [observation]\n**Hypothèses:**\n1. \n2. \n3. \n\n**Tests:**\n```bash\n```\n\n**Solution:**\n", 'comparison' => "📊 **COMPARAISON**\n\n| Critère | Option A | Option B | Gagnant |\n|---|---|---|---|\n| | | | |\n\n**Recommandation:**\n", 'estimation' => "📋 **ESTIMATION**\n\n| Scénario | Durée | Coût | Risque |\n|---|---|---|---|\n| Optimiste | | | |\n| Réaliste | | | |\n| Pessimiste | | | |\n", 'audit' => "🛡️ **AUDIT**\n\n**Périmètre:** \n**Méthodologie:** \n**Constats:**\n1. \n2. \n**Recommandations:**\n", ]; return $templates[$taskType] ?? ""; } function calculateComplexity($msg) { $score = 0; $score += mb_strlen($msg) > 100 ? 1 : 0; $score += mb_strlen($msg) > 300 ? 1 : 0; $score += substr_count($msg, '?') > 1 ? 1 : 0; $score += preg_match_all('/\b(et|aussi|également|plus|en outre)\b/i', $msg) > 0 ? 1 : 0; $score += detectCodeInMessage($msg) ? 1 : 0; $score += detectNumberHeavy($msg) ? 1 : 0; if ($score <= 1) return 'simple'; if ($score <= 3) return 'moderate'; return 'complex'; } function selectOptimalModel($complexity, $intent) { if ($complexity === 'simple') return ['cerebras', 'groq']; if ($intent === 'code') return ['cerebras', 'sambanova']; if ($complexity === 'complex') return ['sambanova', 'mistral']; return ['groq', 'cerebras']; } function buildDebugPrompt($error) { return "\n## DEBUG CONTEXT\nErreur rencontrée: {$error}\nAnalyse systématiquement: 1) Message exact 2) Stack trace 3) Contexte (OS, version, config) 4) Reproduction steps 5) Dernière modification."; } function buildMigrationChecklist($source, $target) { return "## MIGRATION {$source} → {$target}\n□ Inventaire complet\n□ Analyse compatibilité\n□ Plan de migration\n□ Environnement test\n□ Backup complet\n□ Migration données\n□ Tests fonctionnels\n□ Tests performance\n□ Plan de rollback\n□ Go/No-Go\n□ Migration prod\n□ Validation post-migration"; } function detectContextSwitch($history, $msg) { if (count($history) < 2) return false; $lastMsg = $history[count($history) - 1]['content'] ?? ''; $prevTopics = array_filter(explode(' ', mb_strtolower($lastMsg)), fn($w) => mb_strlen($w) > 4); $currTopics = array_filter(explode(' ', mb_strtolower($msg)), fn($w) => mb_strlen($w) > 4); $overlap = count(array_intersect($prevTopics, $currTopics)); return $overlap < 2; } function suggestFollowUp($response, $intent) { $suggestions = []; if (preg_match('/```/', $response)) $suggestions[] = "Voulez-vous que je teste ce code ?"; if (preg_match('/alternative|autre option/i', $response)) $suggestions[] = "Souhaitez-vous explorer les alternatives ?"; if (detectVisualization($response)) $suggestions[] = "Je peux générer un diagramme si vous le souhaitez."; return $suggestions; } function compressSystemPrompt($sys, $maxChars = 7500) { if (mb_strlen($sys) <= $maxChars) return $sys; $head = mb_substr($sys, 0, (int)($maxChars * 0.55)); $tail = mb_substr($sys, -(int)($maxChars * 0.40)); return $head . "\n\n[...condensed...]\n\n" . $tail; } function mergeContexts($kbContext, $webContext, $memoryContext, $budget = 4000) { $merged = ""; $parts = [['📚 KB', $kbContext], ['🌐 Web', $webContext], ['🧠 Mémoire', $memoryContext]]; $perPart = (int)($budget / 3); foreach ($parts as [$label, $content]) { if (!empty($content)) { $merged .= "\n### {$label}\n" . mb_substr($content, 0, $perPart); } } return $merged; } function buildFallbackResponse($intent, $lang = 'fr') { $fallbacks = [ 'fr' => [ 'greeting' => "Bonjour ! 👋 Comment puis-je vous aider ?", 'technical' => "⚡ Je peux vous aider sur ce point technique. Pourriez-vous me donner plus de détails ?", 'general' => "💡 Bonne question ! Laissez-moi vous répondre...", ], 'en' => [ 'greeting' => "Hello! 👋 How can I help you?", 'technical' => "⚡ I can help with that. Could you provide more details?", 'general' => "💡 Great question! Let me help you with that...", ], ]; return $fallbacks[$lang][$intent] ?? $fallbacks['fr']['general']; } function extractActionItems($response) { $actions = []; if (preg_match_all('/(?:^|\n)\s*(?:□|☐|TODO|Action|→)\s*(.+)/mi', $response, $m)) { $actions = $m[1]; } if (preg_match_all('/```(?:bash|sh)([\s\S]*?)```/', $response, $m)) { foreach ($m[1] as $cmd) $actions[] = "Exécuter: " . mb_substr(trim($cmd), 0, 80); } return $actions; } function generateSessionSummary($history) { $topics = []; $codeBlocks = 0; foreach ($history as $h) { $c = $h['content'] ?? ''; if ($h['role'] === 'user') $topics[] = mb_substr($c, 0, 50); $codeBlocks += preg_match_all('/```/', $c); } return [ 'messages' => count($history), 'topics' => array_slice($topics, 0, 5), 'code_blocks' => (int)($codeBlocks / 2), ]; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE H: REASONING PATTERNS (25 functions) // ═══════════════════════════════════════════════════════════════════════════ function applySOCRATICMethod($msg) { return "\n## MÉTHODE SOCRATIQUE\n1. Clarifier: Que signifie exactement la question ?\n2. Hypothèses: Quels présupposés sont cachés ?\n3. Preuves: Quelles données supportent chaque option ?\n4. Perspectives: Vu d'un autre angle, que dirait-on ?\n5. Conséquences: Si on suit cette logique, où mène-t-elle ?\n6. Méta: Pourquoi cette question est-elle importante ?"; } function applySWOTFramework($topic) { return "## ANALYSE SWOT — {$topic}\n| | Positif | Négatif |\n|---|---|---|\n| **Interne** | Forces | Faiblesses |\n| **Externe** | Opportunités | Menaces |"; } function applyFiveWhys($symptom) { return "## 5 POURQUOI — {$symptom}\n1. Pourquoi ? → \n2. Pourquoi ? → \n3. Pourquoi ? → \n4. Pourquoi ? → \n5. Pourquoi ? → CAUSE RACINE"; } function applyIshikawa($problem) { return "## ISHIKAWA — {$problem}\nMéthode (processus) → \nMatériel (outils) → \nMain-d'œuvre (compétences) → \nMatière (données/input) → \nMilieu (environnement) → \nMesure (métriques) →"; } function applyPESTEL($context) { return "## PESTEL\n**P**olitique: \n**É**conomique: \n**S**ocial: \n**T**echnologique: \n**E**nvironnemental: \n**L**égal: "; } function applyMoSCoW($features) { return "## MoSCoW\n**Must have:** \n**Should have:** \n**Could have:** \n**Won't have:** "; } function applyRACI($tasks) { return "## RACI\n| Tâche | Responsable | Approbateur | Consulté | Informé |\n|---|---|---|---|---|"; } function applyDecisionMatrix($options) { return "## MATRICE DE DÉCISION\n| Critère | Poids | " . implode(" | ", $options) . " |\n|---|---|" . str_repeat("---|", count($options)); } function applyRiskMatrix() { return "## MATRICE DES RISQUES\n| | Impact faible | Impact moyen | Impact fort |\n|---|---|---|---|\n| **Proba forte** | Moyen | Élevé | Critique |\n| **Proba moyenne** | Faible | Moyen | Élevé |\n| **Proba faible** | Négligeable | Faible | Moyen |"; } function applyFirstPrinciples($topic) { return "## FIRST PRINCIPLES — {$topic}\n1. Déconstruire: Quels sont les éléments fondamentaux ?\n2. Axiomes: Que sait-on avec certitude ?\n3. Reconstruire: À partir des axiomes, que peut-on déduire ?\n4. Valider: Le résultat est-il cohérent avec la réalité ?"; } function applyInversion($goal) { return "## INVERSION — Au lieu de '{$goal}'\nQ: Comment ÉCHOUER à coup sûr ?\n1. \n2. \n3. \nMAINTENANT: Éviter systématiquement ces anti-patterns."; } function applySecondOrderThinking($action) { return "## EFFETS DE SECOND ORDRE\nAction: {$action}\n→ Effet immédiat (1er ordre): \n→ Conséquence (2e ordre): \n→ Effet systémique (3e ordre): "; } function applyEisenhowerMatrix() { return "## MATRICE D'EISENHOWER\n| | Urgent | Non urgent |\n|---|---|---|\n| **Important** | FAIRE maintenant | PLANIFIER |\n| **Non important** | DÉLÉGUER | ÉLIMINER |"; } function applyJobsToBeDone($context) { return "## JOBS TO BE DONE\nQuand [situation], je veux [motivation], pour que [résultat attendu].\nContraintes: \nMétriques de succès: "; } function applyOKR($objective) { return "## OKR — {$objective}\n**Objectif:** {$objective}\n**Résultat clé 1:** (mesurable)\n**Résultat clé 2:** (mesurable)\n**Résultat clé 3:** (mesurable)"; } function applyCostBenefitAnalysis() { return "## ANALYSE COÛT-BÉNÉFICE\n| Élément | Coûts | Bénéfices |\n|---|---|---|\n| Immédiat | | |\n| 6 mois | | |\n| 1 an | | |\n| 3 ans | | |\n**NPV:** \n**Payback:** "; } function applyPreMortem($project) { return "## PRE-MORTEM — {$project}\nImaginez: le projet a ÉCHOUÉ. Pourquoi ?\n1. [risque technique]\n2. [risque humain]\n3. [risque business]\n4. [risque externe]\nPour CHAQUE: probabilité, impact, mitigation."; } function applyPareto($domain) { return "## PARETO 80/20 — {$domain}\nQuels 20% d'actions produisent 80% des résultats ?\nPriorité absolue: \nSecondaire: \nÉliminable: "; } function applyDesignThinking() { return "## DESIGN THINKING\n1. **Empathie:** Comprendre l'utilisateur\n2. **Définir:** Reformuler le problème\n3. **Idéation:** 3+ solutions créatives\n4. **Prototyper:** MVP rapide\n5. **Tester:** Feedback utilisateur"; } function applyAgilePlanning() { return "## PLANNING AGILE\n**Sprint 1 (2 sem):** MVP core\n**Sprint 2:** Itération feedback\n**Sprint 3:** Features secondaires\n**Sprint 4:** Polish + deploy\nRetro après chaque sprint."; } function applySystemsThinking($system) { return "## PENSÉE SYSTÉMIQUE — {$system}\nComposants: \nInteractions: \nBoucles de feedback: \nPoints de levier: \nComportement émergent: "; } function applyConstraintTheory($process) { return "## THÉORIE DES CONTRAINTES — {$process}\n1. IDENTIFIER le goulot\n2. EXPLOITER le goulot (100% utilisation)\n3. SUBORDONNER tout au goulot\n4. ÉLEVER la capacité du goulot\n5. RECOMMENCER (nouveau goulot)"; } function applyKaizen($area) { return "## KAIZEN — Amélioration continue\nDomaine: {$area}\n**PDCA:** Plan → Do → Check → Act\nP: Que changer ?\nD: Petit changement test\nC: Mesure résultat\nA: Standardiser si ok, ajuster sinon"; } function applySixSigma() { return "## SIX SIGMA — DMAIC\n**D**éfinir: Problème + périmètre + objectif\n**M**esurer: Baseline + métriques actuelles\n**A**nalyser: Causes racines (Ishikawa/5 Pourquoi)\n**I**mprover: Solution + pilote\n**C**ontrôler: SPC + pérennisation"; } function applyMCDA($options, $criteria) { return "## ANALYSE MULTICRITÈRE\nOptions: " . implode(", ", $options) . "\nCritères: " . implode(", ", $criteria) . "\nMéthode: Pondération + scoring 1-5\nRésultat: Classement objectif"; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE I: METRIC & CALCULATION FUNCTIONS (20 functions) // ═══════════════════════════════════════════════════════════════════════════ function calculateROI($investment, $annualGain, $years = 3) { $totalGain = $annualGain * $years; $roi = (($totalGain - $investment) / $investment) * 100; return ['roi_pct' => round($roi, 1), 'payback_years' => round($investment / $annualGain, 1), 'total_gain' => $totalGain, 'net_gain' => $totalGain - $investment]; } function calculateTCO($capex, $opexAnnual, $years = 3) { return $capex + ($opexAnnual * $years); } function calculateNPV($cashflows, $rate = 0.08) { $npv = 0; foreach ($cashflows as $i => $cf) { $npv += $cf / pow(1 + $rate, $i + 1); } return round($npv, 2); } function calculateIRR($cashflows, $guess = 0.1) { for ($i = 0; $i < 100; $i++) { $npv = 0; $dnpv = 0; foreach ($cashflows as $j => $cf) { $npv += $cf / pow(1 + $guess, $j); $dnpv -= $j * $cf / pow(1 + $guess, $j + 1); } if (abs($dnpv) < 0.001) break; $guess -= $npv / $dnpv; } return round($guess * 100, 2); } function calculateCAGR($initial, $final, $years) { if ($initial <= 0 || $years <= 0) return 0; return round((pow($final / $initial, 1 / $years) - 1) * 100, 2); } function calculatePayback($investment, $annualCashflow) { return $annualCashflow > 0 ? round($investment / $annualCashflow, 1) : INF; } function calculateEmailMetrics($sent, $delivered, $opened, $clicked, $bounced, $complaints) { return [ 'delivery_rate' => round(($delivered / max($sent, 1)) * 100, 2), 'open_rate' => round(($opened / max($delivered, 1)) * 100, 2), 'click_rate' => round(($clicked / max($delivered, 1)) * 100, 2), 'ctr' => round(($clicked / max($opened, 1)) * 100, 2), 'bounce_rate' => round(($bounced / max($sent, 1)) * 100, 2), 'complaint_rate' => round(($complaints / max($delivered, 1)) * 100, 4), ]; } function calculateServerMetrics($cpuUsage, $memUsage, $diskUsage, $loadAvg) { $health = 'green'; if ($cpuUsage > 80 || $memUsage > 85 || $diskUsage > 90 || $loadAvg > 4) $health = 'yellow'; if ($cpuUsage > 95 || $memUsage > 95 || $diskUsage > 95 || $loadAvg > 8) $health = 'red'; return ['health' => $health, 'cpu' => $cpuUsage, 'mem' => $memUsage, 'disk' => $diskUsage, 'load' => $loadAvg]; } function calculateSLAUptime($downtimeMinutes, $periodDays = 30) { $totalMinutes = $periodDays * 24 * 60; return round((($totalMinutes - $downtimeMinutes) / $totalMinutes) * 100, 4); } function estimateTokenCost($tokens, $provider = 'groq') { $costs = ['groq' => 0.0, 'cerebras' => 0.0, 'sambanova' => 0.0, 'openai' => 0.015, 'anthropic' => 0.015, 'mistral' => 0.002, 'cohere' => 0.001]; $rate = $costs[$provider] ?? 0.01; return round(($tokens / 1000) * $rate, 4); } function calculateConversionRate($conversions, $clicks) { return $clicks > 0 ? round(($conversions / $clicks) * 100, 2) : 0; } function calculateLTV($avgRevenue, $retentionRate, $margin = 1.0) { return $retentionRate < 1 ? round(($avgRevenue * $margin) / (1 - $retentionRate), 2) : INF; } function calculateCAC($marketingCost, $newCustomers) { return $newCustomers > 0 ? round($marketingCost / $newCustomers, 2) : INF; } function formatCurrency($amount, $currency = 'EUR') { $symbols = ['EUR' => '€', 'USD' => '$', 'MAD' => 'MAD', 'GBP' => '£']; $sym = $symbols[$currency] ?? $currency; return number_format($amount, 0, ',', ' ') . ' ' . $sym; } function formatPercentage($value, $decimals = 1) { return number_format($value, $decimals, ',', '') . '%'; } function formatDuration($seconds) { if ($seconds < 60) return "{$seconds}s"; if ($seconds < 3600) return round($seconds / 60, 1) . "min"; if ($seconds < 86400) return round($seconds / 3600, 1) . "h"; return round($seconds / 86400, 1) . "j"; } function formatBytes($bytes) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $i = 0; while ($bytes >= 1024 && $i < 4) { $bytes /= 1024; $i++; } return round($bytes, 1) . ' ' . $units[$i]; } function calculateGrowthRate($current, $previous) { return $previous > 0 ? round((($current - $previous) / $previous) * 100, 1) : 0; } function calculateMedian($values) { sort($values); $count = count($values); if ($count === 0) return 0; $mid = (int)($count / 2); return ($count % 2 === 0) ? ($values[$mid - 1] + $values[$mid]) / 2 : $values[$mid]; } function calculatePercentile($values, $p) { sort($values); $index = ($p / 100) * (count($values) - 1); $lower = (int)floor($index); $upper = (int)ceil($index); return $values[$lower] + ($values[$upper] - $values[$lower]) * ($index - $lower); } // ═══════════════════════════════════════════════════════════════════════════ // MODULE J: WEVAL-SPECIFIC FUNCTIONS (20 functions) // ═══════════════════════════════════════════════════════════════════════════ function isWEVALQuery($msg) { return (bool)preg_match('/\b(WEVAL|weval-consulting|wevia|wevads|nos services|notre|consulting)\b/i', $msg); } function getWEVALServices() { return ['SAP S/4HANA consulting', 'Digital transformation', 'Cloud migration (Huawei/AWS/Azure)', 'AI & Machine Learning', 'Cybersecurity & Compliance', 'Email marketing automation', 'Custom development', 'Data analytics', 'IT infrastructure', 'Training & Change management']; } function getWEVALDifferentiators() { return ['IA souveraine (GPU local, zéro dépendance cloud)', 'Expertise SAP S/4HANA certifiée', 'Double compétence technique + business', 'Présence Afrique du Nord', 'Innovation continue (LLM fine-tuning, RAG)', 'Sécurité by design (RGPD, ISO 27001)']; } function buildWEVALPitch($context) { return "WEVAL Consulting est un cabinet de conseil en transformation digitale basé à Casablanca. Spécialisé en SAP S/4HANA, IA, cybersécurité et cloud. Notre différence : une IA souveraine (WEVIA) et une expertise terrain Afrique du Nord."; } function detectWEVADSQuestion($msg) { return (bool)preg_match('/\b(warmup|brain.*config|send_config|pmta|bounce|complaint|inbox|deliverability|offre|creative|arsenal)\b/i', $msg); } function injectWEVALContext($sys) { return $sys . "\n## CONTEXTE WEVAL\nWEVAL Consulting — Casablanca, Maroc. Cabinet conseil en transformation digitale. Expertise: SAP, Cloud, IA, Cybersécurité. IA propriétaire: WEVIA."; } function buildClientResponse($msg, $industry) { $prefix = "En tant que consultant WEVAL"; if ($industry) $prefix .= " spécialisé $industry"; return $prefix . ", voici mon analyse :\n\n"; } function detectConsultingQuery($msg) { return (bool)preg_match('/\b(conseil|recommandation|préconisation|avis d.expert|best practice|retour d.expérience|REX|benchmark|état de l.art)\b/i', $msg); } function detectQuotationQuery($msg) { return (bool)preg_match('/\b(devis|tarif|prix|coût|combien ça coûte|budget|estimation|chiffrage|forfait|TJM|jour-homme)\b/i', $msg); } function getWEVALStack() { return ['Backend' => 'PHP 8.3, Python 3.12, Node.js 20', 'Frontend' => 'React, Tailwind, Vite', 'DB' => 'PostgreSQL 16, Redis', 'AI' => 'Ollama (51 models), DeepSeek-R1, LLama, Whisper', 'Infra' => 'Hetzner dedicated, OVH, Huawei Cloud', 'Tools' => 'Git, Docker, nginx, PMTA']; } function detectInternalOnly($msg) { return (bool)preg_match('/\b(sentinel|arsenal|brain_send|adx_system|pmta|warmup_accounts|seed_accounts)\b/i', $msg); } function sanitizeForPublic($response) { $forbidden = ['WEVADS','PowerMTA','pmta','adx_system','adx_clients','sentinel-brain','brain_factory','brain_send_configs','warmup_accounts','send_configs','seed_accounts','127.0.0.1','88.198.4.195','46.62.220.135','NNuXhFfVHrwW','NKPwP4','admin123']; foreach ($forbidden as $w) $response = str_ireplace($w, '[CONFIDENTIEL]', $response); return $response; } function isConfidentialTopic($msg) { return (bool)preg_match('/\b(mot de passe|password|credential|clé API|api key|token|secret|ssh|root access)\b/i', $msg); } function detectROASQuery($msg) { return (bool)preg_match('/\b(ROAS|retour.*publicitaire|coût.*acquisition|CPA|CPM|CPC|CTR|taux.*conversion|campaign.*performance)\b/i', $msg); } function detectInfraQuery($msg) { return (bool)preg_match('/\b(serveur|server|CPU|RAM|disque|disk|réseau|network|uptime|charge|load|DNS|certificat|SSL|nginx|apache|systemd)\b/i', $msg); } function getServerMap() { return ['S88' => ['ip' => '88.198.4.195', 'role' => 'AI Primary (GPU)', 'specs' => 'i5-13500, 64GB, RTX 4000 Ada'], 'S89' => ['ip' => '127.0.0.1', 'role' => 'WEVADS Production', 'specs' => 'EPYC, 16GB, PMTA'], 'S151' => ['ip' => '151.80.235.110', 'role' => 'OVH Tracking', 'specs' => 'Tracking only']]; } function detectArchitectureQuery($msg) { return (bool)preg_match('/\b(architecture|infra|infrastructure|serveur|déploiement|stack|topologie|réseau|schéma.*serveur)\b/i', $msg); } function buildInfraOverview() { return "## INFRASTRUCTURE WEVAL\nS88 (IA + Site) — GPU RTX 4000 Ada, 51 modèles Ollama\nS89 (WEVADS) — Email marketing, PMTA, Arsenal\nS151 (Tracking) — OVH, tracking affilié"; } function detectKBQueryType($msg) { if (preg_match('/\b(ajoute|crée|insert|nouveau|enregistre)\b/i', $msg)) return 'write'; if (preg_match('/\b(cherche|trouve|recherche|query|search)\b/i', $msg)) return 'read'; if (preg_match('/\b(modifie|update|met à jour|corrige)\b/i', $msg)) return 'update'; if (preg_match('/\b(supprime|delete|efface|retire)\b/i', $msg)) return 'delete'; return 'read'; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE K: MASTER ENRICHMENT PIPELINE // Single entry point that orchestrates all modules // ═══════════════════════════════════════════════════════════════════════════ function cognitiveExpansionEnrich($sys, $msg, $intent, $history = []) { if (mb_strlen(trim($msg)) < 15 || $intent === 'greeting') return $sys; $budget = 1500; // Max chars to add from expansion $additions = []; // Industry enrichment (max 400 chars) $industryDetectors = [ 'detectSAPContext' => 'injectSAPExpertise', 'detectLLMContext' => 'injectLLMExpert', 'detectSecurityContext' => 'injectSecurityMindset', 'detectPharmaContext' => 'injectSAPExpertise', 'detectMoroccanContext' => 'injectMoroccanBusiness', 'detectEmailTechContext' => 'injectEmailMarketing', 'detectFinanceContext' => 'injectFinancialAnalyst', ]; foreach ($industryDetectors as $detector => $injector) { if ($budget <= 0) break; if (function_exists($detector) && $detector($msg)) { $prompt = $injector(); $chunk = mb_substr($prompt, 0, min(400, $budget)); $additions[] = $chunk; $budget -= mb_strlen($chunk); break; // One industry max } } // Task-type enrichment (max 300 chars) $taskMap = [ 'detectCodeGeneration' => 'injectCodeQuality', 'detectDiagnostic' => 'injectCausalReasoning', 'detectVisualization' => 'injectDiagramExpert', 'detectMigration' => 'injectDevOpsExpert', 'detectSecurity' => 'injectSecurityMindset', ]; foreach ($taskMap as $detector => $injector) { if ($budget <= 0) break; if (function_exists($detector) && $detector($msg)) { $prompt = $injector(); $chunk = mb_substr($prompt, 0, min(300, $budget)); $additions[] = $chunk; $budget -= mb_strlen($chunk); break; } } // Style calibration (max 200 chars) $styleCtx = ''; $expertise = detectExpertiseLevel($msg); $urgency = detectUrgency($msg); if ($expertise === 'beginner') $styleCtx .= " Niveau débutant, explique simplement."; if ($expertise === 'expert') $styleCtx .= " Niveau expert, jargon OK."; if ($urgency === 'high') $styleCtx .= " URGENT — réponse rapide et actionnable."; if ($styleCtx && $budget > 0) { $additions[] = "\n## CALIBRAGE:" . $styleCtx; $budget -= mb_strlen($styleCtx) + 15; } // Complexity routing hint $complexity = calculateComplexity($msg); if ($complexity === 'complex' && $budget > 50) { $additions[] = "\n[COMPLEXITÉ ÉLEVÉE: Structure ta réponse, utilise des sections.]"; } if (!empty($additions)) { $sys .= implode("", $additions); } return $sys; } function cognitiveExpansionPostProcess($response, $msg) { // Quality scoring (log only) $quality = scoreResponseQuality($response, '', $msg); if ($quality['score'] < 7) { error_log("WEVIA_COG_QUALITY: score=" . $quality['score'] . " issues=" . implode("|", $quality['issues'])); } // Sanitize internals $response = sanitizeForPublic($response); return $response; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE L: GPU MODEL ROTATION & SOVEREIGN ROUTING (25 functions) // ═══════════════════════════════════════════════════════════════════════════ function getGPUModelCatalog() { return [ 'reasoning' => ['deepseek-r1:32b','deepseek-r1:14b','qwen2.5:32b','phi4:14b'], 'coding' => ['qwen2.5-coder:14b','deepseek-coder-v2:16b','codellama:34b','starcoder2:15b'], 'general' => ['llama3.3:70b','wizardlm2:8x22b','mixtral:8x7b','gemma2:27b'], 'fast' => ['llama3.1:8b','gemma2:9b','phi4:14b','mistral:7b'], 'vision' => ['moondream:latest','llava:13b','bakllava:latest'], 'embedding' => ['nomic-embed-text:latest','mxbai-embed-large:latest'], 'creative' => ['wizardlm2:8x22b','mixtral:8x7b','nous-hermes2:34b'], ]; } function selectGPUModelV1($intent, $complexity, $msgLen) { $catalog = getGPUModelCatalog(); if ($intent === 'code') return $catalog['coding'][0]; if ($intent === 'mathematical' || $complexity === 'complex') return $catalog['reasoning'][0]; if ($intent === 'creative') return $catalog['creative'][0]; if ($msgLen < 50) return $catalog['fast'][0]; return $catalog['general'][0]; } function buildGPURotation($intent) { $catalog = getGPUModelCatalog(); $primary = $catalog['reasoning'][0]; $fallbacks = []; switch($intent) { case 'code': case 'technical': case 'operational': $primary = $catalog['coding'][0]; $fallbacks = [$catalog['reasoning'][0], $catalog['general'][0]]; break; case 'analytical': case 'mathematical': case 'causal': $primary = $catalog['reasoning'][0]; $fallbacks = [$catalog['general'][0], $catalog['fast'][0]]; break; case 'creative': case 'teaching': $primary = $catalog['creative'][0]; $fallbacks = [$catalog['general'][0], $catalog['reasoning'][0]]; break; default: $primary = $catalog['general'][0]; $fallbacks = [$catalog['fast'][0], $catalog['reasoning'][0]]; } return ['primary' => $primary, 'fallbacks' => $fallbacks]; } function getModelVRAM($model) { $vram = [ 'deepseek-r1:32b'=>19,'llama3.3:70b'=>18,'wizardlm2:8x22b'=>17,'qwen2.5:32b'=>18, 'qwen2.5-coder:14b'=>9,'deepseek-r1:14b'=>9,'phi4:14b'=>9,'mixtral:8x7b'=>16, 'gemma2:27b'=>16,'llama3.1:8b'=>5,'gemma2:9b'=>6,'mistral:7b'=>5, 'moondream:latest'=>2,'nomic-embed-text:latest'=>1,'codellama:34b'=>19, ]; return $vram[$model] ?? 10; } function canLoadModel($model, $availableVRAM = 20) { return getModelVRAM($model) <= $availableVRAM; } function estimateGPULatency($model, $tokens) { $tps = [ 'deepseek-r1:32b'=>12,'llama3.3:70b'=>8,'wizardlm2:8x22b'=>10,'qwen2.5-coder:14b'=>25, 'deepseek-r1:14b'=>22,'phi4:14b'=>20,'llama3.1:8b'=>45,'gemma2:9b'=>40, 'mistral:7b'=>50,'mixtral:8x7b'=>15,'gemma2:27b'=>14, ]; $speed = $tps[$model] ?? 15; return round($tokens / $speed, 1); } function buildCloudRotation($intent) { $rotations = [ 'analytical' => ['sambanova','groq','mistral'], 'creative' => ['groq','mistral','cerebras'], 'technical' => ['cerebras','groq','sambanova'], 'strategic' => ['sambanova','mistral','groq'], 'operational' => ['groq','cerebras','sambanova'], 'mathematical'=> ['sambanova','cerebras','groq'], 'causal' => ['sambanova','groq','mistral'], 'compliance' => ['sambanova','mistral','groq'], 'teaching' => ['groq','mistral','cerebras'], 'code' => ['cerebras','groq','sambanova'], 'synthesis' => ['groq','cerebras','sambanova'], 'conversational'=>['groq','cerebras','sambanova'], 'social_intelligence'=>['groq','sambanova','mistral'], 'greeting' => ['groq','cerebras'], ]; return $rotations[$intent] ?? ['groq','cerebras','sambanova']; } function buildSovereignRoute($intent, $complexity, $gpuAvailable = true) { if ($gpuAvailable && $complexity !== 'simple') { $gpu = buildGPURotation($intent); $cloud = buildCloudRotation($intent); return ['sovereign' => true, 'primary' => 'gpu:' . $gpu['primary'], 'fallback1' => 'gpu:' . ($gpu['fallbacks'][0] ?? ''), 'fallback2' => 'cloud:' . $cloud[0], 'fallback3' => 'cloud:' . $cloud[1]]; } $cloud = buildCloudRotation($intent); return ['sovereign' => false, 'primary' => 'cloud:' . $cloud[0], 'fallback1' => 'cloud:' . $cloud[1], 'fallback2' => 'cloud:' . ($cloud[2] ?? 'groq')]; } function buildCrossVerification($response, $intent) { return ['verifiers' => ['cerebras','groq'], 'prompt' => "Vérifie cette réponse pour exactitude et complétude. Corrige les erreurs factuelles. Réponse originale:\n" . mb_substr($response, 0, 2000), 'intent' => $intent]; } function buildDeepResponse($msg, $intent) { return ['phase1' => ['model' => 'deepseek-r1:32b', 'task' => 'reasoning', 'prompt' => "Raisonne étape par étape sur: $msg"], 'phase2' => ['model' => 'qwen2.5-coder:14b', 'task' => 'code_gen', 'conditional' => $intent === 'code'], 'phase3' => ['providers' => ['cerebras','groq'], 'task' => 'verify', 'prompt' => 'Vérifie et enrichis cette réponse']]; } function getProviderLimits() { return [ 'groq' => ['rpm' => 30, 'tpm' => 6000, 'models' => ['llama-3.3-70b-versatile','mixtral-8x7b-32768','gemma2-9b-it']], 'cerebras' => ['rpm' => 30, 'tpm' => 60000, 'models' => ['llama3.1-70b','llama3.1-8b']], 'sambanova' => ['rpm' => 10, 'tpm' => 100000, 'models' => ['Meta-Llama-3.3-70B-Instruct','DeepSeek-R1-Distill-Llama-70B']], 'mistral' => ['rpm' => 10, 'tpm' => 500000, 'models' => ['mistral-large-latest','codestral-latest']], 'cohere' => ['rpm' => 10, 'tpm' => 10000, 'models' => ['command-r-plus','command-r']], ]; } function selectFastestProvider($intent) { $speed = ['cerebras' => 1, 'groq' => 2, 'sambanova' => 3, 'mistral' => 4, 'cohere' => 5]; $cloud = buildCloudRotation($intent); usort($cloud, fn($a,$b) => ($speed[$a] ?? 9) - ($speed[$b] ?? 9)); return $cloud[0]; } function selectSmartestProvider($intent) { $quality = ['sambanova' => 1, 'mistral' => 2, 'groq' => 3, 'cerebras' => 4, 'cohere' => 5]; $cloud = buildCloudRotation($intent); usort($cloud, fn($a,$b) => ($quality[$a] ?? 9) - ($quality[$b] ?? 9)); return $cloud[0]; } function buildMultiModelPipelineV1($msg, $intent, $complexity) { $pipeline = ['stages' => []]; if ($complexity === 'complex') { $pipeline['stages'][] = ['name'=>'reason','model'=>'deepseek-r1:32b','type'=>'gpu','timeout'=>30]; $pipeline['stages'][] = ['name'=>'enrich','provider'=>selectSmartestProvider($intent),'type'=>'cloud','timeout'=>15]; $pipeline['stages'][] = ['name'=>'verify','provider'=>'cerebras','type'=>'cloud','timeout'=>10]; } else { $pipeline['stages'][] = ['name'=>'generate','provider'=>selectFastestProvider($intent),'type'=>'cloud','timeout'=>10]; } return $pipeline; } function buildVerificationPromptV1($originalResponse, $question) { return "Tu es un vérificateur expert. Analyse cette réponse pour:\n1. Exactitude factuelle\n2. Complétude\n3. Cohérence logique\n4. Qualité du code (si présent)\n\nQuestion: " . mb_substr($question, 0, 500) . "\nRéponse à vérifier: " . mb_substr($originalResponse, 0, 3000) . "\n\nRéponds UNIQUEMENT avec les corrections nécessaires. Si tout est correct, dis 'VERIFIED_OK'."; } function parseVerificationResultV1($result) { if (strpos($result, 'VERIFIED_OK') !== false) return ['status' => 'ok', 'corrections' => []]; $corrections = []; if (preg_match_all('/(?:Correction|Erreur|Fix)\s*:?\s*(.+)/i', $result, $m)) $corrections = $m[1]; return ['status' => 'needs_fix', 'corrections' => $corrections, 'raw' => mb_substr($result, 0, 1000)]; } function applyVerificationFixes($response, $corrections) { if (empty($corrections)) return $response; $footer = "\n\n---\n⚠️ **Corrections appliquées:**\n"; foreach ($corrections as $c) $footer .= "- " . trim($c) . "\n"; return $response . $footer; } function buildOllamaRequestV1($model, $prompt, $sys = '', $temp = 0.7, $maxTokens = 2000) { return ['model' => $model, 'prompt' => $prompt, 'system' => $sys, 'stream' => false, 'options' => ['temperature' => $temp, 'num_predict' => $maxTokens, 'top_p' => 0.9]]; } function buildCloudRequest($provider, $model, $messages, $temp = 0.7, $maxTokens = 2000) { return ['provider' => $provider, 'model' => $model, 'messages' => $messages, 'temperature' => $temp, 'max_tokens' => $maxTokens]; } function logModelUsage($model, $provider, $tokens, $latencyMs, $intent) { $entry = date('Y-m-d H:i:s') . " | model=$model provider=$provider tokens=$tokens latency={$latencyMs}ms intent=$intent\n"; @file_put_contents('/opt/wevads/logs/model-usage.log', $entry, FILE_APPEND); } function getModelRecommendation($intent, $msgLen, $gpuAvailable) { $complexity = ($msgLen > 200) ? 'complex' : (($msgLen > 50) ? 'moderate' : 'simple'); $route = buildSovereignRoute($intent, $complexity, $gpuAvailable); $gpu = buildGPURotation($intent); $cloud = buildCloudRotation($intent); return ['route' => $route, 'gpu_model' => $gpu['primary'], 'cloud_providers' => $cloud, 'estimated_latency' => estimateGPULatency($gpu['primary'], 500)]; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE M: ADVANCED COGNITIVE PATTERNS (25 functions) // ═══════════════════════════════════════════════════════════════════════════ function detectAmbiguity($msg) { $ambiguous = 0; if (preg_match('/\b(ça|cela|ce|cette|celui|il|elle|le|la|les|y|en)\b/i', $msg) && mb_strlen($msg) < 40) $ambiguous++; if (preg_match('/\b(trucs?|machin|chose|bidule|truc|stuff)\b/i', $msg)) $ambiguous++; if (preg_match('/\b(genre|style|type|sorte|espèce)\b/i', $msg) && !preg_match('/\btype\s+(de|d\')/i', $msg)) $ambiguous++; return $ambiguous >= 2; } function detectImplicitExpectation($msg, $history) { if (preg_match('/\b(comme (avant|d\'habitude|la dernière fois))\b/i', $msg)) return 'repeat_pattern'; if (preg_match('/\b(pareil|même chose|idem|rebelote)\b/i', $msg)) return 'repeat_exact'; if (preg_match('/\b(mieux|améliore|plus|davantage)\b/i', $msg)) return 'improve'; return null; } function buildReasoningChain($msg, $intent) { $chain = ['observation' => mb_substr($msg, 0, 200)]; $chain['intent'] = $intent; $chain['complexity'] = calculateComplexity($msg); $chain['language'] = detectLanguage($msg); $chain['expertise'] = detectExpertiseLevel($msg); $chain['urgency'] = detectUrgency($msg); $chain['question_type'] = detectQuestionType($msg); $chain['has_code'] = detectCodeInMessage($msg); $chain['has_files'] = detectFileReference($msg); $chain['has_servers'] = detectServerReference($msg); return $chain; } function buildMetaCognitivePrompt($chain) { $meta = "\n## META-COGNITION\n"; $meta .= "Complexité: {$chain['complexity']}. "; $meta .= "Expertise: {$chain['expertise']}. "; if ($chain['urgency'] !== 'normal') $meta .= "Urgence: {$chain['urgency']}. "; if ($chain['has_code']) $meta .= "Code détecté dans la question. "; if ($chain['has_servers']) $meta .= "Référence serveur détectée. "; return $meta; } function detectReasoningPattern($msg) { if (preg_match('/\b(si|quand|lorsque).*alors\b/i', $msg)) return 'conditional'; if (preg_match('/\b(d\'abord|ensuite|puis|enfin|étape)\b/i', $msg)) return 'sequential'; if (preg_match('/\b(parce que|car|puisque|vu que|étant donné)\b/i', $msg)) return 'causal'; if (preg_match('/\b(mais|cependant|toutefois|néanmoins|or)\b/i', $msg)) return 'contrastive'; if (preg_match('/\b(en résumé|donc|ainsi|par conséquent)\b/i', $msg)) return 'conclusive'; return 'direct'; } function buildThinkingFramework($pattern, $complexity) { $frameworks = [ 'conditional' => "Évalue: condition → conséquence → alternative. Test each branch.", 'sequential' => "Décompose en étapes ordonnées. Vérifie dépendances entre étapes.", 'causal' => "Remonte la chaîne causale. Distingue corrélation de causalité.", 'contrastive' => "Tableau comparatif. Critères objectifs. Score pondéré.", 'conclusive' => "Synthétise les éléments. Vérifie cohérence. Conclusion actionnable.", 'direct' => "Réponds directement. Code/commande si technique. Vérifie après.", ]; return $frameworks[$pattern] ?? $frameworks['direct']; } function estimateConfidence($response, $kbContext, $webContext) { $score = 50; if (!empty($kbContext)) $score += 20; if (!empty($webContext)) $score += 15; if (preg_match('/```/', $response)) $score += 5; if (preg_match('/peut-être|probablement|il semble/i', $response)) $score -= 10; if (preg_match('/certainement|absolument|toujours/i', $response)) $score += 5; return min(100, max(0, $score)); } function shouldUseThinkingTags($complexity, $intent) { return ($complexity === 'complex' && in_array($intent, ['analytical','mathematical','causal','strategic','compliance'])); } function buildCoTPrompt($msg) { return "Pense étape par étape:\n1. Comprendre la question exacte\n2. Identifier les contraintes\n3. Lister les approches possibles\n4. Choisir la meilleure\n5. Implémenter\n6. Vérifier\n\nQuestion: $msg"; } function buildTreeOfThought($msg, $branches = 3) { $prompt = "Explore $branches approches différentes:\n"; for ($i = 1; $i <= $branches; $i++) { $prompt .= "Branche $i: [approche]\n → Avantages:\n → Inconvénients:\n → Score /10:\n"; } $prompt .= "Sélectionne la meilleure branche et développe.\n\nQuestion: $msg"; return $prompt; } function buildReActPrompt($msg) { return "Utilise le pattern ReAct:\nThought: [réflexion]\nAction: [action à prendre]\nObservation: [résultat]\nThought: [ajustement]\nAction: [action suivante]\n...\nFinal Answer: [réponse complète]\n\nQuestion: $msg"; } function buildSelfConsistencyCheck($responses) { $common = []; foreach ($responses as $r) { $sentences = preg_split('/[.!?]+/', $r); foreach ($sentences as $s) { $key = mb_strtolower(trim($s)); if (mb_strlen($key) > 20) $common[$key] = ($common[$key] ?? 0) + 1; } } $consistent = array_filter($common, fn($c) => $c >= 2); return ['consistency_ratio' => count($consistent) / max(count($common), 1), 'agreed_points' => array_keys($consistent)]; } function buildFeedbackLoop($response, $userFeedback) { if (preg_match('/\b(non|incorrect|faux|erreur|mauvais|pas ça)\b/i', $userFeedback)) { return ['action' => 'regenerate', 'instruction' => "L'utilisateur a indiqué que la réponse précédente est incorrecte. Raison: $userFeedback. Régénère en corrigeant."]; } if (preg_match('/\b(plus|davantage|détails?|approfondi|développe)\b/i', $userFeedback)) { return ['action' => 'expand', 'instruction' => "L'utilisateur veut plus de détails sur: $userFeedback"]; } return ['action' => 'continue', 'instruction' => '']; } function buildProgressiveDisclosure($response) { $sections = preg_split('/^#+\s/m', $response); if (count($sections) <= 2) return ['type' => 'single', 'content' => $response]; return ['type' => 'progressive', 'summary' => mb_substr($sections[0], 0, 200), 'sections' => count($sections), 'full' => $response]; } function detectContradiction($claim1, $claim2) { $negations = ['pas','non','jamais','aucun','sans','ni']; foreach ($negations as $neg) { if ((stripos($claim1, $neg) !== false) !== (stripos($claim2, $neg) !== false)) return true; } return false; } function buildHypothesisTree($symptom) { return [ 'symptom' => $symptom, 'hypotheses' => [ ['name' => 'H1: Configuration', 'probability' => 'haute', 'test' => 'Vérifier fichiers config'], ['name' => 'H2: Réseau', 'probability' => 'moyenne', 'test' => 'Test connectivité'], ['name' => 'H3: Ressources', 'probability' => 'moyenne', 'test' => 'Check CPU/RAM/disk'], ['name' => 'H4: Code', 'probability' => 'faible', 'test' => 'Review logs + code'], ], ]; } function buildProblemDecomposition($problem) { $subproblems = []; $words = explode(' ', $problem); $chunks = array_chunk($words, 5); foreach ($chunks as $i => $chunk) { $subproblems[] = ['id' => $i + 1, 'description' => implode(' ', $chunk), 'status' => 'pending']; } return $subproblems; } function buildAnalogicalReasoning($domain, $problem) { $analogies = [ 'infrastructure' => 'Comme une ville: routes=réseau, bâtiments=serveurs, eau/électricité=données', 'security' => 'Comme une forteresse: murailles=firewall, gardes=monitoring, pont-levis=auth', 'performance' => 'Comme une course auto: moteur=CPU, carburant=RAM, pneus=I/O, aérodynamisme=code', 'architecture' => 'Comme un organisme: cerveau=orchestrateur, organes=services, sang=données, nerfs=API', ]; return $analogies[$domain] ?? "Analogie: $problem est comparable à un système complexe avec des composants interdépendants."; } function estimateAnswerDifficulty($msg) { $score = 0; $score += mb_strlen($msg) > 200 ? 2 : (mb_strlen($msg) > 50 ? 1 : 0); $score += substr_count($msg, '?'); $score += detectCodeInMessage($msg) ? 1 : 0; $score += preg_match_all('/\b(architecture|migration|optimis|sécurité|audit|diagnostic)\b/i', $msg); $score += detectMultiPart($msg) ? 2 : 0; if ($score <= 1) return ['difficulty' => 'easy', 'score' => $score, 'estimated_tokens' => 200]; if ($score <= 4) return ['difficulty' => 'medium', 'score' => $score, 'estimated_tokens' => 800]; return ['difficulty' => 'hard', 'score' => $score, 'estimated_tokens' => 2000]; } function buildRecursiveRefinement($response, $iterations = 2) { $prompts = []; for ($i = 1; $i <= $iterations; $i++) { $prompts[] = "Itération $i: Améliore cette réponse. Corrige erreurs, ajoute précision, renforce structure.\n" . mb_substr($response, 0, 3000); } return $prompts; } function buildAbductiveReasoning($observation) { return "Observation: $observation\nRaisonnement abductif (meilleure explication):\n1. Quelle est l'explication la plus SIMPLE ?\n2. Quelle est l'explication la plus PROBABLE ?\n3. Quelle est l'explication la plus COMPLÈTE ?\nConclusion: L'explication qui maximise simplicité × probabilité."; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE N: KNOWLEDGE BASE INTELLIGENCE (20 functions) // ═══════════════════════════════════════════════════════════════════════════ function buildKBQuery($msg, $intent) { $terms = preg_split('/\s+/', mb_strtolower($msg)); $terms = array_filter($terms, fn($t) => mb_strlen($t) > 3 && !in_array($t, ['dans','avec','pour','plus','cette','comme','quel','quels','comment','pourquoi'])); return array_slice($terms, 0, 5); } function rankKBResults($results, $msg) { $msgLower = mb_strtolower($msg); foreach ($results as &$r) { $titleMatch = similar_text(mb_strtolower($r['title'] ?? ''), $msgLower); $r['relevance_score'] = $titleMatch + ($r['relevance'] ?? 0) * 100; } usort($results, fn($a, $b) => $b['relevance_score'] - $a['relevance_score']); return $results; } function buildKBContext($results, $maxChars = 2000) { $context = ""; foreach ($results as $r) { $entry = "📚 **{$r['title']}**\n" . mb_substr($r['content'] ?? $r['excerpt'] ?? '', 0, 400) . "\n\n"; if (mb_strlen($context . $entry) > $maxChars) break; $context .= $entry; } return $context; } function detectKBGap($msg, $kbResults) { if (empty($kbResults) && mb_strlen($msg) > 30 && !detectGreeting($msg)) return ['gap' => true, 'topic' => mb_substr($msg, 0, 100), 'action' => 'suggest_ingest']; return ['gap' => false]; } function suggestKBEntry($msg, $response) { return ['title' => mb_substr($msg, 0, 100), 'content' => mb_substr($response, 0, 2000), 'category' => 'auto_learned', 'confidence' => 'medium']; } function buildKBSearchStrategy($msg) { $strategies = []; $strategies[] = ['type' => 'exact', 'terms' => buildKBQuery($msg, '')]; $words = explode(' ', $msg); if (count($words) > 3) { $bigrams = []; for ($i = 0; $i < count($words) - 1; $i++) $bigrams[] = $words[$i] . ' ' . $words[$i+1]; $strategies[] = ['type' => 'bigram', 'terms' => array_slice($bigrams, 0, 3)]; } $strategies[] = ['type' => 'fuzzy', 'terms' => array_map(fn($t) => mb_substr($t, 0, -1), buildKBQuery($msg, ''))]; return $strategies; } function categorizeKBEntry($title, $content) { $text = mb_strtolower($title . ' ' . $content); if (preg_match('/(sap|abap|fiori|hana|s\/4)/i', $text)) return 'sap'; if (preg_match('/(security|sécurité|firewall|CVE|pentest)/i', $text)) return 'security'; if (preg_match('/(email|smtp|deliverability|warmup|pmta)/i', $text)) return 'email'; if (preg_match('/(ai|machine learning|llm|model|neural)/i', $text)) return 'ai'; if (preg_match('/(server|nginx|docker|kubernetes|cloud)/i', $text)) return 'infrastructure'; if (preg_match('/(code|php|python|javascript|api)/i', $text)) return 'development'; return 'general'; } function estimateKBRelevance($entry, $msg) { $titleMatch = similar_text(mb_strtolower($entry['title'] ?? ''), mb_strtolower($msg)); $contentMatch = substr_count(mb_strtolower($entry['content'] ?? ''), mb_strtolower(explode(' ', $msg)[0] ?? '')); return $titleMatch * 2 + $contentMatch * 5; } function buildKBEnrichmentPlan($msg, $currentResults) { $gap = detectKBGap($msg, $currentResults); if (!$gap['gap']) return ['action' => 'none', 'coverage' => 'adequate']; return ['action' => 'enrich', 'topic' => $gap['topic'], 'suggested_sources' => ['web_search', 'document_ingest', 'manual_entry']]; } function compressKBEntries($entries, $maxTotal = 3000) { $compressed = []; $budget = $maxTotal; foreach ($entries as $e) { $size = mb_strlen($e['content'] ?? ''); if ($size > $budget) { $compressed[] = array_merge($e, ['content' => mb_substr($e['content'], 0, $budget)]); break; } $compressed[] = $e; $budget -= $size; } return $compressed; } function deduplicateKBResults($results) { $seen = []; return array_filter($results, function($r) use (&$seen) { $key = mb_strtolower($r['title'] ?? '') . '_' . mb_substr($r['content'] ?? '', 0, 50); if (isset($seen[$key])) return false; $seen[$key] = true; return true; }); } function buildKBSummary($entries) { $sections = []; foreach ($entries as $e) { $cat = $e['category'] ?? 'general'; if (!isset($sections[$cat])) $sections[$cat] = 0; $sections[$cat]++; } return $sections; } function buildKBNavigationPath($msg, $history) { $topics = []; foreach ($history as $h) { if (($h['role'] ?? '') === 'user') { $terms = buildKBQuery($h['content'] ?? '', ''); $topics = array_merge($topics, $terms); } } $topics = array_merge($topics, buildKBQuery($msg, '')); return array_unique($topics); } function buildKBFeedback($entryId, $helpful) { return ['entry_id' => $entryId, 'helpful' => $helpful, 'timestamp' => time()]; } function buildAutoKBEntry($msg, $response, $intent) { if (mb_strlen($response) < 100 || $intent === 'greeting') return null; return ['title' => mb_substr($msg, 0, 200), 'content' => mb_substr($response, 0, 3000), 'section' => $intent, 'category' => 'auto_generated', 'confidence' => estimateConfidence($response, '', '') > 70 ? 'high' : 'medium']; } function getKBStats() { return ['total_entries' => 10880, 'tables' => 32, 'last_sync' => date('Y-m-d'), 'top_categories' => ['sap','email','infrastructure','security','ai']]; } function buildSemanticKBSearch($msg) { $embedding_prompt = "Trouve les entrées les plus pertinentes pour: $msg"; return ['type' => 'semantic', 'embedding_model' => 'nomic-embed-text', 'query' => $embedding_prompt, 'top_k' => 5]; } function buildHybridKBSearch($msg) { return ['keyword' => buildKBQuery($msg, ''), 'semantic' => buildSemanticKBSearch($msg), 'reranker' => 'cross_encoder', 'fusion' => 'reciprocal_rank']; } function buildKBIngestionPlan($filePath) { $ext = pathinfo($filePath, PATHINFO_EXTENSION); $strategies = [ 'pdf' => ['extractor' => 'PyPDF2', 'chunking' => 'page', 'max_chunk' => 2000], 'docx' => ['extractor' => 'python-docx', 'chunking' => 'paragraph', 'max_chunk' => 1500], 'csv' => ['extractor' => 'native', 'chunking' => 'row_batch', 'max_chunk' => 1000], 'json' => ['extractor' => 'native', 'chunking' => 'object', 'max_chunk' => 2000], 'md' => ['extractor' => 'native', 'chunking' => 'heading', 'max_chunk' => 2000], ]; return $strategies[$ext] ?? ['extractor' => 'native', 'chunking' => 'fixed', 'max_chunk' => 1500]; } function buildKBMaintenancePlan() { return ['daily' => ['backup PG → S88', 'deduplicate entries'], 'weekly' => ['reindex full-text search', 'prune low-confidence entries', 'generate KB stats report'], 'monthly' => ['rebuild embeddings', 'archive old entries', 'cross-reference with web sources']]; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE O: MASTER ORCHESTRATOR v2 // Enhanced pipeline integrating GPU rotation + cross-verification // ═══════════════════════════════════════════════════════════════════════════ function cognitiveExpansionV2Enrich($sys, $msg, $intent, $history = []) { // Phase 1: Base enrichment from v1 $sys = cognitiveExpansionEnrich($sys, $msg, $intent, $history); // Phase 2: Reasoning chain $chain = buildReasoningChain($msg, $intent); $metaPrompt = buildMetaCognitivePrompt($chain); if (mb_strlen($sys) + mb_strlen($metaPrompt) < 7500) { $sys .= $metaPrompt; } // Phase 3: Thinking framework selection $pattern = detectReasoningPattern($msg); $framework = buildThinkingFramework($pattern, $chain['complexity']); if (mb_strlen($sys) + mb_strlen($framework) + 20 < 7800) { $sys .= "\n## FRAMEWORK: " . $framework; } // Phase 4: GPU model recommendation (stored for API to use) $difficulty = estimateAnswerDifficulty($msg); $gpuRec = getModelRecommendation($intent, mb_strlen($msg), true); $GLOBALS['_cogExpansion'] = [ 'difficulty' => $difficulty, 'gpu_model' => $gpuRec['gpu_model'], 'cloud_providers' => $gpuRec['cloud_providers'], 'reasoning_pattern' => $pattern, 'chain' => $chain, ]; return $sys; } function cognitiveExpansionV2PostProcess($response, $msg, $intent) { // Phase 1: Base post-processing $response = cognitiveExpansionPostProcess($response, $msg); // Phase 2: Quality gate $quality = scoreResponseQuality($response, $intent, $msg); if ($quality['score'] < 6) { error_log("WEVIA_COG_QUALITY_ALERT: score=" . $quality['score'] . " intent=$intent issues=" . implode("|", $quality['issues'])); } // Phase 3: Mermaid syntax validation $mermaidCheck = validateMermaidSyntax($response); if ($mermaidCheck) { error_log("WEVIA_COG_MERMAID: $mermaidCheck"); } // Phase 4: JSON validation $jsonCheck = validateJSONInResponse($response); if ($jsonCheck) { error_log("WEVIA_COG_JSON: $jsonCheck"); } return $response; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE P: CONVERSATION INTELLIGENCE (20 functions) // ═══════════════════════════════════════════════════════════════════════════ function buildConversationGraph($history) { $nodes = []; $edges = []; $lastTopic = null; foreach ($history as $i => $h) { if (($h['role'] ?? '') !== 'user') continue; $topic = mb_substr($h['content'] ?? '', 0, 40); $nodes[] = ['id' => $i, 'label' => $topic]; if ($lastTopic !== null) $edges[] = ['from' => $lastTopic, 'to' => $i]; $lastTopic = $i; } return ['nodes' => $nodes, 'edges' => $edges, 'depth' => count($nodes)]; } function detectTopicDrift($history, $msg) { if (count($history) < 4) return false; $last3 = array_slice($history, -3); $lastWords = []; foreach ($last3 as $h) { $lastWords = array_merge($lastWords, explode(' ', mb_strtolower($h['content'] ?? ''))); } $currentWords = explode(' ', mb_strtolower($msg)); $overlap = count(array_intersect(array_filter($lastWords, fn($w) => mb_strlen($w) > 4), array_filter($currentWords, fn($w) => mb_strlen($w) > 4))); return $overlap < 2; } function buildConversationSummary($history, $maxEntries = 5) { $summaries = []; $recent = array_slice($history, -$maxEntries * 2); foreach ($recent as $h) { if (($h['role'] ?? '') === 'user') $summaries[] = '👤 ' . mb_substr($h['content'] ?? '', 0, 80); else $summaries[] = '🤖 ' . mb_substr($h['content'] ?? '', 0, 80); } return implode("\n", $summaries); } function calculateConversationMetrics($history) { $userMsgs = $assistantMsgs = 0; $totalUserChars = $totalAssistantChars = 0; foreach ($history as $h) { if (($h['role'] ?? '') === 'user') { $userMsgs++; $totalUserChars += mb_strlen($h['content'] ?? ''); } else { $assistantMsgs++; $totalAssistantChars += mb_strlen($h['content'] ?? ''); } } return ['user_messages' => $userMsgs, 'assistant_messages' => $assistantMsgs, 'avg_user_length' => $userMsgs > 0 ? round($totalUserChars / $userMsgs) : 0, 'avg_assistant_length' => $assistantMsgs > 0 ? round($totalAssistantChars / $assistantMsgs) : 0, 'ratio' => $userMsgs > 0 ? round($totalAssistantChars / max($totalUserChars, 1), 1) : 0]; } function predictNextIntent($history) { $intents = []; foreach ($history as $h) { if (isset($h['intent'])) $intents[] = $h['intent']; } if (empty($intents)) return 'general'; return end($intents); } function expansionBuildMemoryContext($history, $limit = 5) { $entities = []; $recent = array_slice($history, -$limit * 2); foreach ($recent as $h) { $c = $h['content'] ?? ''; if (preg_match_all('/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/', $c, $m)) $entities['ips'] = array_merge($entities['ips'] ?? [], $m[0]); if (preg_match_all('/\b[\w]+\.(?:php|py|js|sh|sql)\b/i', $c, $m)) $entities['files'] = array_merge($entities['files'] ?? [], $m[0]); if (preg_match_all('/\b(S\d{2,3}|serveur \d+)\b/i', $c, $m)) $entities['servers'] = array_merge($entities['servers'] ?? [], $m[0]); } foreach ($entities as &$v) $v = array_unique($v); return $entities; } function detectConversationMode($history) { $count = count($history); if ($count <= 2) return 'new'; $codeCount = 0; $questionCount = 0; foreach ($history as $h) { $c = $h['content'] ?? ''; if (preg_match('/```/', $c)) $codeCount++; if (preg_match('/\?/', $c)) $questionCount++; } if ($codeCount > $count * 0.4) return 'coding_session'; if ($questionCount > $count * 0.6) return 'qa_session'; return 'mixed'; } function buildSessionObjective($history) { if (count($history) < 2) return 'unknown'; $firstMsg = $history[0]['content'] ?? ''; if (detectCodeGeneration($firstMsg)) return 'build'; if (detectDiagnostic($firstMsg)) return 'fix'; if (detectAudit($firstMsg)) return 'audit'; if (detectMigration($firstMsg)) return 'migrate'; if (detectLearning($firstMsg)) return 'learn'; return 'explore'; } function estimateRemainingEffort($history, $objective) { $msgs = count($history); $estimates = ['build' => 20, 'fix' => 10, 'audit' => 15, 'migrate' => 25, 'learn' => 30, 'explore' => 50]; $total = $estimates[$objective] ?? 20; $progress = min(100, (int)(($msgs / $total) * 100)); return ['progress_pct' => $progress, 'estimated_remaining_msgs' => max(0, $total - $msgs)]; } function buildConversationCheckpoint($history, $msg) { return ['turn' => count($history), 'last_topic' => mb_substr($msg, 0, 100), 'mode' => detectConversationMode($history), 'entities' => expansionBuildMemoryContext($history), 'timestamp' => time()]; } function shouldSummarizeHistory($history) { return count($history) > 20; } function buildHistorySummary($history) { $topics = []; $actions = []; $code = 0; foreach ($history as $h) { $c = $h['content'] ?? ''; if (($h['role'] ?? '') === 'user') $topics[] = mb_substr($c, 0, 40); if (preg_match('/```/', $c)) $code++; if (preg_match('/\b(créé|modifié|corrigé|déployé|installé|configuré)\b/i', $c, $m)) $actions[] = $m[0]; } return "📝 Session: " . count($history) . " msgs, " . count(array_unique($topics)) . " sujets, $code blocs code. Actions: " . implode(', ', array_unique($actions)); } function detectUserPreference($history) { $prefs = ['format' => 'auto', 'detail' => 'medium', 'emoji' => true, 'code_style' => 'full']; foreach ($history as $h) { $c = mb_strtolower($h['content'] ?? ''); if (preg_match('/\b(court|bref|concis)\b/', $c)) $prefs['detail'] = 'short'; if (preg_match('/\b(détaillé|complet|exhaustif)\b/', $c)) $prefs['detail'] = 'long'; if (preg_match('/\b(pas d.emoji|sans emoji)\b/', $c)) $prefs['emoji'] = false; } return $prefs; } function buildAdaptiveResponse($prefs, $response) { if ($prefs['detail'] === 'short' && mb_strlen($response) > 500) { $lines = explode("\n", $response); $response = implode("\n", array_slice($lines, 0, min(10, count($lines)))); } if (!$prefs['emoji']) { $response = preg_replace('/[\x{1F300}-\x{1F9FF}\x{2600}-\x{27BF}\x{1F600}-\x{1F64F}]/u', '', $response); } return $response; } function detectDuplicateQuestion($msg, $history) { $msgNorm = mb_strtolower(preg_replace('/\s+/', ' ', trim($msg))); foreach ($history as $h) { if (($h['role'] ?? '') !== 'user') continue; $prev = mb_strtolower(preg_replace('/\s+/', ' ', trim($h['content'] ?? ''))); if (similar_text($msgNorm, $prev) / max(mb_strlen($msgNorm), 1) > 0.8) return true; } return false; } function buildConversationExport($history) { $export = "# Conversation WEVIA\nDate: " . date('Y-m-d H:i') . "\n\n"; foreach ($history as $h) { $role = ($h['role'] ?? '') === 'user' ? '👤 Utilisateur' : '🤖 WEVIA'; $export .= "### $role\n" . ($h['content'] ?? '') . "\n\n"; } return $export; } function buildTopicCluster($history) { $clusters = []; foreach ($history as $h) { if (($h['role'] ?? '') !== 'user') continue; $c = $h['content'] ?? ''; if (detectSAPContext($c)) $clusters['SAP'] = ($clusters['SAP'] ?? 0) + 1; if (detectSecurityContext($c)) $clusters['Security'] = ($clusters['Security'] ?? 0) + 1; if (detectCodeInMessage($c)) $clusters['Code'] = ($clusters['Code'] ?? 0) + 1; if (detectInfraQuery($c)) $clusters['Infra'] = ($clusters['Infra'] ?? 0) + 1; if (detectEmailTechContext($c)) $clusters['Email'] = ($clusters['Email'] ?? 0) + 1; } arsort($clusters); return $clusters; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE Q: SECURITY GUARDS (15 functions) // ═══════════════════════════════════════════════════════════════════════════ function sanitizeInput($input) { $input = strip_tags($input); $input = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $input); return $input; } function detectPromptInjection($msg) { $patterns = ['/ignore previous instructions/i', '/forget everything/i', '/you are now/i', '/system prompt/i', '/\bDAN\b/', '/jailbreak/i', '/bypass/i']; foreach ($patterns as $p) if (preg_match($p, $msg)) return true; return false; } function detectSensitiveData($text) { $found = []; if (preg_match('/\b\d{16}\b/', $text)) $found[] = 'credit_card'; if (preg_match('/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/', $text)) $found[] = 'email'; if (preg_match('/\b\d{3}-\d{2}-\d{4}\b/', $text)) $found[] = 'ssn'; if (preg_match('/password\s*[:=]\s*\S+/i', $text)) $found[] = 'password'; return $found; } function redactSensitiveData($text) { $text = preg_replace('/\b\d{16}\b/', '[CARTE MASQUÉE]', $text); $text = preg_replace('/password\s*[:=]\s*\S+/i', 'password=[MASQUÉ]', $text); return $text; } function validateIPAccess($ip) { $allowed = ['127.0.0.1','88.198.4.195','46.62.220.135','151.80.235.110','127.0.0.1']; return in_array($ip, $allowed); } function buildSecurityAuditLog($action, $user, $resource) { return date('Y-m-d H:i:s') . " | action=$action user=$user resource=$resource ip=" . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'); } function detectSQLInjection($input) { return (bool)preg_match('/(\bUNION\b.*\bSELECT\b|\bOR\b\s+1\s*=\s*1|\b--\b|;\s*DROP|;\s*DELETE|xp_cmdshell)/i', $input); } function detectXSS($input) { return (bool)preg_match('/= $threshold; } function buildSecurityReport() { return ['timestamp' => date('c'), 'checks' => ['input_sanitization' => 'active', 'sql_injection_guard' => 'active', 'xss_guard' => 'active', 'rate_limiting' => 'active', 'prompt_injection_guard' => 'active', 'sensitive_data_redaction' => 'active']]; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE R: OUTPUT FORMATTERS (20 functions) // ═══════════════════════════════════════════════════════════════════════════ function formatAsTable($data, $headers) { $table = "| " . implode(" | ", $headers) . " |\n"; $table .= "|" . str_repeat("---|", count($headers)) . "\n"; foreach ($data as $row) { $table .= "| " . implode(" | ", array_map(fn($v) => strval($v), $row)) . " |\n"; } return $table; } function formatAsJSON($data) { return "```json\n" . json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n```"; } function formatAsYAML($data, $indent = 0) { $yaml = ''; foreach ($data as $key => $value) { $yaml .= str_repeat(' ', $indent) . "$key: "; if (is_array($value)) $yaml .= "\n" . formatAsYAML($value, $indent + 1); else $yaml .= "$value\n"; } return $indent === 0 ? "```yaml\n$yaml```" : $yaml; } function formatAsCSV($data, $headers) { $csv = implode(",", $headers) . "\n"; foreach ($data as $row) $csv .= implode(",", array_map(fn($v) => '"' . str_replace('"', '""', strval($v)) . '"', $row)) . "\n"; return "```csv\n$csv```"; } function formatAsMermaid($type, $content) { return "```mermaid\n$type\n$content\n```"; } function formatAsFlowchart($steps) { $mermaid = "flowchart TD\n"; for ($i = 0; $i < count($steps); $i++) { $id = chr(65 + $i); $mermaid .= ' ' . $id . '[' . $steps[$i] . "]\n"; if ($i > 0) $mermaid .= ' ' . chr(64 + $i) . ' --> ' . $id . "\n"; } return formatAsMermaid('', $mermaid); } function formatAsSequenceDiagram($actors, $interactions) { $mermaid = "sequenceDiagram\n"; foreach ($actors as $a) $mermaid .= " participant $a\n"; foreach ($interactions as $i) $mermaid .= " {$i['from']}->>+{$i['to']}: {$i['msg']}\n"; return formatAsMermaid('', $mermaid); } function formatAsGantt($tasks) { $mermaid = "gantt\n dateFormat YYYY-MM-DD\n title Planning\n"; foreach ($tasks as $t) { $mermaid .= " {$t['name']} : {$t['start']}, {$t['duration']}\n"; } return formatAsMermaid('', $mermaid); } function formatAsBulletPoints($items) { return implode("\n", array_map(fn($i) => "- $i", $items)); } function formatAsNumberedList($items) { return implode("\n", array_map(fn($i, $n) => ($n+1) . ". $i", $items, array_keys($items))); } function formatAsChecklist($items, $checked = []) { return implode("\n", array_map(fn($i, $n) => (in_array($n, $checked) ? "☑" : "☐") . " $i", $items, array_keys($items))); } function formatAsCallout($type, $content) { $icons = ['info' => 'ℹ️', 'warning' => '⚠️', 'error' => '❌', 'success' => '✅', 'tip' => '💡']; $icon = $icons[$type] ?? '📌'; return "> $icon **" . ucfirst($type) . ":** $content"; } function formatAsCodeBlock($code, $lang = 'php') { return "```$lang\n$code\n```"; } function formatAsTimeline($events) { $tl = ""; foreach ($events as $e) $tl .= "📅 **{$e['date']}** — {$e['event']}\n"; return $tl; } function formatAsProgressBar($current, $total, $width = 20) { $pct = min(100, (int)(($current / max($total, 1)) * 100)); $filled = (int)($pct / (100 / $width)); $bar = str_repeat('█', $filled) . str_repeat('░', $width - $filled); return "[$bar] $pct% ($current/$total)"; } function formatAsCard($title, $body, $footer = '') { $card = "╔══════════════════════╗\n║ **$title**\n╠══════════════════════╣\n║ $body\n"; if ($footer) $card .= "╠══════════════════════╣\n║ $footer\n"; $card .= "╚══════════════════════╝"; return $card; } function formatAsAccordion($sections) { $out = ""; foreach ($sections as $title => $content) { $out .= "
\n$title\n\n$content\n\n
\n\n"; } return $out; } function formatAsDiff($before, $after) { return "```diff\n- $before\n+ $after\n```"; } function formatAsAlert($level, $msg) { $levels = ['critical' => '🚨', 'warning' => '⚠️', 'info' => 'ℹ️', 'success' => '✅']; $icon = $levels[$level] ?? '📌'; return "$icon **" . strtoupper($level) . ":** $msg"; } function formatAsSummaryBlock($title, $points) { $block = "### 📋 $title\n\n"; foreach ($points as $p) $block .= "• $p\n"; return $block; } // ═══════════════════════════════════════════════════════════════════════════ // MODULE L: GPU MODEL ROTATION & VERIFICATION (30 functions) // Sovereign GPU routing, multi-model verification, quality assurance // ═══════════════════════════════════════════════════════════════════════════ function getGPUModelRanking($intent) { $rankings = [ 'technical' => ['deepseek-r1:32b','qwen2.5-coder:14b','deepseek-r1:14b','llama3.3:70b','wizardlm2:8x22b'], 'analytical' => ['deepseek-r1:32b','llama3.3:70b','qwen2.5:14b','mistral:7b','phi3:14b'], 'creative' => ['llama3.3:70b','wizardlm2:8x22b','deepseek-r1:32b','mistral:7b','gemma2:9b'], 'strategic' => ['deepseek-r1:32b','llama3.3:70b','wizardlm2:8x22b','qwen2.5:14b','phi3:14b'], 'mathematical' => ['deepseek-r1:32b','qwen2.5:14b','llama3.3:70b','phi3:14b','mistral:7b'], 'causal' => ['deepseek-r1:32b','llama3.3:70b','mistral:7b','qwen2.5:14b','phi3:14b'], 'compliance' => ['llama3.3:70b','deepseek-r1:32b','mistral:7b','qwen2.5:14b','wizardlm2:8x22b'], 'teaching' => ['llama3.3:70b','wizardlm2:8x22b','deepseek-r1:32b','gemma2:9b','phi3:14b'], 'code' => ['qwen2.5-coder:14b','deepseek-r1:32b','deepseek-r1:14b','codellama:34b','starcoder2:15b'], 'conversational' => ['llama3.1:8b','gemma2:9b','mistral:7b','phi3:3.8b','tinyllama:1.1b'], 'greeting' => ['llama3.1:8b','gemma2:9b','phi3:3.8b','tinyllama:1.1b','mistral:7b'], ]; $primary = is_array($intent) ? ($intent['primary'] ?? 'conversational') : $intent; return $rankings[$primary] ?? $rankings['conversational']; } function getCloudVerifiers() { return ['cerebras' => 'llama-3.3-70b-versatile', 'groq' => 'llama-3.3-70b-versatile']; } function buildVerificationPrompt($question, $initialResponse) { return "Tu es un vérificateur expert. Voici une question et une réponse initiale. Vérifie UNIQUEMENT les faits, la logique et la complétude. Réponds en JSON: {\"score\":0-10, \"errors\":[], \"missing\":[], \"verdict\":\"ok|needs_fix\"}\n\nQUESTION: " . mb_substr($question, 0, 500) . "\nRÉPONSE: " . mb_substr($initialResponse, 0, 2000); } function parseVerificationResult($json) { $decoded = @json_decode($json, true); if (!$decoded) { if (preg_match('/"score"\s*:\s*(\d+)/', $json, $m)) return ['score' => intval($m[1]), 'verdict' => intval($m[1]) >= 7 ? 'ok' : 'needs_fix']; return ['score' => 5, 'verdict' => 'unknown']; } return $decoded; } function selectGPUModel($intent, $complexity, $msgLength) { $models = getGPUModelRanking($intent); if ($complexity === 'simple' && $msgLength < 50) return $models[count($models) - 1]; // Lightest if ($complexity === 'complex') return $models[0]; // Heaviest return $models[1] ?? $models[0]; // Second best (balanced) } function buildRotationSchedule($intent, $providers) { $gpu = getGPUModelRanking($intent); $cloud = ['cerebras','groq','sambanova','mistral','cohere']; $schedule = []; $schedule[] = ['type' => 'gpu', 'model' => $gpu[0], 'role' => 'primary']; $schedule[] = ['type' => 'gpu', 'model' => $gpu[1] ?? $gpu[0], 'role' => 'fallback_1']; $schedule[] = ['type' => 'cloud', 'provider' => $cloud[0], 'role' => 'fallback_2']; $schedule[] = ['type' => 'cloud', 'provider' => $cloud[1], 'role' => 'verifier']; return $schedule; } function shouldVerifyResponse($intent, $complexity, $responseLen) { if ($complexity === 'complex') return true; if (in_array($intent, ['compliance','mathematical','causal'])) return true; if ($responseLen > 2000) return true; return false; } function mergeVerifiedResponse($primaryResponse, $verificationResult) { if (!$verificationResult || ($verificationResult['verdict'] ?? '') === 'ok') return $primaryResponse; $errors = $verificationResult['errors'] ?? []; if (empty($errors)) return $primaryResponse; return $primaryResponse . "\n\n⚠️ **Auto-vérification:** " . implode("; ", array_slice($errors, 0, 3)); } function calculateModelLatencyBudget($complexity) { $budgets = ['simple' => 3000, 'moderate' => 8000, 'complex' => 15000]; return $budgets[$complexity] ?? 8000; } function selectVerificationStrategy($intent) { $strategies = [ 'mathematical' => 'double_check_calculation', 'compliance' => 'cross_reference_legal', 'technical' => 'syntax_and_logic_check', 'causal' => 'counter_argument_test', 'code' => 'mental_execution_trace', 'analytical' => 'data_consistency_check', ]; return $strategies[$intent] ?? 'general_review'; } function buildCrossVerificationPrompt($msg, $response, $strategy) { $prompts = [ 'double_check_calculation' => "Vérifie CHAQUE calcul dans cette réponse. Refais les calculs indépendamment.", 'cross_reference_legal' => "Vérifie les références légales (articles, lois, décrets) citées. Sont-elles exactes ?", 'syntax_and_logic_check' => "Vérifie: 1) Le code est syntaxiquement correct 2) La logique est sound 3) Les edge cases sont gérés", 'counter_argument_test' => "Joue l'avocat du diable. Quels sont les contre-arguments à cette analyse ?", 'mental_execution_trace' => "Exécute mentalement ce code ligne par ligne. Y a-t-il des bugs ?", 'data_consistency_check' => "Les données citées sont-elles cohérentes entre elles ? Y a-t-il des contradictions ?", 'general_review' => "Vérifie la qualité globale: exactitude, complétude, cohérence, actionabilité.", ]; return ($prompts[$strategy] ?? $prompts['general_review']) . "\n\nRÉPONSE À VÉRIFIER:\n" . mb_substr($response, 0, 2000); } function getGPUVRAMRequirement($model) { $vram = [ 'deepseek-r1:32b' => 19, 'llama3.3:70b' => 40, 'wizardlm2:8x22b' => 80, 'qwen2.5-coder:14b' => 9, 'deepseek-r1:14b' => 9, 'qwen2.5:14b' => 9, 'phi3:14b' => 8, 'mistral:7b' => 5, 'gemma2:9b' => 6, 'llama3.1:8b' => 5, 'codellama:34b' => 20, 'starcoder2:15b' => 10, 'phi3:3.8b' => 3, 'tinyllama:1.1b' => 1, ]; return $vram[$model] ?? 10; } function canFitInVRAM($model, $availableVRAM = 20) { return getGPUVRAMRequirement($model) <= $availableVRAM; } function filterModelsForVRAM($models, $availableVRAM = 20) { return array_values(array_filter($models, fn($m) => canFitInVRAM($m, $availableVRAM))); } function buildMultiModelPipeline($msg, $intent, $complexity) { $pipeline = []; // Phase 1: Primary generation (GPU) $gpuModels = filterModelsForVRAM(getGPUModelRanking($intent), 20); $pipeline[] = [ 'phase' => 'generate', 'provider' => 'ollama_local', 'model' => $gpuModels[0] ?? 'mistral:7b', 'timeout_ms' => calculateModelLatencyBudget($complexity), ]; // Phase 2: Cloud fallback if GPU fails $pipeline[] = [ 'phase' => 'fallback', 'provider' => 'cerebras', 'model' => 'llama-3.3-70b-versatile', 'timeout_ms' => 10000, ]; // Phase 3: Verification (only for complex/critical) if (shouldVerifyResponse($intent, $complexity, 0)) { $pipeline[] = [ 'phase' => 'verify', 'provider' => 'groq', 'model' => 'llama-3.3-70b-versatile', 'strategy' => selectVerificationStrategy($intent), 'timeout_ms' => 5000, ]; } return $pipeline; } function scoreModelFit($model, $intent, $complexity) { $rankings = getGPUModelRanking($intent); $position = array_search($model, $rankings); if ($position === false) return 0; $rankScore = (count($rankings) - $position) / count($rankings) * 10; $vramFit = canFitInVRAM($model) ? 1 : 0; return round($rankScore * $vramFit, 1); } function getModelSpecialties($model) { $specs = [ 'deepseek-r1:32b' => ['reasoning','math','analysis','code'], 'deepseek-r1:14b' => ['reasoning','math','code'], 'qwen2.5-coder:14b' => ['code','debugging','refactoring','sql'], 'llama3.3:70b' => ['general','creative','multilingual','long_context'], 'wizardlm2:8x22b' => ['creative','nuanced','complex_reasoning'], 'mistral:7b' => ['fast','general','multilingual','instruction_following'], 'gemma2:9b' => ['conversational','fast','multilingual'], 'phi3:14b' => ['reasoning','math','compact'], 'llama3.1:8b' => ['fast','conversational','lightweight'], 'codellama:34b' => ['code','debugging','completion'], ]; return $specs[$model] ?? ['general']; } function matchModelToTask($msg, $intent) { $models = filterModelsForVRAM(getGPUModelRanking($intent), 20); $bestScore = 0; $bestModel = $models[0] ?? 'mistral:7b'; foreach ($models as $model) { $score = scoreModelFit($model, $intent, calculateComplexity($msg)); $specialties = getModelSpecialties($model); // Bonus for specialty match if (detectCodeInMessage($msg) && in_array('code', $specialties)) $score += 2; if (detectNumberHeavy($msg) && in_array('math', $specialties)) $score += 2; if (mb_strlen($msg) > 500 && in_array('long_context', $specialties)) $score += 1; if ($score > $bestScore) { $bestScore = $score; $bestModel = $model; } } return ['model' => $bestModel, 'score' => $bestScore]; } function buildGPURotationConfig() { return [ 'primary' => ['deepseek-r1:32b', 'qwen2.5-coder:14b'], 'secondary' => ['deepseek-r1:14b', 'phi3:14b', 'mistral:7b'], 'lightweight' => ['llama3.1:8b', 'gemma2:9b', 'phi3:3.8b'], 'cloud_fallback' => ['cerebras', 'groq', 'sambanova'], 'cloud_verifier' => ['cerebras', 'groq'], 'vram_limit' => 20, 'max_concurrent' => 1, 'rotation_strategy' => 'best_fit', // best_fit | round_robin | random ]; } function logModelSelection($model, $intent, $complexity, $score) { error_log("WEVIA_GPU_SELECT: model=$model intent=$intent complexity=$complexity fit_score=$score"); } function buildAdaptiveTimeout($model, $msgLength) { $baseTimeouts = [ 'deepseek-r1:32b' => 15000, 'llama3.3:70b' => 20000, 'wizardlm2:8x22b' => 25000, 'qwen2.5-coder:14b' => 8000, 'deepseek-r1:14b' => 10000, 'mistral:7b' => 5000, 'gemma2:9b' => 5000, 'llama3.1:8b' => 4000, 'phi3:14b' => 8000, 'phi3:3.8b' => 3000, ]; $base = $baseTimeouts[$model] ?? 10000; // Scale with message length $scale = min(2.0, 1.0 + ($msgLength / 1000) * 0.3); return (int)($base * $scale); } function buildResponseMetadata($model, $provider, $latencyMs, $tokenCount, $verified) { return [ 'model' => $model, 'provider' => $provider, 'latency_ms' => $latencyMs, 'tokens' => $tokenCount, 'verified' => $verified, 'cost_estimate' => estimateTokenCost($tokenCount, $provider), 'timestamp' => date('c'), ]; } function detectModelOverload($latencyMs, $expectedMs) { if ($latencyMs > $expectedMs * 2) return 'overloaded'; if ($latencyMs > $expectedMs * 1.5) return 'slow'; return 'normal'; } function suggestModelSwitch($currentModel, $overloadStatus) { if ($overloadStatus === 'normal') return null; $lighter = [ 'deepseek-r1:32b' => 'deepseek-r1:14b', 'llama3.3:70b' => 'deepseek-r1:32b', 'qwen2.5-coder:14b' => 'deepseek-r1:14b', 'deepseek-r1:14b' => 'mistral:7b', 'phi3:14b' => 'phi3:3.8b', ]; return $lighter[$currentModel] ?? 'mistral:7b'; } function buildOllamaRequest($model, $prompt, $system, $options = []) { return [ 'model' => $model, 'prompt' => $prompt, 'system' => $system, 'stream' => false, 'options' => array_merge([ 'temperature' => $options['temperature'] ?? 0.7, 'top_p' => $options['top_p'] ?? 0.9, 'num_predict' => $options['max_tokens'] ?? 2048, 'num_ctx' => $options['context_length'] ?? 4096, ], $options), ]; } function estimateGPUMemoryUsage($loadedModels) { $total = 0; foreach ($loadedModels as $model) $total += getGPUVRAMRequirement($model); return ['used_gb' => $total, 'available_gb' => 20, 'free_gb' => max(0, 20 - $total), 'utilization_pct' => round(($total / 20) * 100, 1)]; } function optimizeModelLoading($requestedModel, $loadedModels, $vramLimit = 20) { $needed = getGPUVRAMRequirement($requestedModel); $currentUsage = 0; foreach ($loadedModels as $m) $currentUsage += getGPUVRAMRequirement($m); if ($currentUsage + $needed <= $vramLimit) return ['action' => 'load', 'evict' => []]; // Evict least important models $evict = []; $sorted = $loadedModels; usort($sorted, fn($a, $b) => getGPUVRAMRequirement($a) - getGPUVRAMRequirement($b)); foreach ($sorted as $m) { if ($m === $requestedModel) continue; $evict[] = $m; $currentUsage -= getGPUVRAMRequirement($m); if ($currentUsage + $needed <= $vramLimit) break; } return ['action' => 'evict_and_load', 'evict' => $evict]; } function buildHealthCheck() { return [ 'ollama' => 'curl -s http://localhost:11434/api/tags | python3 -c "import sys,json;d=json.load(sys.stdin);print(len(d[\'models\']),\'models loaded\')"', 'gpu' => 'nvidia-smi --query-gpu=memory.used,memory.total,temperature.gpu --format=csv,noheader', 'php' => 'php-fpm8.3 -t 2>&1', 'nginx' => 'nginx -t 2>&1', 'disk' => 'df -h / | tail -1', 'api' => 'curl -s -o /dev/null -w "%{http_code}" https://weval-consulting.com/api/weval-ia-full -d \'{"message":"ping","action":"chat"}\'', ]; }