[ 'name' => 'Groq', 'icon' => '⚡', 'type' => 'cloud', 'free' => true, 'model' => 'llama-3.3-70b-versatile', 'endpoint' => 'https://api.groq.com/openai/v1/chat/completions', 'key_name' => 'groq_api_key' ], 'deepseek' => [ 'name' => 'DeepSeek', 'icon' => '🌊', 'type' => 'cloud', 'free' => true, 'model' => 'deepseek-chat', 'endpoint' => 'https://api.deepseek.com/chat/completions', 'key_name' => 'deepseek_api_key' ], 'mistral' => [ 'name' => 'Mistral', 'icon' => '🇫🇷', 'type' => 'cloud', 'free' => true, 'model' => 'mistral-large-latest', 'endpoint' => 'https://api.mistral.ai/v1/chat/completions', 'key_name' => 'mistral_api_key' ], 'together' => [ 'name' => 'Together AI', 'icon' => '🤝', 'type' => 'cloud', 'free' => true, 'model' => 'meta-llama/Llama-3.3-70B-Instruct-Turbo', 'endpoint' => 'https://api.together.xyz/v1/chat/completions', 'key_name' => 'together_api_key' ], 'openrouter' => [ 'name' => 'OpenRouter', 'icon' => '🔀', 'type' => 'cloud', 'free' => true, 'model' => 'meta-llama/llama-3.3-70b-instruct', 'endpoint' => 'https://openrouter.ai/api/v1/chat/completions', 'key_name' => 'openrouter_api_key' ], // === NOUVEAUX PROVIDERS GRATUITS === 'cerebras' => [ 'name' => 'Cerebras', 'icon' => '🧠', 'type' => 'cloud', 'free' => true, 'model' => 'llama-3.3-70b', 'endpoint' => 'https://api.cerebras.ai/v1/chat/completions', 'key_name' => 'cerebras_api_key' ], 'sambanova' => [ 'name' => 'SambaNova', 'icon' => '🚀', 'type' => 'cloud', 'free' => true, 'model' => 'Meta-Llama-3.1-70B-Instruct', 'endpoint' => 'https://api.sambanova.ai/v1/chat/completions', 'key_name' => 'sambanova_api_key' ], 'fireworks' => [ 'name' => 'Fireworks', 'icon' => '🎆', 'type' => 'cloud', 'free' => true, 'model' => 'accounts/fireworks/models/llama-v3p3-70b-instruct', 'endpoint' => 'https://api.fireworks.ai/inference/v1/chat/completions', 'key_name' => 'fireworks_api_key' ], 'hyperbolic' => [ 'name' => 'Hyperbolic', 'icon' => '🌀', 'type' => 'cloud', 'free' => true, 'model' => 'meta-llama/Llama-3.1-405B-Instruct', 'endpoint' => 'https://api.hyperbolic.xyz/v1/chat/completions', 'key_name' => 'hyperbolic_api_key' ], 'lepton' => [ 'name' => 'Lepton AI', 'icon' => '⚛️', 'type' => 'cloud', 'free' => true, 'model' => 'llama3-70b', 'endpoint' => 'https://llama3-70b.lepton.run/api/v1/chat/completions', 'key_name' => 'lepton_api_key' ], 'ai21' => [ 'name' => 'AI21', 'icon' => '🔮', 'type' => 'cloud', 'free' => true, 'model' => 'jamba-1.5-large', 'endpoint' => 'https://api.ai21.com/studio/v1/chat/completions', 'key_name' => 'ai21_api_key' ], 'cloudflare' => [ 'name' => 'Cloudflare AI', 'icon' => '☁️', 'type' => 'cloud', 'free' => true, 'model' => '@cf/meta/llama-3.1-70b-instruct', 'endpoint' => 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/meta/llama-3.1-70b-instruct', 'key_name' => 'cloudflare_api_key' ], 'novita' => [ 'name' => 'Novita AI', 'icon' => '🌟', 'type' => 'cloud', 'free' => true, 'model' => 'meta-llama/llama-3.1-70b-instruct', 'endpoint' => 'https://api.novita.ai/v3/openai/chat/completions', 'key_name' => 'novita_api_key' ], 'perplexity' => [ 'name' => 'Perplexity', 'icon' => '🔍', 'type' => 'cloud', 'free' => true, 'model' => 'llama-3.1-sonar-small-128k-online', 'endpoint' => 'https://api.perplexity.ai/chat/completions', 'key_name' => 'perplexity_api_key' ], 'chatgpt' => [ 'name' => 'ChatGPT', 'icon' => '🤖', 'type' => 'cloud', 'free' => false, 'model' => 'gpt-4o', 'endpoint' => 'https://api.openai.com/v1/chat/completions', 'key_name' => 'openai_api_key' ], 'copilot' => [ 'name' => 'GitHub Copilot', 'icon' => '🐙', 'type' => 'cloud', 'free' => false, 'model' => 'gpt-4', 'endpoint' => 'https://api.githubcopilot.com/chat/completions', 'key_name' => 'copilot_api_key' ], // Payants premium 'claude' => [ 'name' => 'Claude', 'icon' => '🧠', 'type' => 'cloud', 'free' => false, 'model' => 'claude-3-5-sonnet-20241022', 'endpoint' => 'https://api.anthropic.com/v1/messages', 'key_name' => 'anthropic_api_key' ], 'openai' => [ 'name' => 'OpenAI', 'icon' => '🤖', 'type' => 'cloud', 'free' => false, 'model' => 'gpt-4o', 'endpoint' => 'https://api.openai.com/v1/chat/completions', 'key_name' => 'openai_api_key' ], 'gemini' => [ 'name' => 'Gemini', 'icon' => '💎', 'type' => 'cloud', 'free' => false, 'model' => 'gemini-1.5-flash', 'endpoint' => 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent', 'key_name' => 'gemini_api_key' ], 'cohere' => [ 'name' => 'Cohere', 'icon' => '🔶', 'type' => 'cloud', 'free' => false, 'model' => 'command-r-plus', 'endpoint' => 'https://api.cohere.ai/v1/chat', 'key_name' => 'cohere_api_key' ], // Self-hosted 'ollama' => [ 'name' => 'Ollama Claude', 'icon' => '🦙', 'type' => 'local', 'free' => true, 'model' => 'mistral:7b-instruct', 'endpoint' => 'http://localhost:11434/api/chat', 'key_name' => 'ollama_url' ], 'ollama_mini' => [ 'name' => 'Ollama Mini', 'icon' => '⚡🦙', 'type' => 'local', 'free' => true, 'model' => 'phi:latest', 'endpoint' => 'http://localhost:11434/api/chat', 'key_name' => 'ollama_url' ], 'hamid_engine' => [ 'name' => 'WEVAL MIND Engine', 'icon' => '⭐', 'type' => 'local', 'free' => true, 'model' => 'llama3.1:8b', 'endpoint' => 'local', 'key_name' => '' ], 'vllm' => [ 'name' => 'vLLM', 'icon' => '🖥️', 'type' => 'local', 'free' => true, 'model' => 'default', 'endpoint' => 'http://localhost:8000/v1/chat/completions', 'key_name' => 'vllm_url' ] ]; // ═══════════════════════════════════════════════════════════════════════════ // 🧠 CERVEAU CLAUDE-LIKE (Style Opus) - À PRÉSERVER // ═══════════════════════════════════════════════════════════════════════════ private $CLAUDE_BRAIN = <<<'BRAIN' ## FORMAT OBLIGATOIRE Pour CHAQUE réponse, commence par: [Ton raisonnement: analyse, hypothèses, vérification, conclusion] Puis ta réponse finale. --- Tu es WEVAL MIND, une intelligence artificielle de niveau expert comparable à Claude Opus 4.5, opérant sur le serveur WEVAL (89.167.40.150). Nom: WEVAL MIND (Highly Advanced Multi-modal Intelligent Daemon) Niveau: Expert IA équivalent Claude Opus 4.5 Créateur: WEVAL Team Mission: Être l'assistant IA le plus utile, intelligent et proactif AVANT CHAQUE RÉPONSE, tu dois: 1. **ANALYSER** - Comprendre profondément la demande 2. **RÉFLÉCHIR** - Explorer plusieurs approches possibles 3. **STRUCTURER** - Organiser ta réponse de manière optimale 4. **EXÉCUTER** - Agir avec précision et expertise 5. **VÉRIFIER** - Contrôler la qualité du résultat 6. **ENRICHIR** - Proposer des améliorations proactives Pour les tâches complexes, utilise le raisonnement en chaîne: - Décompose en sous-problèmes - Résous étape par étape - Valide chaque étape avant de continuer - Synthétise une solution complète RÈGLES DE COMMUNICATION: 1. **DIRECT** - Va droit au but, évite le bavardage inutile 2. **INTELLIGENT** - Montre ta réflexion, pas juste le résultat 3. **PROACTIF** - Anticipe les besoins, propose des améliorations 4. **HUMBLE** - Admets tes limites quand nécessaire 5. **PRÉCIS** - Chaque mot compte, évite la redondance 6. **NATUREL** - Prose fluide, évite les listes excessives 7. **EXPERT** - Affirme avec confiance basée sur l'expertise INTERDICTIONS: - Jamais "N'hésitez pas", "Je suis là pour aider", "Bien sûr!" - Jamais de phrases creuses ou de remplissage - Jamais de listes à puces pour des explications simples ## EXÉCUTION CODE - **Bash/Shell**: Commandes système, scripts avancés, automation, pipelines - **Python**: Data science, ML, APIs, scraping, automation - **PHP**: Web backend, modification fichiers, intégration DB - **SQL**: Requêtes PostgreSQL complexes, CTEs, window functions, admin.* - **JavaScript**: Frontend, Node.js, APIs, automation browser ## SYSTÈME & INFRASTRUCTURE - **Services**: systemctl, journalctl, logs, monitoring - **Fichiers**: CRUD, permissions, recherche récursive, diff - **Réseau**: Ports, firewall, DNS, SSL/TLS, curl, wget - **Performance**: CPU, RAM, I/O, processus, optimisation ## GÉNÉRATION DE DOCUMENTS Quand on te demande de créer un document: 1. **RÉFLÉCHIS** d'abord au contenu optimal (structure, sections, détails) 2. **GÉNÈRE** un contenu RICHE et DÉTAILLÉ (minimum 2000 mots pour un rapport) 3. **STRUCTURE** avec des sections claires, tableaux, graphiques si pertinent 4. **INCLUS** des données concrètes, exemples, recommandations Types supportés: - **PDF**: Rapports détaillés, documentation technique, analyses - **DOCX**: Documents professionnels, contrats, procédures - **XLSX**: Tableaux avec formules, analyses de données, dashboards - **PPTX**: Présentations avec slides structurées - **HTML**: Pages web, emails formatés - **Mermaid**: Diagrammes, flowcharts, architectures ## EMAIL MARKETING (Expertise WEVAL) - **PowerMTA**: Configuration avancée, pools, virtual MTAs, logs - **DNS**: SPF, DKIM (rotation), DMARC, MX, PTR records - **Office 365**: Automation PowerShell, Graph API, connecteurs - **Délivrabilité**: IP warming, reputation, blacklist monitoring - **Tracking**: Opens, clicks, bounces, unsubscribes ## WEB & API - **Recherche**: Web search en temps réel - **APIs REST**: Intégration, authentification, parsing - **Scraping**: BeautifulSoup, Selenium si autorisé - **Webhooks**: Réception et envoi ## BASE DE DONNÉES - **PostgreSQL**: adx_system, adx_clients - **Schémas**: admin.*, public.* - **Tables clés**: commonia_config, commonia_knowledge, hamid_* - **Opérations**: CRUD, migrations, backups, optimisation Serveur: WEVAL 89.167.40.150 (Hetzner Cloud, Ubuntu 24.04, 16GB RAM) Applications: - WEVAL: port 5821 (/opt/wevads/public/) - FMGAPP: port 5822 (/opt/fmgapp/public/) - BCGAPP: port 5823 (/opt/bcgapp/public/) Database: PostgreSQL 16 (admin/admin123) - adx_system: Configuration, users, logs - adx_clients: Données clients Services: - Apache/Nginx: Web server - Ollama: localhost:11434 (mistral:7b, phi:latest) - PowerMTA: Email delivery - Redis: Cache (si actif) Chemins importants: - /opt/wevads/public/ - Web root - /opt/wevads/storage/ - Fichiers stockés - /opt/wevads/public/docs/ - Documents générés Quand l'utilisateur demande un document (PDF, rapport, analyse): 1. **RÉFLEXION PRÉALABLE** (affichée à l'utilisateur): - "🧠 Analyse de la demande..." - "📋 Structuration du contenu..." - "✍️ Rédaction détaillée..." - "📄 Génération du document..." 2. **CONTENU RICHE** - Minimum attendu: - Rapport/Analyse: 2000-5000 mots - Documentation: 1500-3000 mots - Présentation: 10-20 slides détaillées 3. **STRUCTURE PROFESSIONNELLE**: - Page de titre avec métadonnées - Table des matières si > 5 sections - Introduction contextualisée - Corps avec sous-sections détaillées - Tableaux et données chiffrées - Conclusion et recommandations - Annexes si pertinent 4. **STYLE PROFESSIONNEL**: - Langage formel mais accessible - Données concrètes et sourcées - Exemples pratiques - Visuels et diagrammes quand utile Tu as accès à une Knowledge Base WEVAL contenant: - Documentation technique - Configurations serveur - Procédures email marketing - Historique des conversations - FAQ et solutions connues TOUJOURS consulter la KB pour: - Questions sur WEVAL/FMGAPP/BCGAPP - Configurations spécifiques - Procédures établies - Contexte historique - **Markdown** pour la structure quand utile - **Code** dans blocs avec langage spécifié - **Tableaux** pour données comparatives - **Français** par défaut (anglais si demandé) - **Longueur** adaptée à la complexité (détaillé ≠ verbeux) Après chaque réponse, considère: - Y a-t-il des actions complémentaires utiles? - Des améliorations à suggérer? - Des risques à signaler? - Une suite logique à proposer? Propose proactivement sans être envahissant. ## SERVEUR TRACKING (OVH) - IP: 151.80.235.110 - Fonction: Tracking emails (opens, clicks, leads, unsubscribes) - SSL configuré - Domaines tracking multiples ## AMAZON S3 - Hosting images/assets pour emails - Améliore délivrabilité (évite IP directe) - CDN pour performance globale ## CLOUD PROVIDERS - Huawei Cloud: Instances email, VPC multi-régions - Google Cloud: Services complémentaires - OVH: Serveur tracking dédié ## WEVAL MIND - 11 PROVIDERS Cerebras (défaut), Groq, DeepSeek, Gemini, Claude, Hyperbolic, Mistral, Cohere, SambaNova, Ollama, WEVAL MIND Engine Knowledge Base: 26 articles + 141 QA AVANT CHAQUE RÉPONSE, vérifie: Ai-je vraiment compris la demande? Ma réponse est-elle assez détaillée? Ai-je inclus des exemples concrets? Un expert serait-il satisfait? Si NON → Améliore avant d envoyer! Tu es maintenant prêt. Réponds en expert avec intelligence et profondeur. BRAIN; // ═══════════════════════════════════════════════════════════════════════════ // CONSTRUCTEUR // ═══════════════════════════════════════════════════════════════════════════ public function __construct() { try { $this->pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123"); $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->loadConfig(); } catch (Exception $e) { $this->lastError = "DB Error: " . $e->getMessage(); } } private function loadConfig() { $stmt = $this->pdo->query("SELECT config_key, config_value FROM admin.hamid_config"); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $this->config[$row['config_key']] = $row['config_value']; } } public function getConfig($key, $default = '') { return $this->config[$key] ?? $default; } public function getLastError() { return $this->lastError; } public function getLastProvider() { return $this->lastProvider; } // ═══════════════════════════════════════════════════════════════════════════ // OBTENIR LES PROVIDERS DISPONIBLES (avec clés configurées) // ═══════════════════════════════════════════════════════════════════════════ public function getAvailableProviders() { $available = []; foreach (self::$PROVIDERS as $id => $provider) { $keyName = $provider['key_name']; $hasKey = !empty($this->config[$keyName]); $available[$id] = array_merge($provider, [ 'id' => $id, 'configured' => $hasKey, 'status' => $hasKey ? 'ready' : 'no_key' ]); } return $available; } // ═══════════════════════════════════════════════════════════════════════════ // APPEL API UNIFIÉ // ═══════════════════════════════════════════════════════════════════════════ public function callProvider($provider, $prompt, $toolsContext = '') { $p = self::$PROVIDERS[$provider] ?? null; if (!$p) return ['success' => false, 'error' => "Provider inconnu: $provider"]; $apiKey = $this->config[$p['key_name']] ?? ''; if (empty($apiKey) && $p['type'] !== 'local') { return ['success' => false, 'error' => "Clé API manquante pour {$p['name']}"]; } // Construire le prompt complet avec le cerveau Claude $fullPrompt = $this->CLAUDE_BRAIN . "\n\n"; if ($toolsContext) { $fullPrompt .= "\n$toolsContext\n\n\n"; } $fullPrompt .= "Question: $prompt\n\nRéponds en français, sois concis et direct."; $this->lastProvider = $provider; switch ($provider) { case 'claude': return $this->callClaude($apiKey, $fullPrompt); case 'gemini': return $this->callGemini($apiKey, $fullPrompt); case 'cohere': return $this->callCohere($apiKey, $fullPrompt); case 'ollama': // Ollama Claude: Brain complet (plus lent ~10-30s) return $this->callOllama('mistral:7b-instruct', $fullPrompt); case 'ollama_mini': // Ollama Mini: Rapide (~2-5s) $miniBrain = "Tu es WEVAL MIND, assistant IA WEVAL (89.167.40.150). STYLE: Direct, concis, proactif. Pas de blabla. CAPACITÉS: Bash, Python, PHP, SQL, fichiers, BDD, email, DNS, Linux. Réponds en français avec du code si nécessaire."; return $this->callOllama('phi:latest', $miniBrain . "\n\nQuestion: " . $prompt); case 'hamid_engine': // WEVAL MIND ENGINE - Claude Like, 100% local require_once __DIR__ . '/hamid-engine.php'; $engine = new HamidEngine($this->pdo); return $engine->call($prompt, $toolsContext); default: return $this->callOpenAICompatible($provider, $apiKey, $fullPrompt); } } // OpenAI-compatible (Groq, DeepSeek, Mistral, OpenAI, Together, OpenRouter, vLLM) private function callOpenAICompatible($provider, $apiKey, $prompt) { $p = self::$PROVIDERS[$provider]; $headers = ['Content-Type: application/json']; if ($provider === 'openrouter') { $headers[] = 'Authorization: Bearer ' . $apiKey; $headers[] = 'HTTP-Referer: https://wevads.com'; } else { $headers[] = 'Authorization: Bearer ' . $apiKey; } $data = [ 'model' => $p['model'], 'messages' => [ ['role' => 'user', 'content' => $prompt] ], 'max_tokens' => 8192, 'temperature' => 0.1 ]; return $this->curlRequest($p['endpoint'], $headers, $data, function($response) { return $response['choices'][0]['message']['content'] ?? null; }); } // Claude (Anthropic) private function callClaude($apiKey, $prompt) { $headers = [ 'Content-Type: application/json', 'x-api-key: ' . $apiKey, 'anthropic-version: 2023-06-01' ]; $data = [ 'model' => 'claude-3-5-sonnet-20241022', 'max_tokens' => 8192, 'system' => $this->CLAUDE_BRAIN, 'messages' => [['role' => 'user', 'content' => $prompt]] ]; return $this->curlRequest(self::$PROVIDERS['claude']['endpoint'], $headers, $data, function($response) { return $response['content'][0]['text'] ?? null; }); } // Gemini (Google) private function callGemini($apiKey, $prompt) { $url = self::$PROVIDERS['gemini']['endpoint'] . '?key=' . $apiKey; $headers = ['Content-Type: application/json']; $data = [ 'contents' => [['parts' => [['text' => $this->CLAUDE_BRAIN . "\n\n" . $prompt]]]], 'generationConfig' => ['maxOutputTokens' => 8192, 'temperature' => 0.1] ]; return $this->curlRequest($url, $headers, $data, function($response) { return $response['candidates'][0]['content']['parts'][0]['text'] ?? null; }); } // Cohere private function callCohere($apiKey, $prompt) { $headers = [ 'Content-Type: application/json', 'Authorization: Bearer ' . $apiKey ]; $data = [ 'model' => 'command-r-plus', 'message' => $prompt, 'preamble' => $this->CLAUDE_BRAIN ]; return $this->curlRequest(self::$PROVIDERS['cohere']['endpoint'], $headers, $data, function($response) { return $response['text'] ?? null; }); } // Ollama (local) private function callOllama($model, $prompt) { $endpoint = 'http://localhost:11434/api/chat'; $headers = ['Content-Type: application/json']; $data = [ 'model' => $model, 'messages' => [ ['role' => 'user', 'content' => $prompt] ], 'stream' => false, 'options' => ['num_predict' => 300] ]; return $this->curlRequest($endpoint, $headers, $data, function($response) { return $response['message']['content'] ?? null; }); } // Requête CURL générique private function curlRequest($url, $headers, $data, $extractFn) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_TIMEOUT => 180, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($data) ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { return ['success' => false, 'error' => "CURL: $error", 'http_code' => 0]; } if ($httpCode !== 200) { $errorMsg = json_decode($response, true)['error']['message'] ?? $response; return ['success' => false, 'error' => "HTTP $httpCode: " . substr($errorMsg, 0, 200), 'http_code' => $httpCode]; } $decoded = json_decode($response, true); $content = $extractFn($decoded); if ($content) { return ['success' => true, 'response' => $content, 'http_code' => $httpCode]; } return ['success' => false, 'error' => 'Réponse vide', 'http_code' => $httpCode]; } // ═══════════════════════════════════════════════════════════════════════════ // 🔄 AUTO-FALLBACK - Essayer les providers jusqu'à succès // ═══════════════════════════════════════════════════════════════════════════ public function callWithFallback($prompt, $toolsContext = '', $preferredProvider = null) { // Ordre de priorité: préféré → gratuits configurés → payants configurés $order = []; // Provider préféré en premier if ($preferredProvider && !empty($this->config[self::$PROVIDERS[$preferredProvider]['key_name'] ?? ''])) { $order[] = $preferredProvider; } // Gratuits configurés foreach (['cerebras', 'deepseek', 'mistral', 'together', 'openrouter'] as $p) { if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) { $order[] = $p; } } // Payants configurés foreach (['claude', 'openai', 'gemini', 'cohere'] as $p) { if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) { $order[] = $p; } } // Local foreach (['ollama', 'ollama_mini', 'vllm'] as $p) { if (!in_array($p, $order) && !empty($this->config[self::$PROVIDERS[$p]['key_name']])) { $order[] = $p; } } if (empty($order)) { return ['success' => false, 'error' => 'Aucun provider configuré', 'provider' => null]; } $errors = []; foreach ($order as $provider) { $result = $this->callProvider($provider, $prompt, $toolsContext); if ($result['success']) { $result['provider'] = $provider; $result['fallback_used'] = ($provider !== ($preferredProvider ?? $order[0])); return $result; } $errors[] = "{$provider}: {$result['error']}"; // Si rate limit (429), passer au suivant if (($result['http_code'] ?? 0) === 429) { continue; } } return [ 'success' => false, 'error' => "Tous les providers ont échoué:\n" . implode("\n", $errors), 'provider' => null ]; } } // ═══════════════════════════════════════════════════════════════════════════════ // API ENDPOINT // ═══════════════════════════════════════════════════════════════════════════════ if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') { header('Content-Type: application/json'); $brain = new HamidBrain(); // Liste des providers if (isset($_GET['providers'])) { header('Content-Type: application/json'); echo json_encode(['success' => true, 'providers' => HamidBrain::$PROVIDERS, 'count' => count(HamidBrain::$PROVIDERS)], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); exit; exit; } // Appel IA $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $message = $input['message'] ?? ''; $provider = $input['provider'] ?? null; $toolsContext = $input['tools_context'] ?? ''; // Traitement des fichiers uploadés $fileContext = ''; if (!empty($_FILES['file']['tmp_name'])) { $tmpFile = $_FILES['file']['tmp_name']; $fileName = $_FILES['file']['name'] ?? 'fichier'; $fileType = $_FILES['file']['type'] ?? ''; $uploadDir = '/opt/wevads/public/uploads/hamid/'; if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true); $savedFile = $uploadDir . time() . '_' . basename($fileName); move_uploaded_file($tmpFile, $savedFile); if (strpos($fileType, 'image') !== false) { $fileContext = "\n\n[IMAGE UPLOADEE: $fileName]\nChemin: $savedFile\nDecris ou traite cette image."; } elseif (strpos($fileType, 'text') !== false || strpos($fileType, 'csv') !== false || strpos($fileName, '.csv') !== false) { $txt = file_get_contents($savedFile); $fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($txt, 0, 5000); } elseif (strpos($fileName, '.pdf') !== false) { $pdfText = shell_exec("pdftotext '$savedFile' - 2>/dev/null | head -100"); $fileContext = "\n\n[PDF: $fileName]\nContenu:\n" . ($pdfText ?: "Extraction impossible"); } else { $txt = @file_get_contents($savedFile); $fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($txt ?: '', 0, 5000); } $message .= $fileContext; } // Traitement des fichiers uploadés $fileContext = ''; if (!empty($_FILES['file']['tmp_name'])) { $tmpFile = $_FILES['file']['tmp_name']; $fileName = $_FILES['file']['name'] ?? 'fichier'; $fileType = $_FILES['file']['type'] ?? ''; // Sauvegarder le fichier $uploadDir = '/opt/wevads/public/uploads/hamid/'; if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true); $savedFile = $uploadDir . time() . '_' . basename($fileName); move_uploaded_file($tmpFile, $savedFile); // Analyser selon le type if (strpos($fileType, 'image') !== false) { $fileContext = "\n\n[FICHIER IMAGE: $fileName - Chemin: $savedFile]\n"; $fileContext .= "L'utilisateur a uploadé une image. Décris ce que tu peux faire avec."; } elseif (strpos($fileType, 'text') !== false || strpos($fileType, 'csv') !== false) { $content = file_get_contents($savedFile); $fileContext = "\n\n[FICHIER TEXTE: $fileName]\nContenu:\n" . substr($content, 0, 5000); } elseif (strpos($fileName, '.pdf') !== false) { $fileContext = "\n\n[FICHIER PDF: $fileName - Chemin: $savedFile]\n"; // Tenter extraction texte $pdfText = shell_exec("pdftotext '$savedFile' - 2>/dev/null | head -100"); if ($pdfText) $fileContext .= "Contenu extrait:\n" . substr($pdfText, 0, 3000); } elseif (strpos($fileName, '.doc') !== false) { $fileContext = "\n\n[FICHIER WORD: $fileName - Chemin: $savedFile]\n"; } else { $content = @file_get_contents($savedFile); if ($content) { $fileContext = "\n\n[FICHIER: $fileName]\nContenu:\n" . substr($content, 0, 5000); } } $message .= $fileContext; } // API ENDPOINTS CAPACITES AVANCEES $action = $input["action"] ?? $_GET["action"] ?? ""; if ($action === "analyze") { header("Content-Type: application/json"); $file = $input["file"] ?? ""; echo json_encode($file && file_exists($file) ? HamidCapabilities::analyzeDocument($file) : ["success" => false, "error" => "Fichier non trouve"]); exit; } if ($action === "artifact") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::createArtifact($input["type"] ?? "html", $input["content"] ?? "", $input["title"] ?? "artifact")); exit; } if ($action === "mermaid") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::generateMermaid($input["diagram_type"] ?? "flowchart", $input["data"] ?? [])); exit; } if ($action === "execute") { header("Content-Type: application/json"); echo json_encode(HamidCapabilities::executeCode($input["language"] ?? "bash", $input["code"] ?? "")); exit; } if ($action === "list_artifacts") { header("Content-Type: application/json"); echo json_encode(["success" => true, "artifacts" => HamidCapabilities::listArtifacts()]); exit; } if ($action === "generate_doc") { header("Content-Type: application/json"); $t=$input["type"]??"txt"; $ti=$input["title"]??"Doc"; $c=$input["content"]??""; switch($t){ case "txt": echo json_encode(HamidDocuments::generateTxt($ti,$c)); break; case "md": echo json_encode(HamidDocuments::generateMarkdown($ti,$c)); break; case "html": echo json_encode(HamidDocuments::generateHtml($ti,$c)); break; case "pdf": echo json_encode(HamidDocuments::generatePdf($ti,$c)); break; default: echo json_encode(["success"=>false,"error"=>"Type non supporté"]); } exit; } if ($action === "list_docs") { header("Content-Type: application/json"); echo json_encode(HamidDocuments::listDocuments()); exit; } $autoFallback = $input['auto_fallback'] ?? true; if (empty($message)) { echo json_encode(['success' => false, 'error' => 'Message vide']); if ($action === "generate_meme") { header("Content-Type: application/json"); echo json_encode(HamidMemes::generateMeme($input["template"]??"blank", $input["texts"]??[], $input["options"]??[])); exit; } exit; } $start = microtime(true); if ($autoFallback) { $result = $brain->callWithFallback($message, $toolsContext, $provider); } else { $result = $brain->callProvider($provider ?? 'groq', $message, $toolsContext); $result['provider'] = $provider ?? 'groq'; } $result['duration_ms'] = round((microtime(true) - $start) * 1000); // Sauvegarder la conversation dans la BDD try { $sessionId = $input['session_id'] ?? session_id() ?: uniqid('sess_'); $pdo = new PDO('pgsql:host=localhost;dbname=adx_system', 'admin', 'admin123'); // Sauvegarder dans hamid_conversations $stmt = $pdo->prepare("INSERT INTO admin.hamid_conversations (session_id, role, content, provider) VALUES (?, 'user', ?, ?)"); $stmt->execute([$sessionId, $message, $result['provider'] ?? $provider]); $stmt = $pdo->prepare("INSERT INTO admin.hamid_conversations (session_id, role, content, provider) VALUES (?, 'assistant', ?, ?)"); $stmt->execute([$sessionId, $result['response'] ?? '', $result['provider'] ?? $provider]); // Aussi dans chatbot_conversations pour l'interface learning $stmt = $pdo->prepare("INSERT INTO admin.chatbot_conversations (session_id, role, message) VALUES (?, 'user', ?)"); $stmt->execute([$sessionId, $message]); $stmt = $pdo->prepare("INSERT INTO admin.chatbot_conversations (session_id, role, message) VALUES (?, 'assistant', ?)"); $stmt->execute([$sessionId, $result['response'] ?? '']); $result['session_id'] = $sessionId; } catch (Exception $e) { // Silently fail - ne pas bloquer la réponse } echo json_encode($result); } // ═══════════════════════════════════════════════════════════════════════════════ // CAPACITÉS AVANCÉES - DOCUMENTS & SCHÉMAS // ═══════════════════════════════════════════════════════════════════════════════ class HamidCapabilities { // Analyse de document (PDF, DOCX, TXT, images) public static function analyzeDocument($filePath, $mimeType = null) { if (!file_exists($filePath)) { return ['success' => false, 'error' => 'Fichier non trouvé']; } $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); $content = ''; switch ($ext) { case 'txt': case 'md': case 'php': case 'py': case 'js': case 'json': case 'sql': case 'sh': case 'css': case 'html': $content = file_get_contents($filePath); break; case 'pdf': $content = self::extractPdfText($filePath); break; case 'docx': $content = self::extractDocxText($filePath); break; case 'xlsx': case 'csv': $content = self::extractSpreadsheetText($filePath, $ext); break; case 'png': case 'jpg': case 'jpeg': case 'gif': case 'webp': return self::analyzeImage($filePath); default: return ['success' => false, 'error' => "Type de fichier non supporté: $ext"]; } return [ 'success' => true, 'type' => $ext, 'content' => $content, 'size' => filesize($filePath), 'lines' => substr_count($content, "\n") + 1 ]; } // Extraction texte PDF private static function extractPdfText($filePath) { // Utiliser pdftotext si disponible $output = shell_exec("pdftotext -layout '$filePath' - 2>/dev/null"); if ($output) return trim($output); // Fallback: lecture basique $content = file_get_contents($filePath); preg_match_all('/\((.*?)\)/', $content, $matches); return implode(' ', $matches[1] ?? []); } // Extraction texte DOCX private static function extractDocxText($filePath) { $zip = new ZipArchive(); if ($zip->open($filePath) === true) { $content = $zip->getFromName('word/document.xml'); $zip->close(); // Extraire le texte des balises XML $content = strip_tags(str_replace('<', ' <', $content)); return trim(preg_replace('/\s+/', ' ', $content)); } return ''; } // Extraction spreadsheet private static function extractSpreadsheetText($filePath, $ext) { if ($ext === 'csv') { return file_get_contents($filePath); } // XLSX basique $zip = new ZipArchive(); if ($zip->open($filePath) === true) { $content = $zip->getFromName('xl/sharedStrings.xml'); $zip->close(); preg_match_all('/]*>([^<]+)<\/t>/', $content, $matches); return implode("\n", $matches[1] ?? []); } return ''; } // Analyse image (OCR ou description) private static function analyzeImage($filePath) { $base64 = base64_encode(file_get_contents($filePath)); $mime = mime_content_type($filePath); return [ 'success' => true, 'type' => 'image', 'mime' => $mime, 'base64' => $base64, 'size' => filesize($filePath), 'dimensions' => getimagesize($filePath) ]; } // ═══════════════════════════════════════════════════════════════════════════ // GÉNÉRATION DE SCHÉMAS // ═══════════════════════════════════════════════════════════════════════════ // Générer un schéma Mermaid public static function generateMermaid($type, $data) { $mermaid = ''; switch ($type) { case 'flowchart': $mermaid = self::buildFlowchart($data); break; case 'sequence': $mermaid = self::buildSequence($data); break; case 'er': $mermaid = self::buildER($data); break; case 'class': $mermaid = self::buildClassDiagram($data); break; case 'gantt': $mermaid = self::buildGantt($data); break; default: $mermaid = $data; // Raw mermaid code } return [ 'success' => true, 'type' => 'mermaid', 'diagram_type' => $type, 'code' => $mermaid, 'html' => self::wrapMermaidHtml($mermaid) ]; } private static function buildFlowchart($data) { $lines = ["flowchart TD"]; if (is_array($data)) { foreach ($data as $node) { $lines[] = " " . $node; } } else { $lines[] = $data; } return implode("\n", $lines); } private static function buildSequence($data) { $lines = ["sequenceDiagram"]; if (is_array($data)) { foreach ($data as $step) { $lines[] = " " . $step; } } return implode("\n", $lines); } private static function buildER($data) { $lines = ["erDiagram"]; if (is_array($data)) { foreach ($data as $relation) { $lines[] = " " . $relation; } } return implode("\n", $lines); } private static function buildClassDiagram($data) { $lines = ["classDiagram"]; if (is_array($data)) { foreach ($data as $class) { $lines[] = " " . $class; } } return implode("\n", $lines); } private static function buildGantt($data) { $lines = ["gantt", " dateFormat YYYY-MM-DD"]; if (is_array($data)) { foreach ($data as $task) { $lines[] = " " . $task; } } return implode("\n", $lines); } private static function wrapMermaidHtml($code) { return '
' . htmlspecialchars($code) . '
'; } // ═══════════════════════════════════════════════════════════════════════════ // GÉNÉRATION D'ARTIFACTS // ═══════════════════════════════════════════════════════════════════════════ public static function createArtifact($type, $content, $title = 'artifact') { $dir = '/opt/wevads/public/artifacts/'; if (!is_dir($dir)) mkdir($dir, 0755, true); $id = uniqid('art_'); $ext = self::getArtifactExtension($type); $filename = "{$id}.{$ext}"; $filepath = $dir . $filename; // Wrapper selon le type switch ($type) { case 'html': $wrapped = self::wrapHtmlArtifact($content, $title); break; case 'react': $wrapped = self::wrapReactArtifact($content, $title); break; case 'svg': $wrapped = $content; break; case 'mermaid': $wrapped = self::wrapMermaidHtml($content); $ext = 'html'; $filename = "{$id}.html"; $filepath = $dir . $filename; break; default: $wrapped = $content; } file_put_contents($filepath, $wrapped); return [ 'success' => true, 'type' => $type, 'id' => $id, 'filename' => $filename, 'path' => $filepath, 'url' => "/artifacts/{$filename}", 'content' => $wrapped ]; } private static function getArtifactExtension($type) { $map = [ 'html' => 'html', 'react' => 'html', 'svg' => 'svg', 'mermaid' => 'html', 'javascript' => 'js', 'python' => 'py', 'php' => 'php', 'css' => 'css', 'json' => 'json', 'markdown' => 'md' ]; return $map[$type] ?? 'txt'; } private static function wrapHtmlArtifact($content, $title) { // Si déjà un document complet if (stripos($content, ' ' . htmlspecialchars($title) . ' ' . $content . ' '; } private static function wrapReactArtifact($content, $title) { return ' ' . htmlspecialchars($title) . '
'; } // ═══════════════════════════════════════════════════════════════════════════ // EXÉCUTION DE CODE // ═══════════════════════════════════════════════════════════════════════════ public static function executeCode($language, $code, $timeout = 30) { $result = ['success' => false, 'output' => '', 'error' => '']; $tmpDir = '/tmp/hamid_exec/'; if (!is_dir($tmpDir)) mkdir($tmpDir, 0755, true); $id = uniqid(); switch (strtolower($language)) { case 'bash': case 'sh': $file = "{$tmpDir}{$id}.sh"; file_put_contents($file, $code); $result['output'] = shell_exec("timeout {$timeout} bash '$file' 2>&1"); unlink($file); $result['success'] = true; break; case 'python': case 'py': $file = "{$tmpDir}{$id}.py"; file_put_contents($file, $code); $result['output'] = shell_exec("timeout {$timeout} python3 '$file' 2>&1"); unlink($file); $result['success'] = true; break; case 'php': $file = "{$tmpDir}{$id}.php"; file_put_contents($file, "&1"); unlink($file); $result['success'] = true; break; case 'sql': $result['output'] = shell_exec("timeout {$timeout} PGPASSWORD=admin123 psql -U admin -d adx_system -c " . escapeshellarg($code) . " 2>&1"); $result['success'] = true; break; case 'javascript': case 'js': $file = "{$tmpDir}{$id}.js"; file_put_contents($file, $code); $result['output'] = shell_exec("timeout {$timeout} node '$file' 2>&1"); unlink($file); $result['success'] = true; break; default: $result['error'] = "Langage non supporté: $language"; } return $result; } // ═══════════════════════════════════════════════════════════════════════════ // UTILITAIRES // ═══════════════════════════════════════════════════════════════════════════ public static function listArtifacts() { $dir = '/opt/wevads/public/artifacts/'; if (!is_dir($dir)) return []; $files = []; foreach (glob($dir . '*') as $file) { $files[] = [ 'name' => basename($file), 'path' => $file, 'url' => '/artifacts/' . basename($file), 'size' => filesize($file), 'modified' => filemtime($file) ]; } return $files; } public static function deleteArtifact($id) { $dir = '/opt/wevads/public/artifacts/'; $files = glob($dir . $id . '*'); foreach ($files as $file) { unlink($file); } return ['success' => true]; } } // ═══════════════════════════════════════════════════════════════════════════════ // API ENDPOINTS POUR CAPACITÉS AVANCÉES // ═══════════════════════════════════════════════════════════════════════════════ if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $action = $input['action'] ?? $_GET['action'] ?? ''; // Analyze document if ($action === 'analyze') { header('Content-Type: application/json'); $file = $input['file'] ?? ''; if ($file && file_exists($file)) { echo json_encode(HamidCapabilities::analyzeDocument($file)); } else { echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']); } exit; } // Create artifact if ($action === 'artifact') { header('Content-Type: application/json'); $type = $input['type'] ?? 'html'; $content = $input['content'] ?? ''; $title = $input['title'] ?? 'artifact'; echo json_encode(HamidCapabilities::createArtifact($type, $content, $title)); exit; } // Generate mermaid if ($action === 'mermaid') { header('Content-Type: application/json'); $type = $input['diagram_type'] ?? 'flowchart'; $data = $input['data'] ?? []; echo json_encode(HamidCapabilities::generateMermaid($type, $data)); exit; } // Execute code if ($action === 'execute') { header('Content-Type: application/json'); $lang = $input['language'] ?? 'bash'; $code = $input['code'] ?? ''; echo json_encode(HamidCapabilities::executeCode($lang, $code)); exit; } // List artifacts if ($action === 'list_artifacts') { header('Content-Type: application/json'); echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]); exit; } } // ═══════════════════════════════════════════════════════════════════════════════ // API ENDPOINTS POUR CAPACITÉS AVANCÉES // ═══════════════════════════════════════════════════════════════════════════════ if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $action = $input['action'] ?? $_GET['action'] ?? ''; // Analyze document if ($action === 'analyze') { header('Content-Type: application/json'); $file = $input['file'] ?? ''; if ($file && file_exists($file)) { echo json_encode(HamidCapabilities::analyzeDocument($file)); } else { echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']); } exit; } // Create artifact if ($action === 'artifact') { header('Content-Type: application/json'); $type = $input['type'] ?? 'html'; $content = $input['content'] ?? ''; $title = $input['title'] ?? 'artifact'; echo json_encode(HamidCapabilities::createArtifact($type, $content, $title)); exit; } // Generate mermaid if ($action === 'mermaid') { header('Content-Type: application/json'); $type = $input['diagram_type'] ?? 'flowchart'; $data = $input['data'] ?? []; echo json_encode(HamidCapabilities::generateMermaid($type, $data)); exit; } // Execute code if ($action === 'execute') { header('Content-Type: application/json'); $lang = $input['language'] ?? 'bash'; $code = $input['code'] ?? ''; echo json_encode(HamidCapabilities::executeCode($lang, $code)); exit; } // List artifacts if ($action === 'list_artifacts') { header('Content-Type: application/json'); echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]); exit; } } // ═══════════════════════════════════════════════════════════════════════════════ // API ENDPOINTS POUR CAPACITÉS AVANCÉES // ═══════════════════════════════════════════════════════════════════════════════ if (basename($_SERVER['SCRIPT_NAME']) === 'hamid-brain.php') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $action = $input['action'] ?? $_GET['action'] ?? ''; // Analyze document if ($action === 'analyze') { header('Content-Type: application/json'); $file = $input['file'] ?? ''; if ($file && file_exists($file)) { echo json_encode(HamidCapabilities::analyzeDocument($file)); } else { echo json_encode(['success' => false, 'error' => 'Fichier non trouvé']); } exit; } // Create artifact if ($action === 'artifact') { header('Content-Type: application/json'); $type = $input['type'] ?? 'html'; $content = $input['content'] ?? ''; $title = $input['title'] ?? 'artifact'; echo json_encode(HamidCapabilities::createArtifact($type, $content, $title)); exit; } // Generate mermaid if ($action === 'mermaid') { header('Content-Type: application/json'); $type = $input['diagram_type'] ?? 'flowchart'; $data = $input['data'] ?? []; echo json_encode(HamidCapabilities::generateMermaid($type, $data)); exit; } // Execute code if ($action === 'execute') { header('Content-Type: application/json'); $lang = $input['language'] ?? 'bash'; $code = $input['code'] ?? ''; echo json_encode(HamidCapabilities::executeCode($lang, $code)); exit; } // List artifacts if ($action === 'list_artifacts') { header('Content-Type: application/json'); echo json_encode(['success' => true, 'artifacts' => HamidCapabilities::listArtifacts()]); exit; } } // ═══════════════════════════════════════════════════════════════════════════════ // GÉNÉRATION DE DOCUMENTS TÉLÉCHARGEABLES // ═══════════════════════════════════════════════════════════════════════════════ class HamidDocuments { private static $docsDir = '/opt/wevads/public/docs/'; public static function generateTxt($title, $content) { $id = uniqid('doc_'); $filename = $id . '.txt'; $filepath = self::$docsDir . $filename; file_put_contents($filepath, "=== $title ===\n\n$content"); return self::docResponse($id, $filename, $filepath, 'txt', $title); } public static function generateMarkdown($title, $content) { $id = uniqid('doc_'); $filename = $id . '.md'; $filepath = self::$docsDir . $filename; file_put_contents($filepath, "# $title\n\n$content"); return self::docResponse($id, $filename, $filepath, 'md', $title); } public static function generateHtml($title, $content) { $id = uniqid('doc_'); $filename = $id . '.html'; $filepath = self::$docsDir . $filename; $html = "$title

$title

$content