setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Auto-create tables if missing $pdo->exec("CREATE SCHEMA IF NOT EXISTS brain"); $pdo->exec("CREATE TABLE IF NOT EXISTS brain.memory ( id SERIAL PRIMARY KEY, session_id VARCHAR(100), user_id VARCHAR(100) DEFAULT 'default', memory_type VARCHAR(50) DEFAULT 'fact', key TEXT NOT NULL, value TEXT NOT NULL, confidence REAL DEFAULT 1.0, source VARCHAR(100) DEFAULT 'conversation', access_count INT DEFAULT 0, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() )"); $pdo->exec("CREATE TABLE IF NOT EXISTS brain.learnings ( id SERIAL PRIMARY KEY, category VARCHAR(100), scenario VARCHAR(200), input TEXT, output TEXT, score REAL, quality VARCHAR(20), provider VARCHAR(100), improvement TEXT, applied BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW() )"); $pdo->exec("CREATE TABLE IF NOT EXISTS brain.consensus_log ( id SERIAL PRIMARY KEY, query TEXT, provider_count INT, winner VARCHAR(100), response TEXT, elapsed_ms INT, created_at TIMESTAMP DEFAULT NOW() )"); $pdo->exec("CREATE INDEX IF NOT EXISTS idx_memory_key ON brain.memory(key)"); $pdo->exec("CREATE INDEX IF NOT EXISTS idx_memory_type ON brain.memory(memory_type)"); $pdo->exec("CREATE INDEX IF NOT EXISTS idx_learnings_cat ON brain.learnings(category)"); } catch (Exception $e) { return null; } } return $pdo; } // ═══════════════════════════════════════════════════════ // CLAUDE OPUS 4.6 SKILL SYSTEM // ═══════════════════════════════════════════════════════ function getOpusSkills() { $skills = [ // Core Reasoning Skills 'chain-of-thought' => ['desc' => 'Deep reasoning with step-by-step thinking', 'trigger' => '/analyse|compare|pourquoi|explain|debug/i'], 'tree-of-thoughts' => ['desc' => 'Multi-path exploration for complex problems', 'trigger' => '/strateg|optimis|architect|plan|design/i'], 'self-critique' => ['desc' => 'Verify own response accuracy before output', 'trigger' => '/verifi|precise|exact|certain|sure/i'], // Domain Skills 'erp-sap-expert' => ['desc' => 'SAP S/4HANA, modules FI/CO/MM/SD, Vistex', 'trigger' => '/sap|erp|vistex|s4hana|fiori|abap/i'], 'cloud-architect' => ['desc' => 'AWS, Azure, GCP, hybrid, sovereign cloud', 'trigger' => '/cloud|aws|azure|gcp|kubernetes|docker/i'], 'cybersecurity' => ['desc' => 'OWASP, pentest, SOC, SIEM, zero-trust', 'trigger' => '/securit|owasp|pentest|soc|siem|firewall|vulnerability/i'], 'data-engineer' => ['desc' => 'ETL, data lake, BI, ML pipelines', 'trigger' => '/data|etl|pipeline|warehouse|bi|machine.learning/i'], 'email-deliverability' => ['desc' => 'SPF, DKIM, DMARC, PMTA, KumoMTA, warmup', 'trigger' => '/email|delivrabilit|dkim|spf|dmarc|pmta|kumo|warmup/i'], 'pharma-hcp' => ['desc' => 'Life Sciences, HCP outreach, Ethica, Maghreb regulations', 'trigger' => '/pharma|hcp|medecin|ethica|loi.*09.*08|consentement|maghreb.*sante/i'], // Output Skills 'mermaid-architect' => ['desc' => 'Generate Mermaid diagrams (flowcharts, sequences, ERDs)', 'trigger' => '/schema|diagramme|flowchart|mermaid|architecture|processus/i'], 'svg-designer' => ['desc' => 'Generate SVG logos and illustrations', 'trigger' => '/logo|svg|icone|illustration|branding/i'], 'pdf-generator' => ['desc' => 'Generate structured PDF documents', 'trigger' => '/pdf|document|rapport|genere.*document/i'], 'code-generator' => ['desc' => 'Python, PHP, JS, SQL, Bash code generation', 'trigger' => '/code|script|python|php|javascript|sql|bash|function/i'], // Analysis Skills 'swot-analyst' => ['desc' => 'SWOT, PESTEL, Porter, BCG analysis', 'trigger' => '/swot|pestel|porter|bcg|analyse.*strateg/i'], 'market-researcher' => ['desc' => 'Market research, competitive analysis, trends', 'trigger' => '/marche|concurrent|benchmark|trend|etude/i'], 'financial-advisor' => ['desc' => 'Financial modeling, ROI, TCO calculations', 'trigger' => '/roi|tco|financ|budget|cout|pricing|tarif/i'], // Communication Skills 'proposal-writer' => ['desc' => 'Write professional proposals and offers', 'trigger' => '/proposition|offre|devis|proposal|commercial/i'], 'email-composer' => ['desc' => 'Draft professional emails', 'trigger' => '/email.*redige|mail.*ecri|courrier|draft/i'], 'multilingual' => ['desc' => '14 languages: FR, EN, AR, Darija, ES, DE, IT, PT, ZH, JA, KO, RU, TR, HI', 'trigger' => '/traduire|translate|langue|language/i'], ]; return $skills; } function detectSkills($query) { $skills = getOpusSkills(); $matched = []; foreach ($skills as $name => $skill) { if (preg_match($skill['trigger'], $query)) { $matched[] = $name; } } return $matched ?: ['chain-of-thought']; // default } // ═══════════════════════════════════════════════════════ // COLLECTIVE CONSCIOUSNESS (Multi-model consensus) // ═══════════════════════════════════════════════════════ function collectiveAsk($query, $sys = '', $lang = 'fr') { $providers = [ ['name'=>'Groq', 'url'=>'https://api.groq.com/openai/v1/chat/completions', 'key'=>GROQ_KEY, 'model'=>'llama-3.3-70b-versatile', 'timeout'=>8], ['name'=>'Cerebras', 'url'=>'https://api.cerebras.ai/v1/chat/completions', 'key'=>CEREBRAS_KEY, 'model'=>'qwen-3-235b-a22b-instruct-2507', 'timeout'=>8], ]; // Inject matched skills into system prompt $skills = detectSkills($query); $skillContext = "Tes compétences activees pour cette requete: " . implode(', ', $skills) . "."; // Memory context $memories = recallMemories($query, 3); $memContext = ''; if ($memories) { $memContext = " Contexte memoire: " . implode('; ', array_map(fn($m) => $m['key'].': '.$m['value'], $memories)); } $fullSys = ($sys ?: "Tu es WEVIA, IA souveraine WEVAL Consulting.") . " $skillContext" . $memContext; // Parallel query $mh = curl_multi_init(); $handles = []; foreach ($providers as $p) { $ch = curl_init($p['url']); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $p['timeout'], CURLOPT_CONNECTTIMEOUT => 3, CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer '.$p['key']], CURLOPT_POSTFIELDS => json_encode(['model'=>$p['model'], 'messages'=>[ ['role'=>'system','content'=>$fullSys], ['role'=>'user','content'=>mb_substr($query,0,2000)] ], 'max_tokens'=>800, 'temperature'=>0.7]) ]); curl_multi_add_handle($mh, $ch); $handles[] = ['ch'=>$ch, 'name'=>$p['name']]; } // Execute all in parallel $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh, 0.1); } while ($running > 0); $responses = []; foreach ($handles as $h) { $r = curl_multi_getcontent($h['ch']); $code = curl_getinfo($h['ch'], CURLINFO_HTTP_CODE); curl_multi_remove_handle($mh, $h['ch']); curl_close($h['ch']); if ($code == 200 && $r) { $d = json_decode($r, true); $text = trim($d['choices'][0]['message']['content'] ?? ''); if (strlen($text) > 20) { $responses[] = ['provider'=>$h['name'], 'text'=>$text, 'len'=>strlen($text)]; } } } curl_multi_close($mh); if (empty($responses)) return ['response'=>'Service indisponible', 'provider'=>'none', 'skills'=>$skills]; // Pick best (longest + most complete) usort($responses, fn($a,$b) => $b['len'] - $a['len']); $winner = $responses[0]; // Log consensus $db = getDB(); if ($db) { try { $db->prepare("INSERT INTO brain.consensus_log (query, provider_count, winner, response, elapsed_ms) VALUES (?,?,?,?,?)") ->execute([mb_substr($query,0,200), count($responses), $winner['provider'], mb_substr($winner['text'],0,500), 0]); } catch(Exception $e) {} } return ['response'=>$winner['text'], 'provider'=>$winner['provider'], 'providers_responded'=>count($responses), 'skills'=>$skills]; } // ═══════════════════════════════════════════════════════ // PERSISTENT MEMORY // ═══════════════════════════════════════════════════════ function storeMemory($key, $value, $type = 'fact', $source = 'conversation', $session = '', $confidence = 1.0) { $db = getDB(); if (!$db) return false; try { $db->prepare("INSERT INTO brain.memory (session_id, memory_type, key, value, confidence, source) VALUES (?,?,?,?,?,?)") ->execute([$session, $type, $key, $value, $confidence, $source]); return true; } catch(Exception $e) { return false; } } function recallMemories($query, $limit = 5) { $db = getDB(); if (!$db) return []; try { // Simple keyword matching (could be upgraded to vector search via Qdrant) $words = array_filter(explode(' ', preg_replace('/[^a-zA-Z0-9\s]/u', '', strtolower($query))), fn($w) => strlen($w) > 3); if (empty($words)) return []; $conditions = array_map(fn($w) => "LOWER(key || ' ' || value) LIKE '%$w%'", array_slice($words, 0, 5)); $sql = "SELECT key, value, memory_type, confidence FROM brain.memory WHERE " . implode(' OR ', $conditions) . " ORDER BY confidence DESC, updated_at DESC LIMIT $limit"; return $db->query($sql)->fetchAll(PDO::FETCH_ASSOC); } catch(Exception $e) { return []; } } // ═══════════════════════════════════════════════════════ // AUTO-LEARNING // ═══════════════════════════════════════════════════════ function storeLearning($category, $scenario, $input, $output, $score, $quality, $provider, $improvement = '') { $db = getDB(); if (!$db) return false; try { $db->prepare("INSERT INTO brain.learnings (category, scenario, input, output, score, quality, provider, improvement) VALUES (?,?,?,?,?,?,?,?)") ->execute([$category, $scenario, mb_substr($input,0,500), mb_substr($output,0,1000), $score, $quality, $provider, $improvement]); // Auto-store high-quality responses as memories if ($score >= 8 && $quality === 'excellent') { storeMemory("learned:$scenario", mb_substr($output, 0, 500), 'learned', 'auto-learning', '', $score/10); } return true; } catch(Exception $e) { return false; } } function getLearningStats() { $db = getDB(); if (!$db) return ['error' => 'no db']; try { $total = $db->query("SELECT COUNT(*) FROM brain.learnings")->fetchColumn(); $excellent = $db->query("SELECT COUNT(*) FROM brain.learnings WHERE quality='excellent'")->fetchColumn(); $recent = $db->query("SELECT category, quality, score FROM brain.learnings ORDER BY created_at DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC); return ['total'=>$total, 'excellent'=>$excellent, 'recent'=>$recent]; } catch(Exception $e) { return ['error' => $e->getMessage()]; } } // ═══════════════════════════════════════════════════════ // ACTION ROUTER // ═══════════════════════════════════════════════════════ switch ($action) { case 'ask': $query = $input['query'] ?? $input['message'] ?? ''; if (!$query) { echo json_encode(['error'=>'query required']); break; } $result = collectiveAsk($query, $input['system'] ?? '', $input['lang'] ?? 'fr'); echo json_encode($result); break; case 'remember': $ok = storeMemory($input['key'] ?? '', $input['value'] ?? '', $input['type'] ?? 'fact', $input['source'] ?? 'api', $input['session'] ?? ''); echo json_encode(['success'=>$ok]); break; case 'recall': $memories = recallMemories($input['query'] ?? '', $input['limit'] ?? 5); echo json_encode(['memories'=>$memories, 'count'=>count($memories)]); break; case 'learn': $ok = storeLearning($input['category']??'general', $input['scenario']??'', $input['input']??'', $input['output']??'', floatval($input['score']??0), $input['quality']??'unknown', $input['provider']??''); echo json_encode(['success'=>$ok]); break; case 'skills': $skills = getOpusSkills(); $query = $input['query'] ?? ''; $matched = $query ? detectSkills($query) : array_keys($skills); echo json_encode(['total'=>count($skills), 'matched'=>$matched, 'skills'=>$skills]); break; case 'status': default: $db = getDB(); $stats = ['db'=>'disconnected', 'memory'=>0, 'learnings'=>['total'=>0], 'skills'=>count(getOpusSkills()), 'models'=>['cloud'=>3,'local'=>10], 'consensus'=>'ready']; if ($db) { try { $stats['db'] = 'connected'; $stats['memory'] = $db->query("SELECT COUNT(*) FROM brain.memory")->fetchColumn(); $stats['learnings'] = getLearningStats(); $stats['consensus_log'] = $db->query("SELECT COUNT(*) FROM brain.consensus_log")->fetchColumn(); } catch(Exception $e) { $stats['db_error'] = $e->getMessage(); } } echo json_encode([ 'service' => 'WEVIA Brain Orchestrator', 'version' => '2.0', 'capabilities' => ['collective_consciousness', 'persistent_memory', 'auto_learning', 'opus_skills', 'multi_language'], 'stats' => $stats, 'status' => 'live' ], JSON_PRETTY_PRINT); }