PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5 ]); } return $pdo; } function respond($data, $code = 200) { http_response_code($code); echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); exit; } $action = $_GET['action'] ?? $_POST['action'] ?? 'stats'; try { $db = getDb(); switch ($action) { case 'stats': $r = $db->query("SELECT count(*) as total, max(updated_at) as last_update, count(DISTINCT section) as sections, count(DISTINCT category) as categories FROM knowledge_base"); $stats = $r->fetch(PDO::FETCH_ASSOC); $bc = $db->query("SELECT count(*) as total FROM brain_config WHERE is_active=true"); $brainConfigs = $bc->fetch(PDO::FETCH_ASSOC); respond([ 'status' => 'ok', 'knowledge_base' => $stats, 'brain_configs' => $brainConfigs, 'server' => 'S88 gateway → S89 PG' ]); break; case 'search': $q = $_GET['q'] ?? $_POST['q'] ?? ''; if (!$q) respond(['error' => 'Missing q parameter'], 400); $limit = intval($_GET['limit'] ?? 10); $stmt = $db->prepare("SELECT id, section, title, content, category, similarity(title || ' ' || content, :q) as relevance FROM knowledge_base WHERE title || ' ' || content ILIKE :pattern ORDER BY relevance DESC LIMIT :lim"); $stmt->execute(['q' => $q, 'pattern' => "%$q%", 'lim' => $limit]); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); respond(['status' => 'ok', 'query' => $q, 'count' => count($results), 'results' => $results]); break; case 'sections': $r = $db->query("SELECT section, count(*) as entries FROM knowledge_base GROUP BY section ORDER BY entries DESC"); respond(['status' => 'ok', 'sections' => $r->fetchAll(PDO::FETCH_ASSOC)]); break; case 'ingest': $title = $_POST['title'] ?? ''; $content = $_POST['content'] ?? ''; $section = $_POST['section'] ?? 'general'; $category = $_POST['category'] ?? 'manual'; if (!$title || !$content) respond(['error' => 'Missing title or content'], 400); $stmt = $db->prepare("INSERT INTO knowledge_base (section, title, content, category, created_at, updated_at) VALUES (:section, :title, :content, :category, NOW(), NOW()) RETURNING id"); $stmt->execute(['section' => $section, 'title' => $title, 'content' => $content, 'category' => $category]); $id = $stmt->fetchColumn(); respond(['status' => 'ok', 'id' => $id, 'message' => "Entry ingested: $title"]); break; default: respond(['error' => 'Unknown action', 'available' => ['stats','search','sections','ingest']], 400); } } catch (Exception $e) { error_log("WEVIA_KB_GW: " . $e->getMessage()); respond(['error' => 'DB connection failed', 'detail' => $e->getMessage()], 500); }