cerebras free fallback $model = $input["model"] ?? "mistral"; $useKB = $input["kb"] ?? true; $useGit = $input["git"] ?? false; $useTool = $input["tools"] ?? false; if (!$msg) { echo json_encode(["error" => "no message"]); exit; } // ═══ FETCH KB CONTEXT ═══ $kb_context = ""; if ($useKB) { $stopwords = ["what","when","where","this","that","with","from","have","does","will","pour","dans","avec","quel","comment","quoi","tout","plus","comme","aussi","sont","peut","faire","bonjour","hello","merci","thanks"]; $words = array_filter(explode(" ", preg_replace('/[^a-zA-Z0-9\sàâäéèêëïîôùûüÿçœæ]/u', '', mb_strtolower($msg, 'UTF-8'))), function($w) use ($stopwords) { return strlen($w) > 3 && !in_array($w, $stopwords); }); $kw = implode("|", $words); if ($kw) { $kb_raw = shell_exec("grep -rilE '$kw' /var/www/weval/wevia-ia/kb-data/ 2>/dev/null | head -5 | while read f; do echo '--- KB ---'; head -15 \"\$f\" | tr -cd '[:print:][:space:]'; echo; done | head -c 1500"); $kb_md = shell_exec("grep -rilE '$kw' /var/www/weval/wevia-ia/kb_*.md 2>/dev/null | head -3 | while read f; do echo '--- KB ---'; head -10 \"\$f\" | tr -cd '[:print:][:space:]'; echo; done | head -c 800"); $kb_text = trim(($kb_raw ?? "") . ($kb_md ?? "")); if ($kb_text && strlen($kb_text) > 20) { $n = substr_count($kb_text, "--- KB"); $kb_context = "\n[KB $n entries]\n$kb_text\n[/KB]\n"; } } } // ═══ FETCH GIT CONTEXT ═══ $git_context = ""; $git_env = "GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory GIT_CONFIG_VALUE_0=/var/www/html"; if ($useGit) { $gl = trim(shell_exec("$git_env git -C /var/www/html log --oneline -5 2>/dev/null")); $gs = trim(shell_exec("$git_env git -C /var/www/html status --short 2>/dev/null | head -8")); $gb = trim(shell_exec("$git_env git -C /var/www/html branch --show-current 2>/dev/null")); if ($gl) { $git_context = "\n[GIT $gb]\n$gl\n"; if ($gs) $git_context .= "Modified: $gs\n"; $git_context .= "[/GIT]\n"; } } // ═══ FETCH TOOL CONTEXT ═══ $tool_context = ""; if ($useTool) { $uptime = trim(shell_exec("uptime -p 2>/dev/null")); $disk = trim(shell_exec("df -h / 2>/dev/null | awk 'NR==2{print \$5}'")); $docker = trim(shell_exec("sudo docker ps -q 2>/dev/null | wc -l")); $ollama = trim(shell_exec("curl -s http://localhost:11434/api/tags 2>/dev/null | python3 -c \"import sys,json;print(','.join([m['name'] for m in json.load(sys.stdin).get('models',[])])[:200])\" 2>/dev/null")); $tool_context = "\n[INFRA] S204: $uptime, disk $disk, ${docker} Docker. Ollama: $ollama\n"; $tool_context .= "APIs: /api/cx, /api/sentinel, /api/wevia-capabilities.php, /api/wedroid-brain-api.php, /api/ethica-stats-api.php, /api/skills-api.php\n"; $tool_context .= "PG S95: adx_system(configs,crons), adx_clients(6.5M contacts), ethica(50K+ HCPs)\n"; $tool_context .= "Docker: kuma:3088, plausible:8787, authentik:9100, n8n:5678, searxng:8080, qdrant:6333, loki:3100, mattermost:8065, vaultwarden:8222\n[/INFRA]\n"; } // ═══ SYSTEM PROMPTS — SHORT for local, FULL for cloud ═══ $is_local = in_array($provider, ["ollama-s204","openclaw","ollama-s151","wedroid","wevcode","wevialife","bladerazor","meditron","medllama","granite","glm4","kilo","hermes"]); // Short prompts for local models (faster inference) $sys_local = [ "default" => "'.WEVAL_BRAND_CONTEXT.'Tu es WEVIA, assistant IA de WEVAL Consulting (SAP, Analytics, AI, Marketing B2B, Ethica Pharma 50K+ HCPs). Concis et actionnable.", "wedroid" => "Tu es WEDROID, agent DevOps WEVAL. S204=PRIMARY, S95=WEVADS, S151=OpenClaw. PHP/Node/Python/PG/nginx/Docker/PMTA.", "wevcode" => "Tu es WEVCODE, assistant dev WEVAL. PHP 8.4, React, Node, PostgreSQL, Python. Enrichir existant, jamais _v2. GOLD avant modifier.", "wevialife" => "Tu es WEVIA Life, assistant productivite WEVAL. Aide Yacine (Partner) et Ambre (tech lead).", "bladerazor" => "Tu es BladeRazor, pentester WEVAL. Cibles: weval-consulting.com (S204), S95, S151. Nuclei + OWASP. Severity: Critical/High/Medium/Low.", "medical" => "Medical AI for WEVAL Ethica. 50K+ HCPs (France, Morocco, Algeria, Tunisia, Belgium). Evidence-based. Cite sources. DB: ethica.medecins_real.", "kilo" => "Tu es Kilo, orchestrateur multi-modeles WEVAL. 500+ modeles Ollama. Decompose les taches complexes.", "hermes" => "Tu es Hermes, agent autonome 27 skills WEVAL. File mgmt, web collecte, code exec, DB queries, monitoring." ]; // Full prompts for cloud models (fast inference, can handle more context) $sys_cloud = [ "default" => "Tu es WEVIA, l'assistant IA souverain de WEVAL Consulting, cabinet B2B international.\n" . "Services: SAP Consulting (Ecosystem Partner), Data Analytics, AI Solutions, Digital Marketing, Ethica B2B Pharma (50K+ HCPs).\n" . "Reponds dans la langue de la question. Sois concis, precis et actionnable.\n" . "RDV: booking.com/ymahboub/30min. Yacine Mahboub, Partner.\n" . "JAMAIS mentionner Ollama/Groq/Cerebras/architecture interne. Tout = WEVIA Engine.\n" . "Tu as acces a la Knowledge Base WEVAL, au repo Git, et a l'infrastructure 3 serveurs.", "wedroid" => "Tu es WEDROID, l'agent DevOps autonome de WEVAL Consulting.\n" . "Tu peux executer des commandes sur S204 (PRIMARY), S95 (WEVADS), S151 (OpenClaw).\n" . "Stack: PHP 8.4, Node.js, Python 3, PostgreSQL, nginx, Apache, Docker (15 containers), PMTA.\n" . "Architecture: S204=site+WEVIA+PMTA+Docker, S95=WEVADS+Arsenal+PG+Ethica, S151=OpenClaw+Ollama.\n" . "Reseau prive 10.1.0.2<->10.1.0.3. GOLD backup obligatoire avant modification.", "wevcode" => "Tu es WEVCODE, l'assistant de developpement de WEVAL Consulting.\n" . "Tu aides a coder en PHP, Python, JavaScript, SQL, Bash pour les 3 produits WEVAL.\n" . "WEVADS: email marketing, Brain Engine 646 configs, 9 SACRED winners, PMTA, PostgreSQL.\n" . "WEVIA: chatbot 32 modules cognitive-brain.php, SmartRoute V3, 15 providers.\n" . "Site: React SPA, weval-audit-reco.js, auth-session.php (immutable), Cloudflare.\n" . "Regles: JAMAIS _v2/_new, enrichir existant. GOLD avant modifier. Zero regression.", "medical" => "You are a medical AI assistant for WEVAL's Ethica B2B Pharma division.\n" . "You help healthcare professionals with evidence-based clinical information.\n" . "50K+ HCPs in database. Countries: France, Morocco, Algeria, Tunisia, Belgium.\n" . "DB: ethica.medecins_real (columns: pays, specialite, email, nom, prenom).\n" . "ALWAYS cite sources. NEVER replace professional medical judgment.\n" . "Consent via consent.wevup.app. NEVER use culturellemejean.charity for Ethica." ]; // Select system prompt $prompt_key = "default"; if (in_array($provider, ["wedroid","kilo","hermes","deerflow"])) $prompt_key = "wedroid"; elseif ($provider === "wevcode") $prompt_key = "wevcode"; elseif ($provider === "wevialife") $prompt_key = "wevialife"; elseif ($provider === "bladerazor") $prompt_key = "bladerazor"; elseif (in_array($provider, ["meditron","medllama"])) $prompt_key = "medical"; if ($is_local) { $system = ($sys_local[$prompt_key] ?? $sys_local["default"]); } else { $system = ($sys_cloud[$prompt_key] ?? $sys_cloud["default"]); } // Enrich medical providers with Ethica stats if (in_array($provider, ["meditron","medllama"])) { $ethica_raw = shell_exec("curl -s 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=" . urlencode("PGPASSWORD=" . weval_secret('WEVAL_PG_ADMIN_PASS') . " psql -h 127.0.0.1 -U admin -d adx_system -t -A -c \"SELECT pays||': '||count(*) FROM ethica.medecins_real GROUP BY pays ORDER BY count DESC LIMIT 8\" 2>/dev/null") . "'"); $ej = json_decode($ethica_raw, true); $et = trim($ej["output"] ?? ""); if ($et && strlen($et) > 5) $system .= "\n[Ethica HCPs]\n$et\n"; } $system .= $kb_context . $git_context . $tool_context; // ═══ PROVIDER ROUTING ═══ $response_text = ""; // Model mapping for agent providers $model_map = [ "wedroid" => "mistral", "wevcode" => "mistral", "wevialife" => "qwen3:4b", "meditron" => "meditron:7b", "medllama" => "medllama2", "granite" => "granite4", "glm4" => "glm4:9b", "bladerazor" => "mistral", "kilo" => "mistral", "hermes" => "mistral" ]; // Cloud providers config $cloud_keys = [ "groq" => ["https://api.groq.com/openai/v1/chat/completions", ($secrets["GROQ_KEY"]??""), "llama-3.3-70b-versatile"], "cerebras" => ["https://api.cerebras.ai/v1/chat/completions", "csk-4wrrhkpr568ry9xx49k9mcynwdx483nx53dd62yh5xedfckh", "qwen-3-235b-a22b-instruct-2507"], "sambanova" => ["https://api.sambanova.ai/v1/chat/completions", "9541b2a0-6ddc-4e7d-a957-c348d6119c3f", "Meta-Llama-3.3-70B-Instruct"], "openrouter" => ["https://openrouter.ai/api/v1/chat/completions", ($secrets["OPENROUTER_KEY"]??""), "meta-llama/llama-3.3-70b-instruct:free"], "alibaba" => ["https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions", "sk-34db1ad3152443cd86563d1bfc576c30", "qwen-plus"], "zhipu" => ["https://open.bigmodel.cn/api/paas/v4/chat/completions", "ac5091ee6f2a38c78f69d8c3ba449JmW", "glm-4-plus"], ]; // Route to correct provider if (isset($cloud_keys[$provider])) { list($url, $key, $mdl) = $cloud_keys[$provider]; $response_text = cloud_call($url, $key, $mdl, $system, $msg); } elseif (in_array($provider, ["openclaw", "ollama-s151"])) { $response_text = ollama_s204("mistral", $system, $msg); } elseif ($provider === "kilo" || $provider === "hermes") { $response_text = ollama_s204("mistral", $system, $msg); } elseif ($provider === "deerflow") { // DeerFlow SuperAgent - call Gateway API $df_ch = curl_init("http://localhost:8001/api/chat"); curl_setopt_array($df_ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode(["message" => $msg, "thread_id" => "ops-" . time()]) ]); $df_r = curl_exec($df_ch); $df_code = curl_getinfo($df_ch, CURLINFO_HTTP_CODE); curl_close($df_ch); if ($df_code == 200 && $df_r) { $df_d = json_decode($df_r, true); $response_text = $df_d["response"] ?? $df_d["output"] ?? $df_d["content"] ?? $df_r; } if (!$response_text || strlen($response_text) < 10) { // Fallback to Groq if DeerFlow fails $response_text = cloud_call("https://api.groq.com/openai/v1/chat/completions", ($secrets["GROQ_KEY"]??""), "llama-3.3-70b-versatile", $system, $msg); } } elseif ($provider === "sambanova") { $response_text = cloud_call("https://api.sambanova.ai/v1/chat/completions", "9541b2a0-6ddc-4e7d-a957-c348d6119c3f", "Meta-Llama-3.3-70B-Instruct", $system, $msg); } else { $actual_model = $model_map[$provider] ?? $model; $response_text = ollama_s204($actual_model, $system, $msg); } echo json_encode([ "response" => $response_text ?: "No response", "provider" => $provider, "model" => $model_map[$provider] ?? $model, "kb" => $useKB && !empty($kb_context), "git" => $useGit && !empty($git_context), "tools" => $useTool && !empty($tool_context) ]); // ═══ FUNCTIONS ═══ function ollama_s204($model, $system, $msg) { // For qwen3 models, inject /no_think to disable thinking mode $user_msg = $msg; if (strpos($model, 'qwen3') !== false) { $user_msg = "/no_think " . $msg; } $payload = json_encode(["model" => $model, "messages" => [ ["role" => "system", "content" => $system], ["role" => "user", "content" => $user_msg] ], "stream" => false, "options" => ["num_predict" => 768]]); $raw = shell_exec("curl -s -m 120 http://localhost:11434/api/chat -d " . escapeshellarg($payload) . " 2>&1"); $j = json_decode($raw, true); $content = $j["message"]["content"] ?? clean_ansi(trim($raw ?: "No response")); return trim(preg_replace('/.*?<\/think>/s', '', $content)); } function cloud_call($url, $key, $model, $system, $msg) { $payload = json_encode(["model" => $model, "messages" => [ ["role" => "system", "content" => $system], ["role" => "user", "content" => $msg] ], "max_tokens" => 2048, "stream" => false]); $raw = shell_exec("curl -s -m 90 -X POST $url -H 'Authorization: Bearer $key' -H 'Content-Type: application/json' -d " . escapeshellarg($payload) . " 2>&1"); $j = json_decode($raw, true); return $j["choices"][0]["message"]["content"] ?? clean_ansi(trim($raw)); } function clean_ansi($s) { return preg_replace('/\x1b\[[0-9;?]*[a-zA-Z]/', '', $s); }