openRouterService = new OpenRouterService(); } /** * AI Assistant endpoint for generating installation scripts */ public function assist(): void { requireAdmin(); try { $input = json_decode(file_get_contents('php://input'), true); if (!$input) { throw new Exception('Invalid JSON input'); } $prompt = trim($input['prompt'] ?? ''); $model = trim($input['model'] ?? 'openai/gpt-3.5-turbo'); $protocolType = trim($input['protocol_type'] ?? ''); $protocolId = isset($input['protocol_id']) ? (int) $input['protocol_id'] : null; $target = trim($input['target'] ?? 'install'); // install, uninstall, template if (empty($prompt)) { throw new Exception('Prompt is required'); } // Generate enhanced prompt based on protocol type and target $enhancedPrompt = $this->enhancePrompt($prompt, $protocolType, $target); // Call OpenRouter API $response = $this->openRouterService->generateScript($enhancedPrompt, $model); // Save AI generation to database $generationId = $this->saveAIGeneration([ 'protocol_id' => $protocolId, 'model_used' => $model, 'prompt' => "[$target] " . $prompt, 'generated_script' => $response['script'] ?? '', 'suggestions' => json_encode($response['suggestions'] ?? []), 'ubuntu_compatible' => $response['ubuntu_compatible'] ?? null, 'created_at' => date('Y-m-d H:i:s') ]); header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'data' => [ 'script' => $response['script'] ?? '', 'suggestions' => $response['suggestions'] ?? [], 'ubuntu_compatible' => $response['ubuntu_compatible'] ?? false, 'estimated_time' => $response['estimated_time'] ?? '5 minutes', 'model_used' => $model, 'generation_id' => $generationId, 'target' => $target ] ]); } catch (Exception $e) { error_log("Error in AIController::assist: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } } /** * Get available AI models */ public function getModels(): void { requireAdmin(); try { $models = $this->openRouterService->getAvailableModels(); header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'data' => $models ]); } catch (Exception $e) { error_log("Error in AIController::getModels: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } } public function testModel(): void { requireAdmin(); header('Content-Type: application/json'); try { $input = json_decode(file_get_contents('php://input'), true); if (!$input) { throw new Exception('Invalid JSON input'); } $model = trim($input['model'] ?? ''); if ($model === '') { throw new Exception('Model id is required'); } $result = $this->openRouterService->testModelAvailability($model); echo json_encode([ 'success' => $result['success'] ?? false, 'message' => $result['message'] ?? null, 'http_code' => $result['http_code'] ?? null ]); } catch (Exception $e) { http_response_code(400); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } } /** * Get AI generation history for a protocol */ public function getGenerationHistory(int $protocolId): void { requireAdmin(); try { $generations = $this->getAIGenerationsByProtocol($protocolId); header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'data' => $generations ]); } catch (Exception $e) { error_log("Error in AIController::getGenerationHistory: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } } /** * Apply AI-generated script to protocol */ public function applyGeneration(int $generationId): void { requireAdmin(); try { $generation = $this->getAIGeneration($generationId); if (!$generation) { throw new Exception('AI generation not found'); } if (!$generation['protocol_id']) { throw new Exception('This generation is not associated with any protocol'); } // Determine target from prompt $target = 'install'; if (preg_match('/^\[(uninstall|template)\]/', $generation['prompt'], $matches)) { $target = $matches[1]; } // Update protocol with generated script $pdo = DB::conn(); if ($target === 'uninstall') { $stmt = $pdo->prepare(' UPDATE protocols SET uninstall_script = ?, updated_at = ? WHERE id = ? '); $stmt->execute([ $generation['generated_script'], date('Y-m-d H:i:s'), $generation['protocol_id'] ]); } elseif ($target === 'template') { $stmt = $pdo->prepare(' UPDATE protocols SET output_template = ?, updated_at = ? WHERE id = ? '); $stmt->execute([ $generation['generated_script'], date('Y-m-d H:i:s'), $generation['protocol_id'] ]); } else { $stmt = $pdo->prepare(' UPDATE protocols SET install_script = ?, ubuntu_compatible = ?, updated_at = ? WHERE id = ? '); $stmt->execute([ $generation['generated_script'], $generation['ubuntu_compatible'], date('Y-m-d H:i:s'), $generation['protocol_id'] ]); } header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'message' => 'AI-generated script applied to protocol successfully' ]); } catch (Exception $e) { error_log("Error in AIController::applyGeneration: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } } /** * Preview AI-generated script with syntax highlighting */ public function previewGeneration(int $generationId): void { requireAdmin(); try { $generation = $this->getAIGeneration($generationId); if (!$generation) { throw new Exception('AI generation not found'); } View::render('ai/preview_generation.twig', [ 'generation' => $generation, 'script' => $generation['generated_script'], 'suggestions' => json_decode($generation['suggestions'], true) ?? [] ]); } catch (Exception $e) { $_SESSION['protocol_error'] = $e->getMessage(); redirect('/settings/protocols'); } } /** * Enhance user prompt with context and requirements */ private function enhancePrompt(string $prompt, string $protocolType, string $target = 'install'): string { $context = ""; if ($target === 'uninstall') { $context = "Create a bash uninstallation script for a VPN protocol. "; } elseif ($target === 'template') { $context = "Create a WireGuard-compatible client config template. "; } else { $context = "Create a bash installation script for a VPN protocol. "; } if ($protocolType) { $context .= "This is for a $protocolType protocol. "; } $context .= "Requirements:\n"; if ($target === 'template') { $context .= "- Use Mustache-style placeholders like {{private_key}}, {{client_ip}}, {{server_host}}, {{server_port}}\n"; $context .= "- The template should be valid configuration format (e.g. .conf for WireGuard)\n"; } elseif ($target === 'uninstall') { $context .= "- The script should be compatible with Ubuntu 22.04 and 24.04\n"; $context .= "- Remove all docker containers, images, and networks created by the installation\n"; $context .= "- Remove configuration files and directories\n"; $context .= "- Clean up firewall rules if necessary\n"; } else { $context .= "- The script should be compatible with Ubuntu 22.04 and 24.04\n"; $context .= "- Use Docker containers where possible for isolation\n"; $context .= "- Generate necessary keys and certificates automatically\n"; $context .= "- Configure appropriate firewall rules\n"; $context .= "- Provide clear output about installation progress\n"; $context .= "- Handle errors gracefully\n"; $context .= "- Include configuration validation\n"; } $context .= "\nUser requirements: $prompt\n"; $context .= "\nReturn the response in this JSON format:\n"; $context .= "{\n"; if ($target === 'template') { $context .= ' "script": "[Interface]\\nPrivateKey = {{private_key}}...",' . "\n"; } else { $context .= ' "script": "#!/bin/bash\\n# Complete script",' . "\n"; } $context .= ' "suggestions": ["suggestion 1", "suggestion 2"],' . "\n"; $context .= ' "ubuntu_compatible": true,' . "\n"; $context .= ' "estimated_time": "5 minutes"' . "\n"; $context .= "}\n"; return $context; } /** * Database methods */ private function saveAIGeneration(array $data): int { $pdo = DB::conn(); $stmt = $pdo->prepare(' INSERT INTO ai_generations (protocol_id, model_used, prompt, generated_script, suggestions, ubuntu_compatible, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) '); $stmt->execute([ $data['protocol_id'], $data['model_used'], $data['prompt'], $data['generated_script'], $data['suggestions'], $data['ubuntu_compatible'], $data['created_at'] ]); return (int) $pdo->lastInsertId(); } private function getAIGeneration(int $id): ?array { $pdo = DB::conn(); $stmt = $pdo->prepare(' SELECT ag.*, p.name as protocol_name, p.slug as protocol_slug FROM ai_generations ag LEFT JOIN protocols p ON ag.protocol_id = p.id WHERE ag.id = ? '); $stmt->execute([$id]); $generation = $stmt->fetch(PDO::FETCH_ASSOC); return $generation ?: null; } private function getAIGenerationsByProtocol(int $protocolId): array { $pdo = DB::conn(); $stmt = $pdo->prepare(' SELECT ag.*, p.name as protocol_name FROM ai_generations ag LEFT JOIN protocols p ON ag.protocol_id = p.id WHERE ag.protocol_id = ? ORDER BY ag.created_at DESC LIMIT 50 '); $stmt->execute([$protocolId]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } }