'unauthorized'])); } function api($url, $method = 'GET', $body = null, $timeout = 8) { $ch = curl_init($url); $headers = ['Content-Type: application/json']; if ($body) curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($body) ? $body : json_encode($body)); if ($method !== 'GET') curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); curl_setopt_array($ch, [CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout]); $r = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return ['code' => $code, 'data' => json_decode($r, true) ?: $r]; } switch ($cap) { // ═══ HEALTH CHECK ═══ case 'health': $services = [ 'searxng' => api('http://localhost:8888/healthz', 'GET', null, 3), 'qdrant' => api('http://localhost:6333/healthz', 'GET', null, 3), 'ollama' => api('https://api.groq.com/openai/v1/models', 'GET', null, 3), 'n8n' => api('http://localhost:5678/healthz', 'GET', null, 3), 'plausible'=> api('https://analytics.weval-consulting.com/api/health', 'GET', null, 5), 'kuma' => api('http://localhost:3088/api/entry', 'GET', null, 3), 'loki' => api('http://localhost:3100/ready', 'GET', null, 3), 'mattermost'=> api('http://localhost:8065/api/v4/system/ping', 'GET', null, 3), 'vaultwarden'=> api('http://localhost:8222/alive', 'GET', null, 3), 'ollama_local'=> api('http://localhost:11434/api/tags', 'GET', null, 3), ]; $up = 0; foreach ($services as $k => &$s) { $s['up'] = $s['code'] >= 200 && $s['code'] < 500; if ($s['up']) $up++; unset($s['data']); // compact } echo json_encode(['services' => $services, 'up' => $up, 'total' => count($services)]); break; // ═══ SEARXNG: Web search for WEVIA chatbot ═══ case 'search': if (!$q) die(json_encode(['error' => 'no query'])); $r = api("http://localhost:8888/search?q=" . urlencode($q) . "&format=json&engines=google,bing,duckduckgo&language=fr", 'GET', null, 10); $results = []; foreach (($r['data']['results'] ?? []) as $i => $res) { if ($i >= 5) break; $results[] = ['title' => $res['title'] ?? '', 'url' => $res['url'] ?? '', 'content' => substr($res['content'] ?? '', 0, 200)]; } echo json_encode(['results' => $results, 'count' => count($results)]); break; // ═══ QDRANT: Vector memory for user profiles + RAG ═══ case 'vector': $action = $_POST['action'] ?? 'search'; $collection = $_POST['collection'] ?? 'wevia_memory'; if ($action === 'create_collection') { $r = api("http://localhost:6333/collections/$collection", 'PUT', [ 'vectors' => ['size' => 384, 'distance' => 'Cosine'] ]); echo json_encode($r); } elseif ($action === 'upsert') { $points = json_decode($_POST['points'] ?? '[]', true); $r = api("http://localhost:6333/collections/$collection/points", 'PUT', ['points' => $points]); echo json_encode($r); } elseif ($action === 'search') { $vector = json_decode($_POST['vector'] ?? '[]', true); $r = api("http://localhost:6333/collections/$collection/points/search", 'POST', [ 'vector' => $vector, 'limit' => intval($_POST['limit'] ?? 5), 'with_payload' => true ]); echo json_encode($r); } break; // ═══ OLLAMA: Local AI inference ═══ case 'ollama': $model = $_POST['model'] ?? 'qwen3:8b'; $prompt = $_POST['prompt'] ?? $q; if (!$prompt) die(json_encode(['error' => 'no prompt'])); $r = api('http://localhost:11434/api/generate', 'POST', [ 'model' => $model, 'prompt' => $prompt, 'stream' => false, 'options' => ['temperature' => 0.7, 'num_predict' => 500] ], 30); echo json_encode(['response' => $r['data']['response'] ?? '', 'model' => $model]); break; // ═══ N8N: Workflow automation trigger ═══ case 'workflow': $webhook = $_POST['webhook'] ?? ''; $payload = json_decode($_POST['payload'] ?? '{}', true); if (!$webhook) die(json_encode(['error' => 'no webhook URL'])); $r = api("http://localhost:5678/webhook/$webhook", 'POST', $payload); echo json_encode($r); break; // ═══ PLAUSIBLE: Analytics API ═══ case 'analytics': $site = $_POST['site'] ?? 'weval-consulting.com'; $period = $_POST['period'] ?? '7d'; $r = api("http://localhost:8787/api/v1/stats/aggregate?site_id=$site&period=$period&metrics=visitors,pageviews,bounce_rate", 'GET', null, 5); echo json_encode($r); break; // ═══ SCREENSHOT: Playwright visual capture ═══ case 'screenshot': $url = $_POST['url'] ?? ''; if (!$url) die(json_encode(['error' => 'no url'])); $slug = preg_replace('/[^a-z0-9]/', '-', strtolower(parse_url($url, PHP_URL_HOST) . parse_url($url, PHP_URL_PATH))); $file = "/var/www/html/wevia-ia/screenshots/cap-$slug.png"; $cmd = "python3 -c \" import asyncio from playwright.async_api import async_playwright async def s(): async with async_playwright() as p: b=await p.chromium.launch(headless=True,args=['--no-sandbox','--ignore-certificate-errors']) pg=await b.new_page() await pg.goto('$url',timeout=12000) await pg.wait_for_timeout(2000) await pg.screenshot(path='$file',full_page=True) await b.close() asyncio.run(s()) \" 2>&1"; $out = shell_exec($cmd); echo json_encode(['file' => str_replace('/var/www/html', '', $file), 'exists' => file_exists($file), 'size' => filesize($file) ?: 0]); break; // ═══ CROWDSEC: Threat intelligence ═══ case 'threats': $out = shell_exec('sudo cscli alerts list -l 10 -o json 2>/dev/null'); echo $out ?: json_encode(['alerts' => [], 'note' => 'no alerts']); break; // ═══ LOKI: Log query ═══ case 'logs': $query = $_POST['query'] ?? '{job="nginx"}'; $limit = intval($_POST['limit'] ?? 20); $r = api("http://localhost:3100/loki/api/v1/query_range?query=" . urlencode($query) . "&limit=$limit", 'GET', null, 5); echo json_encode($r); break; // === MATTERMOST: Team alerts === case 'alert': $channel = $_POST['channel'] ?? 'town-square'; $text = $_POST['text'] ?? ''; if (!$text) die(json_encode(['error'=>'no text'])); $r = api('http://localhost:8065/hooks/wevia-alert', 'POST', ['channel'=>$channel, 'text'=>$text]); echo json_encode($r); break; // === VAULTWARDEN: Secrets check === case 'vault': $r = api('http://localhost:8222/alive', 'GET', null, 3); echo json_encode(['alive'=>$r['code']===200]); break; // === OLLAMA S151: DR fallback inference === case 'ollama-local': $model = $_POST['model'] ?? 'qwen3:4b'; $prompt = $_POST['prompt'] ?? $q; if (!$prompt) die(json_encode(['error'=>'no prompt'])); $r = api('http://localhost:11434/api/generate', 'POST', [ 'model'=>$model, 'prompt'=>$prompt, 'stream'=>false, 'options'=>['temperature'=>0.7, 'num_predict'=>500] ], 30); echo json_encode(['response'=>$r['data']['response'] ?? '', 'model'=>$model, 'server'=>'S151-DR']); break; // === COGNITIVE: List active brain modules === case 'cognitive': $modules = []; foreach (glob('/var/www/weval/wevia-ia/cognitive-*.php') as $f) { $b = basename($f, '.php'); $lines = count(file($f)); $modules[] = ['name'=>$b, 'lines'=>$lines, 'path'=>$f]; } echo json_encode(['modules'=>$modules, 'count'=>count($modules)]); break; default: echo json_encode([ 'available' => ['health','search','vector','ollama','ollama-local','workflow','analytics','screenshot','threats','logs','alert','vault','cognitive'], 'usage' => 'POST /api/wevia-capabilities.php?cap=', 'auth' => 'Header X-WEVIA-KEY or POST key=...' ]); }